package got import ( "text/template" . "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/common" G "github.com/dave/jennifer/jen" ) var ( updateStmtsTmpl *template.Template updateStmtsErr error ) func init() { updateStmtsTmpl, updateStmtsErr = ParseTemplate(` var ( entity = &models.{{.entity}}Input{} ) if err = api.ReadJson(ctx, entity); err != nil { return } entity.SetMode("update") if err = api.Validate(entity); err != nil { return } values := ctx.Values() entity.LastUpdate = api.NowUnix() user, hasUserRef := values.Get("$user.ref").(*models.UserReference) if hasUserRef { entity.UpdatedBy = user } values.Set("entity", entity) {{if .preconditions}} if _, err = executeAction( ctx, {{.preconditions}}, ); err != nil { return } {{end}} filter := values.Get("$filter").(*api.Filter) filter.DB = "{{.dbName}}" filter.Collection = "{{.collectionName}}" filter.Entity = entity {{if .beforePersist}} if err = BeforePersist{{.entity}}Update(ctx, resp); err != nil { return }{{end}} if _, err = models.Api.UpdateOne(filter); err != nil { return } {{if .hasUpdateRelation}} // Cria uma thread que executa a atualizaca das referências. go func() { UpdateRelation{{.entity}}(filter) }() {{end}} {{if .beforeResponse}} if resp, err = executeAction( ctx, {{.beforeResponse}}, ); err != nil || resp != nil { return } {{end}} resp = entity return`) if updateStmtsErr != nil { panic(updateStmtsErr) } } var ( GenUpdateStmts = &Middleware{ Id: "implement", Type: "method", Fn: func(ctx *MiddlewareContext) error { var ( project = ctx.Project method = ctx.Method dbName = project.GetEntityDB(method.Entity) collectionName = project.GetCollection(method.Entity) dependenceMethod = BASE_HAS_DEPENDE + method.Entity beforeSend = method.Hook("beforeSend") beforePersist = method.Hook("beforePersist") relations = []map[string]interface{}{} context = map[string]interface{}{ "dbName": dbName, "collectionName": collectionName, "entity": method.Entity, "dependenceMethod": dependenceMethod, "beforeSend": beforeSend, "beforePersist": beforePersist, "relations": &relations, "hasUpdateRelation": SR.Has(method.Entity), "preconditions": parseMethodActions(method.Preconditions), "beforeResponse": parseMethodActions(method.BeforeResponse), } ) generateHookCall(project, method, "beforePersist") generateHookCall(project, method, "beforeSend") // Nome do metodo que verifica se a entidade tem dependencias out, _ := TemplateToString(updateStmtsTmpl, context) afterMethod := ctx.Statement.Block(G.Id(out)).Line() if body, err := createUpdateRelationMethod(method, context); err == nil { afterMethod.Id(body) } return nil }, } ) // updateRelationStmtsTmpl, updateStmtsErr = ParseTemplate(` // func UpdateRelation{{.entity}}(options *api.Filter) { // var ( // filter *api.Filter // err *errs.Error // entity = &{{.entity}}Reference{} // wg = sync.WaitGroup{} // ) // options.Entity = entity // if _, err = models.Api.FindOne(options); err != nil { // return // } // entity.Id = entity.Id.(primitive.ObjectID).Hex() // {{range .relations}} // wg.Add(1) // go func(){ // defer wg.Done() // filter = &api.Filter{ // Collection: "{{.Collection}}", // DB: "{{.DB}}", // Patchs: &bson.A{bson.M{"$set": bson.M{"{{.path}}": entity}}}, // Query: &bson.M{"{{.attr}}._id": entity.Id}, // } // if _, err = models.Api.PatchMany(filter); err != nil { // fmt.Println(err.Error()) // } // }() // {{end}} // wg.Wait() // }`) // if updateStmtsErr != nil { // panic(updateStmtsErr) // } // if hasUpdateRelation && !updateRelationMethodDefined { // relationFunctionDefined[updRelation] = true // for _, relation := range SR.Get(method.Entity) { // if relation.DB == "" || relation.Collection == "" { // api.LogWarning(0, fmt.Sprintf("Relation DB or Collection can't be empty! %s -> %s", relation.Target, relation.Source)) // continue // } // relations = append(relations, map[string]interface{}{ // "DB": relation.DB, // "Collection": relation.Collection, // "attr": relation.Attr, // "path": fmt.Sprintf("%s%s", relation.Attr, indexMap[relation.IsArray]), // }) // } // out, _ = TemplateToString(updateRelationStmtsTmpl, context) // afterMethod.Id(out) // } // j = G.Id("filter").Op("=").Op("&").Qual(API_URL, "Filter").Values(G.Dict{ // // Especifica a collection // G.Id("DB"): G.Lit(relation.DB), // G.Id("Collection"): G.Lit(relation.Collection), // // Especifica a query // G.Id("Query"): G.Op("&").Qual(BSON, "M").Values(G.Dict{ // G.Lit(attrId + "._id"): G.Id("f").Dot("Id").Dot("Hex").Call(), // }), // // G.Id("Entity"): G.Qual(BSON, "M").Values(G.Dict{ // // G.Lit("$set"): G.Qual(BSON, "M").Values(G.Dict{ // // G.Lit(attrId + index): G.Id("f").Dot("Entity"), // // }), // // }), // G.Id("Patchs"): G.Op("&").Qual(BSON, "A").Values( // G.Qual(BSON, "M").Values(G.Dict{ // G.Lit("$set"): G.Qual(BSON, "M").Values(G.Dict{ // G.Lit(attrId + index): G.Id("f").Dot("Entity"), // }), // }), // ), // }).Line().If( // G.List(G.Id("_"), G.Id("err")).Op("=").Id("Models").Dot("PatchMany").Call( // G.Id("filter"), // ), // G.Id("err").Op("!=").Id("nil"), // ).Block( // G.Qual("fmt", "Println").Call(G.Id("err").Dot("Error").Call()), // ).Line().Line() // k.Add(j) // .Do(func(s *G.Statement) { // _, found := relationFunctionDefined[updRelation] // if !createUpdateRelation || found { // return // } // s.Comment(updRelation + " atualiza as referências da entidade " + method.Entity).Line() // s.Func().Id(updRelation).Params( // G.Id("f").Op("*").Qual(API_URL, "Filter"), // ).Block( // G.Var().Defs( // G.Id("filter").Op("*").Qual(API_URL, "Filter"), // G.Id("err").Op("*").Qual(API_ERROR, "Error"), // ), // // atualiza o filtro para a entidade de referencia // G.Id("f").Dot("Entity").Op("=").Op("&").Id(method.Entity+"Reference").Values(), // // Carrega os dados do banco para atualizar nas entidades relacionadas // G.If( // G.List(G.Id("_"), G.Id("err")).Op("=").Id("Models").Dot("FindOne").Call( // G.Id("f"), // ), // G.Id("err").Op("!=").Id("nil"), // ).Block( // G.Return(), // ), // G.Do(func(k *G.Statement) { // Adiciona as regras de atualizacao // var ( // j *G.Statement // index string // ) // for _, relation := range SR.Get(method.Entity) { // if relation.DB == "" || relation.Collection == "" { // api.LogWarning(0, fmt.Sprintf("Relation DB or Collection can't be empty! %s -> %s", relation.Target, relation.Source)) // continue // } // // spew.Dump(relation) // // panic("sss") // // e := project.GetSchema(relation) // attrId := relation.Attr // if relation.IsArray { // index = ".$" // } else { // index = "" // } // j = G.Id("filter").Op("=").Op("&").Qual(API_URL, "Filter").Values(G.Dict{ // // Especifica a collection // G.Id("DB"): G.Lit(relation.DB), // G.Id("Collection"): G.Lit(relation.Collection), // // Especifica a query // G.Id("Query"): G.Op("&").Qual(BSON, "M").Values(G.Dict{ // G.Lit(attrId + "._id"): G.Id("f").Dot("Id").Dot("Hex").Call(), // }), // // G.Id("Entity"): G.Qual(BSON, "M").Values(G.Dict{ // // G.Lit("$set"): G.Qual(BSON, "M").Values(G.Dict{ // // G.Lit(attrId + index): G.Id("f").Dot("Entity"), // // }), // // }), // G.Id("Patchs"): G.Op("&").Qual(BSON, "A").Values( // G.Qual(BSON, "M").Values(G.Dict{ // G.Lit("$set"): G.Qual(BSON, "M").Values(G.Dict{ // G.Lit(attrId + index): G.Id("f").Dot("Entity"), // }), // }), // ), // }).Line().If( // G.List(G.Id("_"), G.Id("err")).Op("=").Id("Models").Dot("PatchMany").Call( // G.Id("filter"), // ), // G.Id("err").Op("!=").Id("nil"), // ).Block( // G.Qual("fmt", "Println").Call(G.Id("err").Dot("Error").Call()), // ).Line().Line() // k.Add(j) // } // }), // ) // }) // var ( // // UpdateRelationRotine *G.Statement // method = ctx.Method // project = ctx.Project // updRelation = UPDATE_RELATION + method.Entity // createUpdateRelation = false // entity = method.Request // responseEntity = GenericPart.ReplaceAllString(method.Response, "") // ) // if entity == "" { // panic("Modelo de request não definido em UpdateStmt!") // } // if responseEntity == "" { // panic("Modelo de response não definido!") // } // ctx.Statement.Block( // // Declaracao das variaveis // G.Var().Defs( // // G.Id("err").Op("*").Qual(API_ERROR, "Error"), // G.Id("entity").Op("=").Op("&").Id(entity).Values(), // ).Line(), // // Fazendo o parse do body // G.If( // G.Id("err").Op("=").Qual(API_URL, "ReadJson").Call(G.Id("ctx"), G.Id("entity")), // G.Id("err").Op("!=").Id("nil"), // ).Block( // // G.Id("api").Dot("Falha").Call( // // G.Id("ctx"), // // G.Id("api").Dot("ErrGeneral"), // // G.Id("err").Dot("Error").Call(), // // G.Nil(), // // ), // // G.Return(G.Id("err")), // G.Return(), // ), // G.Do(func(s *G.Statement) { // entity := ctx.Project.EntityDesc(method.Entity) // if entity != nil && entity.HasMode { // s.Add(G.Id(`entity.SetMode("create")`)) // } // }), // G.If( // G.Id("err").Op("=").Qual(API_URL, "Validate").Call(G.Id("entity")), // G.Id("err").Op("!=").Id("nil"), // ).Block( // // G.Return(G.Id("err")), // G.Return(), // ).Line(), // // Captura a base de values // G.Id("values").Op(":=").Id("ctx").Dot("Values").Call(), // // Gera as atribuicoes de variaveis que seram atualizadas (usuario e ultimo update quando existir) // G.Do(func(part *G.Statement) { // entity := ctx.Project.GetSchema(method.Entity) // user := false // for _, prop := range entity.Properties { // if def, ok := prop.Autogenerate["update"]; ok { // switch def.Type { // case "user": // if !user { // part.Add(G.Id(`user := values.Get("$user.ref").(*UserReference)`).Line()) // user = true // } // part.Add(G.Id("entity").Dot(strings.Title(prop.ID)).Op("=").Id("user").Line()) // case "now": // part.Add(G.Id("entity").Dot(strings.Title(prop.ID)).Op("=").Qual("time", "Now").Call().Id(".Unix()").Line()) // } // } // } // }).Line(), // // Carrega o filtro do contexto para adicionar a entidade // G.Id("filter").Op(":=").Id("values").Dot("Get").Call( // G.Lit("$filter"), // ).Assert(G.Op("*").Qual(API_URL, "Filter")).Line(), // // Adiciona a entidade // G.Id("filter").Dot("DB").Op("=").Lit(ctx.Project.GetEntityDB(method.Entity)), // G.Id("filter").Dot("Collection").Op("=").Lit(ctx.Project.GetCollection(method.Entity)), // G.Id("filter").Dot("Entity").Op("=").Id("entity").Line(), // generateHookCall(project, method, "beforePersist"), // // Inseri a entidade na coleção e verifica se a operação ocorreu com exito // G.If( // G.List(G.Id("_"), G.Id("err")).Op("=").Id("Models").Dot("UpdateOne").Call( // // G.Lit(ctx.Project.GetCollection(method.Entity)), // G.Id("filter"), // ), // G.Id("err").Op("!=").Id("nil"), // ).Block( // // G.Id("api").Dot("Falha").Call( // // G.Id("ctx"), // // G.Id("api").Dot("ErrGeneral"), // // G.Id("err").Dot("Error").Call(), // // G.Nil(), // // ), // // bson.IsObjectIdHex(m.Id.Hex()) // // G.Return(G.Id("err")), // G.Return(), // ), // // Cria a rotina de atualização de relacionamentos // G.Do(func(s *G.Statement) { // if SR.Has(method.Entity) { // createUpdateRelation = true // relationFunctionDefined[updRelation] = true // s.Comment("Cria uma thread que executa a atualizaca das referências.").Line().Go().Func().Params().Block( // G.Id(updRelation).Call(G.Id("filter")), // ).Call() // } // }), // // Envia a resposta pro usuario em caso de sucesso // // G.Line().Id("resp").Op("=").Id(responseEntity).Values(G.Dict{ // // G.Id("Entity"): G.Id("entity"), // // }), // G.Line().Id("resp").Op("=").Id("entity"), // generateHookCall(project, method, "beforeSend"), // // G.Return(G.Nil()), // G.Return(), // ).Line()