A tool to generate code that support dynamic curd operations based on ent
Before you read this introducation, i suggest you to be familary with ent firstly
mkdir curdboy-playground
cd curdboy-playground
go mod init curdboy-playground
go install entgo.io/ent/cmd/ent@latest
go run entgo.io/ent/cmd/ent init User
edit the User schema at ent/schema/user.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/field"
)
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("firstname"),
field.String("lastname"),
field.Int("age"),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return nil
}
Run go generate
to generate ent code
go generate ./ent
go install github.com/pigfall/curdboy@latest
Run command to generate dynamic curd code
cbc --schemaDirPath ./ent/schema --entTargetDirPath ./ent --targetDirPath ./curd
Take a loot at the ./curd/curd_user.go
func UserQuery (ctx context.Context,req *QueryRequest,entCli *ent.Client)([]*ent.User,error ){
var pred predicate.User
if len(req.Filter) > 0{
filterExpr,err := filter.ParseFilter(req.Filter)
if err != nil{
return nil,err
}
pred,err = ToUserPredicate(filterExpr)
if err != nil{
return nil,err
}
}
query := entCli.User.Query().Limit(req.PageSize).Offset(req.PageIndex * req.PageSize)
if pred != nil{
query = query.Where(pred)
}
return query.All(ctx)
}
The QueryRequest
struct will be provided by the client. It will contains query conditions. The UserQuery
will parse the QueryRequest
then config the ent query object to query the db;
filter = "(name eq 'foo' and age ge 10) or (dept.age eq 50)"
fields = "name,age,lastname,parent.name,parent.age"
This will tell the ent we want to query:
predicateUser.Or(
predicateUser.And(
predicateUser.NameEQ("foo"),
predicateUser.AgeGE(10),
),
predicateUser.HasParentWith(
predicateUser.AgeEQ(50),
),
)
the fields we want to select are:
ent.Client.User.Query().Select(name,age,lastname).WithParent(func (q *UserQuery){
q.Select(age)
})
Filter will be parsed and mapped to ent predicates object
((name eq "foo") and (age ge 10)) or (name eq "foo2" and age leq 10)
binary_logical_compare -> unary_logical (("or"|"and") unary_logical)*
unary_logical -> "not" unary_logical | group
group -> ( "(" binary_logical_compare ")" ) | compare
compare -> IDENTIFIER binary_cmp_op (STRING | NUMBER)
---
IDENTIFIER -> ALPHA (ALPHA | DIGIT)*
STRING -> "\"" <any char except "> "\""
NUMBER -> DIGIT + ( "." DIGIT+)?
ALPHA -> "a" ... "z" | "A" ... "Z" | "_"
DIGIT -> "0" ... "9"
FIELD -> IDENTIFIER ("." IDENTIFIER)*
Fields will tell the ent which fields we want to query
query the user's parent id, user's children name, and the user's name
user.parent.id , user.children.name, name
FIELDS -> FIELD ("," FIELD)*