schemas.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. package got
  2. import (
  3. "fmt"
  4. . "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/common" // . "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/gen"
  5. G "github.com/dave/jennifer/jen"
  6. "regexp"
  7. "strings"
  8. "time" // "github.com/davecgh/go-spew/spew"
  9. )
  10. var (
  11. filled = map[string]*Entity{}
  12. numberRegex = regexp.MustCompile("(int|float).*")
  13. // bool
  14. // string
  15. // int int8 int16 int32 int64
  16. // uint uint8 uint16 uint32 uint64 uintptr
  17. // byte // alias for uint8
  18. // rune // alias for int32
  19. // // represents a Unicode code point
  20. // float32 float64
  21. // complex64 complex128
  22. primitiveRegex = regexp.MustCompile(`^(bool|string|u?int\d{0,2}|byte|rune|float\d{0,2}|complex\d{2,3})$`)
  23. )
  24. func GenSchemas(p *Project) error {
  25. var (
  26. // requiredOnCreate bool
  27. hasAddOrRemove bool
  28. filename string
  29. inputName string
  30. typ string
  31. extName string
  32. f *G.File
  33. propertie *G.Statement
  34. extend *G.Statement
  35. base = "models/"
  36. posfix = ""
  37. properties G.Statement
  38. // values G.Dict
  39. cproperties map[string]*G.Statement
  40. addUpdate map[string]string
  41. removeUpdate map[string]map[string]string
  42. entityName string
  43. entityPatchName string
  44. propName string
  45. entityInfo *EntityInfo
  46. inputProperties G.Statement
  47. patchProperties G.Statement
  48. referenceProperties G.Statement
  49. entities, err = Schemas(p)
  50. // entities = p.Schemas
  51. // err error
  52. )
  53. if err != nil {
  54. return err
  55. }
  56. go GenModelIndex(p)
  57. if err = GenFilterEntityDocument(p); err != nil {
  58. return err
  59. }
  60. if err = GenEntityHelpers(p); err != nil {
  61. return err
  62. }
  63. for _, entity := range entities {
  64. entityInfo = p.ResponseEntity(entity.ID)
  65. if entityInfo.IsGeneric {
  66. continue
  67. }
  68. inputName = ""
  69. entityPatchName = ""
  70. hasAddOrRemove = false
  71. // requiredOnCreate = false
  72. entityName = GenericPart.ReplaceAllString(entity.ID, "")
  73. filename = base + strings.ToLower(entityName)
  74. // f = G.NewFile(p.Package)
  75. f = G.NewFile("models")
  76. generateIndexsEntity(f, entity)
  77. // fmt.Println("Gerando entity: ", entityName)
  78. cproperties = map[string]*G.Statement{}
  79. // f.Comment(entity.Description)
  80. properties = G.Statement{}
  81. patchProperties = G.Statement{
  82. G.Qual(API_URL, "PatchHistoryRegister").Tag(map[string]string{
  83. "json": "-",
  84. "bson": ",inline",
  85. }),
  86. }
  87. entityModel := G.Qual(API_URL, "EntityModel").Tag(map[string]string{
  88. "json": "-",
  89. "bson": "-",
  90. })
  91. patchProperties = append(patchProperties, entityModel)
  92. // values = G.Dict{}
  93. // entityInfo = p.IsGenericEntity(entity.ID)
  94. inputProperties = G.Statement{
  95. // G.Qual(API_URL, "DotNotation").Tag(map[string]string{
  96. // "json": "-",
  97. // "bson": ",inline",
  98. // }),
  99. G.Id("DotNotation map[string]interface{}").Tag(map[string]string{
  100. "json": "-",
  101. "bson": ",inline",
  102. }),
  103. }
  104. // inputProperties = append(inputProperties, entityModel)
  105. referenceProperties = G.Statement{}
  106. addUpdate = map[string]string{}
  107. removeUpdate = map[string]map[string]string{}
  108. for _, meta := range entity.Properties {
  109. // fmt.Println("Gerando ---------- ", entityName, "---------", propName, "----", meta.Array)
  110. if meta.Targets != "" && !strings.Contains(meta.Targets, "go") {
  111. continue
  112. }
  113. propName = strings.Title(meta.ID)
  114. propertie = G.Id(propName)
  115. meta.FillTags(p, propName)
  116. posfix = ""
  117. // Registra a relaao entre as entidades
  118. if meta.Relation {
  119. posfix = "Reference"
  120. SR.Add(&Relation{
  121. Source: meta.GetType(),
  122. Target: entity.ID,
  123. Attr: strings.Replace(meta.Tags["bson"], ",omitempty", "", 1),
  124. DB: entity.DB,
  125. Collection: entity.Collection,
  126. IsArray: meta.Array,
  127. })
  128. }
  129. typ = meta.Type + posfix
  130. if typ == "any" {
  131. typ = "interface{}"
  132. }
  133. if meta.Array {
  134. hasAddOrRemove = true
  135. propertie.Op("*")
  136. propertie.Index()
  137. if !meta.Readonly {
  138. extName = "Add" + propName
  139. addUpdate[extName] = meta.ID
  140. extend = G.Id(extName).Index().Id(ConvType(typ)).Tag(map[string]string{
  141. "json": extName + ",omitempty",
  142. "bson": extName + ",omitempty",
  143. })
  144. patchProperties = append(patchProperties, extend)
  145. extName = "Remove" + propName
  146. removeUpdate[extName] = map[string]string{
  147. "type": ConvType(typ),
  148. "propId": meta.ID,
  149. }
  150. extend = G.Id(extName).Index().Interface().Tag(map[string]string{
  151. "json": extName + ",omitempty",
  152. "bson": extName + ",omitempty",
  153. })
  154. patchProperties = append(patchProperties, extend)
  155. }
  156. }
  157. // propertie.Id(entityInfo.TranslateType(meta.Type) + posfix)
  158. if strings.Contains(typ, ".") {
  159. typt := strings.Split(typ, ".")
  160. propertie.Qual(ImportMap(typt[0]), ConvType(typt[1]))
  161. } else {
  162. propertie.Id(ConvType(typ))
  163. }
  164. entity.HasMode = true
  165. // Adiciona as tags caso sejam definidas
  166. if meta.Tags != nil {
  167. // if name, ok := meta.Tags["valid"]; ok && strings.Contains(name, "requiredOnCreate") {
  168. // entity.HasMode = true
  169. // }
  170. propertie.Tag(meta.Tags)
  171. // if name, ok := meta.Tags["json"]; ok {
  172. // // tsPropertieName = strings.Split(name, ",")[0]
  173. // }
  174. } else {
  175. // tsPropertieName = meta.ID
  176. }
  177. // Adiciona a crescricao como comentario
  178. // tsPropertie = &ts.Group{}
  179. if meta.Description != "" {
  180. propertie.Comment(meta.Description)
  181. // tsPropertie.Comment(meta.Description)
  182. }
  183. // if tsPropertieName != "" {
  184. // tsPropertie.Add(ts.Public().Id(tsPropertieName).Op(":").Id(ts.ConvType(meta.Type)))
  185. // if meta.Array {
  186. // tsPropertie.Add(ts.Index())
  187. // }
  188. // tsPropertie.Endl()
  189. // tsProperties = append(tsProperties, tsPropertie)
  190. // }
  191. cproperties[meta.ID] = propertie
  192. // Adiciona o valor padrao de inicializacao
  193. // spew.Dump(meta)
  194. // if tvalue, ok := meta.Autogenerate["create"]; ok {
  195. // switch tvalue {
  196. // case "objectId":
  197. // values[G.Id(propName)] = G.Qual(BSON_PRIMITIVE, "NewObjectID").Call()
  198. // case "now":
  199. // values[G.Id(propName)] = G.Qual("time", "Now").Call().Id(".Unix()")
  200. // case "time:now":
  201. // case "user:current":
  202. // default:
  203. // // Verifica se possui valor padrão
  204. // if meta.Default != nil {
  205. // values[G.Id(propName)] = G.Lit(meta.Default)
  206. // }
  207. // }
  208. // }
  209. // Adiciona as propriedades readonly na entidade principal
  210. // e as que tem permissao de escrita na entidade input
  211. if !meta.Readonly {
  212. inputProperties = append(inputProperties, propertie)
  213. } else {
  214. properties = append(properties, propertie)
  215. }
  216. // Adiciona a propriedade que é referencia a lista de propriedades
  217. // da entidade reference
  218. if meta.Reference {
  219. if propName == "Id" {
  220. propertie = G.Id("Id").Interface().Tag(map[string]string{
  221. "json": "_id",
  222. "bson": "_id",
  223. })
  224. }
  225. referenceProperties = append(referenceProperties, propertie)
  226. }
  227. }
  228. extend = G.Qual(API_URL, "EntityModel").Tag(map[string]string{
  229. "json": "-",
  230. "bson": ",inline",
  231. })
  232. inputProperties = append(G.Statement{extend}, inputProperties...)
  233. if len(inputProperties) > 0 {
  234. // if entity.HasMode {
  235. // values[G.Id("Mode")] = G.Qual(API_URL, "Mode").Values(G.Dict{
  236. // G.Id("M"): G.Lit("create"),
  237. // })
  238. // }
  239. if len(properties) == 0 {
  240. properties = inputProperties
  241. patchProperties = append(patchProperties, G.Id("Set").Op("*").Id(entityName).Tag(map[string]string{
  242. "json": "$set,omitempty",
  243. "bson": "$set,omitempty",
  244. }))
  245. } else {
  246. inputName = entity.ID + "Input"
  247. extend = G.Id(inputName).Tag(map[string]string{
  248. "json": ",inline",
  249. "bson": ",inline",
  250. })
  251. properties = append(G.Statement{extend}, properties...)
  252. f.Comment("Representação Input aplicada em operações de update.")
  253. f.Type().Id(inputName).Struct(inputProperties...)
  254. patchProperties = append(patchProperties, G.Id("Set").Op("*").Id(inputName).Tag(map[string]string{
  255. "json": "$set,omitempty",
  256. "bson": "-",
  257. }))
  258. }
  259. }
  260. if len(referenceProperties) > 0 {
  261. f.Comment("Representação reference aplicada quando a entidade é associada a outra.")
  262. f.Type().Id(entity.ID + "Reference").Struct(referenceProperties...)
  263. }
  264. // if entity.Representations != nil {
  265. // for k, rep := range entity.Representations {
  266. // tproperties = G.Statement{}
  267. // for _, attr := range rep {
  268. // tproperties = append(tproperties, cproperties[attr])
  269. // }
  270. // f.Comment("Representação " + k)
  271. // f.Type().Id(entity.ID + k).Struct(tproperties...)
  272. // }
  273. // }
  274. if len(patchProperties) > 1 {
  275. entityPatchName = fmt.Sprintf("%sPatchs", entityName)
  276. f.Comment(entity.Description).Line().Comment("Representação de atualização")
  277. // patchProperties = append(G.Statement{*entityModel}, patchProperties)
  278. f.Type().Id(entityPatchName).Struct(patchProperties...)
  279. }
  280. // Cria a entidade normal
  281. f.Comment(entity.Description).Line().Comment("Representação Completa")
  282. f.Type().Id(entityName).Struct(properties...)
  283. // Cria a entidade em typescript
  284. // tsModels.Line().Export().Class().Id(strings.Title(entity.ID)).Block(tsProperties...).Line()
  285. f.Comment("Cria uma instancia de " + entity.ID + ".")
  286. // Cria a função de instanciar um novo elemento com os valores padrão determinados
  287. f.Func().Id("New"+entityName).Params().Op("*").Id(entityName).Block(
  288. G.Id("entity").Op(":=").Op("&").Id(entityName).Values(),
  289. G.Do(func(x *G.Statement) {
  290. if entity.HasMode {
  291. x.Add(G.Id(`entity.SetMode("create")`))
  292. }
  293. }),
  294. G.Do(func(part *G.Statement) {
  295. // user := false
  296. for _, prop := range entity.Properties {
  297. typ := ConvType(prop.Type)
  298. isMap := strings.Contains(typ, "map")
  299. if prop.Relation {
  300. typ = typ + "Reference"
  301. }
  302. if def, ok := prop.Autogenerate["create"]; ok {
  303. switch def.Type {
  304. case "objectId":
  305. part.Add(G.Id("entity").Dot(strings.Title(prop.ID)).Op("=").Qual(BSON_PRIMITIVE, "NewObjectID()").Line())
  306. case "now":
  307. part.Add(G.Id("entity").Dot(strings.Title(prop.ID)).Op("=").Qual("time", "Now").Call().Id(".Unix()").Line())
  308. case "default":
  309. part.Add(G.Id("entity").Dot(strings.Title(prop.ID)).Op("=").Lit(prop.Default).Line())
  310. }
  311. } else if prop.Array {
  312. part.Add(G.Id("entity").Dot(strings.Title(prop.ID)).Op("= &").Index().Id(typ).Values().Line())
  313. } else if isMap {
  314. part.Add(G.Id("entity").Dot(strings.Title(prop.ID)).Op("=").Id(typ).Values().Line())
  315. }
  316. }
  317. }).Line(),
  318. G.Return(G.Id("entity")).Line(),
  319. )
  320. // update = bson.M{"$set": f.Entity}
  321. // if data, ok = f.Entity.Push(); ok {
  322. // update["$push"] = data
  323. // }
  324. // if data, ok = f.Entity.Pull(); ok {
  325. // update["$pull"] = data
  326. // }
  327. if entityPatchName != "" {
  328. f.Func().Params(
  329. G.Id("t").Op("*").Id(entityPatchName),
  330. ).Id("Patch").Params().Op("*").Qual(BSON, "A").Block(
  331. G.Id("updt").Op(":=").Qual(BSON, "A").Values().Line(),
  332. G.Id(`if t.Set != nil {
  333. updt = append(updt, bson.M{"$set": t.Set})
  334. }`).Line(),
  335. G.Do(func(y *G.Statement) {
  336. if !hasAddOrRemove {
  337. return
  338. }
  339. stmts := G.Statement{
  340. G.Id("hasAdd").Op(":=").Lit(0).Line(),
  341. G.Id("hasRemove").Op(":=").Lit(0).Line(),
  342. G.Id("pull").Op(":=").Qual(BSON, "M").Values().Line(),
  343. G.Id("push").Op(":=").Qual(BSON, "M").Values().Line(),
  344. }
  345. // add entitys
  346. // spew.Dump(addUpdate)
  347. for prop, value := range addUpdate {
  348. stmts = append(stmts, G.If(G.Len(G.Id("t").Dot(prop)).Op(">").Lit(0)).Block(
  349. G.Id("hasAdd").Op("++"),
  350. G.Id("push").Index(G.Lit(value)).Op("=").Qual(BSON, "M").Values(G.Dict{
  351. G.Lit("$each"): G.Id("t").Dot(prop),
  352. }),
  353. ).Line())
  354. }
  355. // spew.Dump(removeUpdate)
  356. // remove entitys
  357. for prop, value := range removeUpdate {
  358. stmts = append(stmts, G.If(G.Len(G.Id("t").Dot(prop)).Op(">").Lit(0)).Block(
  359. G.Id("hasRemove").Op("++"),
  360. G.Do(func(hasRemove *G.Statement) {
  361. var assign G.Dict
  362. // Se o array for de um atributo de tipo primitivo
  363. if primitiveRegex.MatchString(value["type"]) {
  364. assign = G.Dict{
  365. G.Lit("$in"): G.Id("t").Dot(prop),
  366. }
  367. } else {
  368. assign = G.Dict{
  369. G.Lit("_id"): G.Qual(BSON, "M").Values(G.Dict{
  370. G.Lit("$in"): G.Id("t").Dot(prop),
  371. }),
  372. }
  373. }
  374. hasRemove.Id("pull").Index(G.Lit(value["propId"])).Op("=").Qual(BSON, "M").Values(assign)
  375. }),
  376. ).Line())
  377. }
  378. // fmt.Println("Remove:", inputName, prop, value)
  379. // fmt.Printf("%#v", G.If(G.Len(G.Id("t").Dot(prop)).Op(">").Lit(0)).Block(
  380. // G.Id("hasRemove").Op("++"),
  381. // G.Id("pull").Index(G.Lit(value)).Op("=").Qual(BSON, "M").Values(G.Dict{
  382. // G.Lit("$in"): G.Id("t").Dot(prop),
  383. // }),
  384. // ).Line())
  385. // x.Add(G.If(G.Len(G.Id("t").Dot(prop)).Op(">").Lit(0)).Block(
  386. // G.Id("hasRemove").Op("++"),
  387. // G.Id("pull").Index(G.Lit(value)).Op("=").Qual(BSON, "M").Values(G.Dict{
  388. // G.Lit("$in"): G.Id("t").Dot(prop),
  389. // }),
  390. // ).Line())
  391. stmts = append(stmts, G.If(G.Id("hasAdd").Op(">").Lit(0)).Block(
  392. // G.Id("updt").Index(G.Lit("$push")).Op("=").Id("push"),
  393. G.Id("updt").Op("=").Append(
  394. G.Id("updt"),
  395. G.Qual(BSON, "M").Values(G.Lit("$push").Id(": push")),
  396. ),
  397. // .Index(G.Lit("$push")).Op("=").Id("push"),
  398. ).Line())
  399. stmts = append(stmts, G.If(G.Id("hasRemove").Op(">").Lit(0)).Block(
  400. // G.Id("updt").Index(G.Lit("$pull")).Op("=").Id("pull"),
  401. G.Id("updt").Op("=").Append(
  402. G.Id("updt"),
  403. G.Qual(BSON, "M").Values(G.Lit("$pull").Id(": pull")),
  404. ),
  405. ).Line())
  406. y.Add(stmts...)
  407. }),
  408. G.Return(G.Op("&").Id("updt")),
  409. )
  410. }
  411. // Salva o arquivo da entidade
  412. // if err := f.Save(fmt.Sprintf("%s/%s/%s_gen.go", p.OutPath, p.Package, filename)); err != nil {
  413. if err := Write(fmt.Sprintf("%s/%s/%s_gen.go", p.OutPath, p.Package, filename), f); err != nil {
  414. return err
  415. }
  416. } // Fim do for de schema
  417. return nil
  418. }
  419. func ConvType(ntype string) string {
  420. if len(ntype) < 3 {
  421. fmt.Printf("Invalid type name '%s':\n", ntype)
  422. }
  423. if ntype[0:3] == "map" {
  424. parts := strings.Split(ntype, "|")
  425. ntype = fmt.Sprintf("map[%s]%s", parts[1], parts[2])
  426. }
  427. return ntype
  428. }
  429. func GenModelIndex(p *Project) error {
  430. var (
  431. // Index = G.NewFile(p.Package)
  432. Index = G.NewFile("models")
  433. )
  434. Index.Id(`type Entity struct {}`).Line()
  435. Index.Comment("")
  436. Index.Var().Defs(
  437. G.Id("Api").Op("=").Op("&").Qual(API_URL, "Mongo").Values(),
  438. ).Line()
  439. return Write(fmt.Sprintf("%s/%s/models/index_gen.go", p.OutPath, p.Package), Index)
  440. }
  441. func fill(p *Project, schema *Entity) (*Entity, error) {
  442. var (
  443. // found, ok bool
  444. found bool
  445. cls *Entity
  446. // newSchema = &(*schema)
  447. err error
  448. )
  449. // Se o esquema ainda não esta completo com as classes extendidas caso possua
  450. if _, found = filled[schema.ID]; !found {
  451. // fEntity = schema
  452. //
  453. // fmt.Println("Fill ............ ", schema.ID)
  454. // fmt.Println("Nao estava cheio ", schema.ID)
  455. for _, entity := range schema.Extends {
  456. if cls, err = fill(p, p.GetSchema(entity)); err != nil {
  457. return nil, err
  458. }
  459. // fmt.Println("extends ", entity)
  460. // if cls, ok = filled[entity]; !ok {
  461. // cls = p.GetSchema(entity)
  462. // // fmt.Println("Não tava cheio", entity)
  463. // // fmt.Println("fill:", schema)
  464. // // fmt.Println(cls)
  465. // if err = fill(p, cls); err != nil {
  466. // return err
  467. // }
  468. // }
  469. // else {
  470. // fmt.Println("estava cheio ", entity)
  471. // fmt.Println("Merge ", schema.ID, cls.ID, ok)
  472. schema.Properties = append(schema.Properties, cls.Properties...)
  473. }
  474. // for _, x := range schema.Properties {
  475. // fmt.Println("fill----------------", schema.ID, x.ID, len(schema.Properties))
  476. // }
  477. filled[schema.ID] = schema
  478. }
  479. return filled[schema.ID], nil
  480. }
  481. func Schemas(p *Project) ([]*Entity, error) {
  482. var (
  483. err error
  484. entities = []*Entity{}
  485. )
  486. for _, schema := range p.Schemas {
  487. if schema, err = fill(p, schema); err != nil {
  488. return nil, err
  489. }
  490. if schema.Type != "abstract" {
  491. entities = append(entities, schema)
  492. }
  493. // for _, x := range schema.Properties {
  494. // fmt.Printf("%s , %s, %p\n", schema.ID, x.ID, x)
  495. // }
  496. }
  497. // for _, s := range entities {
  498. // for _, x := range s.Properties {
  499. // fmt.Printf("final-schemas....%s , %s, %p\n", s.ID, x.ID, x)
  500. // }
  501. // }
  502. return entities, nil
  503. }
  504. func GenFilterEntityDocument(p *Project) error {
  505. var (
  506. content string
  507. path string
  508. err error
  509. )
  510. for _, s := range p.Schemas {
  511. if s.Type == "nested.object" {
  512. continue
  513. }
  514. // fmt.Println("gerando filtro ", s.ID)
  515. filter := &ApiFilter{
  516. Id: strings.ToLower(s.ID),
  517. Date: time.Now().Unix(),
  518. }
  519. for _, attr := range s.Properties {
  520. if attr.Filter == nil {
  521. continue
  522. }
  523. // Atualiza o tipo do filtro na estrutura do campo
  524. for _, filterItem := range attr.Filter {
  525. FilterTypeMap(attr, filterItem)
  526. // Atualiza o path da query
  527. if filterItem.Type == "nested" {
  528. FilterPath(filter, p, attr, attr.ID)
  529. } else {
  530. if filterItem.Path == "" {
  531. filterItem.Path = attr.ID
  532. }
  533. if filterItem.UserEnumAsOptions {
  534. filterItem.Options = []FilterOption{}
  535. // if len(attr.Values) == 0 {
  536. // attr.Values = make([]string, len(attr.Enum))
  537. // }
  538. // values = make()
  539. // }
  540. for key, value := range attr.Enum {
  541. filterItem.Options = append(filterItem.Options, FilterOption{
  542. Value: attr.Values[key],
  543. Label: value,
  544. })
  545. }
  546. }
  547. filter.Fields = append(filter.Fields, filterItem)
  548. }
  549. }
  550. }
  551. if filter.Fields == nil {
  552. continue
  553. }
  554. if content, err = JSONStringfy(filter); err != nil {
  555. return err
  556. }
  557. path = fmt.Sprintf("%s/filters/%s.json", p.OutPath, strings.ToLower(s.ID))
  558. // fmt.Printf("storing filter '%s'\n",path)
  559. if err = FilePutContents(path, content, 0777); err != nil {
  560. return err
  561. }
  562. }
  563. return nil
  564. }
  565. func FilterPath(filter *ApiFilter, p *Project, attr *Propertie, path string) {
  566. var (
  567. nfil Filter
  568. npath string
  569. typ = attr.Type
  570. )
  571. if attr.Relation {
  572. typ += "Reference"
  573. }
  574. entity := p.GetSchema(typ)
  575. for _, x := range entity.Properties {
  576. if x.Filter == nil {
  577. continue
  578. }
  579. npath = fmt.Sprintf("%s.%s", path, x.ID)
  580. for _, item := range x.Filter {
  581. if item.Type != "nested" {
  582. nfil = *item
  583. if nfil.Path == "" {
  584. nfil.Path = npath
  585. }
  586. FilterTypeMap(x, item)
  587. filter.Fields = append(filter.Fields, &nfil)
  588. } else {
  589. FilterPath(filter, p, x, npath)
  590. }
  591. }
  592. }
  593. }
  594. func FilterTypeMap(attr *Propertie, f *Filter) {
  595. typ := f.Type
  596. if typ != "" {
  597. return
  598. }
  599. switch {
  600. // Se o tipo for numerico
  601. case numberRegex.Match([]byte(typ)):
  602. f.Type = "number"
  603. default:
  604. f.Type = attr.Type
  605. }
  606. }
  607. func generateIndexsEntity(file *G.File, entity *Entity) {
  608. // keys := G.{}
  609. // options := G.Dict{
  610. // G.Id("Unique"): G.Lit(true),
  611. // // G.Id("Key"): G.Lit("unique"),
  612. // // G.Id("Value"): G.Lit(true),
  613. // }
  614. var create = false
  615. indexOptions := G.Dict{
  616. G.Id("Keys"): G.Qual(BSONX, "Doc").ValuesFunc(func(keys *G.Group) {
  617. for _, propertie := range entity.Properties {
  618. if propertie.Unique {
  619. keys.Add(G.Values(G.Lit(propertie.ID), G.Qual(BSONX, "Int32").Call(G.Lit(1))))
  620. create = true
  621. // keys[G.Lit(propertie.ID)] = G.Lit(1)
  622. }
  623. }
  624. }),
  625. // G.Id("Options"): G.Qual(BSON, "M").Values(options),
  626. G.Id("Options"): G.Id("opts.SetUnique(true)"),
  627. }
  628. if create {
  629. file.Line().Func().Id("init").Call().Block(
  630. G.Id("models.Api.Ready().Subscribe").Call(
  631. G.Func().Call(G.Id("value").Id("...interface{}")).Block(
  632. G.Id("opts := &").Qual("go.mongodb.org/mongo-driver/mongo/options", "IndexOptions").Values(),
  633. G.Id(`index := `).Qual("go.mongodb.org/mongo-driver/mongo", "IndexModel").Values(indexOptions),
  634. // G.Qual("fmt", "Println").Call(G.Lit("create index for "), G.Lit(entity.ID)),
  635. G.Id(`if err := models.Api.CreateIndex(`).Lit(entity.DB).Id(`, `).Lit(entity.Collection).Id(`, index); err != nil`).
  636. Block(
  637. G.Id("panic").Call(
  638. G.Qual("fmt", "Sprintf").Call(
  639. // G.Lit(fmt.Sprintf("Index %s creation error %s", entity.ID, err.Error())),
  640. G.Id(`"Index`).Id(entity.ID).Id(`creation error %s", err.Error()`),
  641. ),
  642. ).Line(),
  643. // (`).
  644. // Call().
  645. // Line().
  646. ),
  647. ),
  648. ),
  649. )
  650. // .BlockFunc(func(statement *G.Group) {
  651. // statement.Add(
  652. // ,
  653. // )
  654. // statement.Add(G.Line().Id("})"))
  655. // })
  656. }
  657. }
  658. func GenEntityHelpers(project *Project) error {
  659. file := G.NewFile("models")
  660. entities, err := Schemas(project)
  661. if err != nil {
  662. return err
  663. }
  664. file.Add(G.Id(`
  665. import(
  666. "reflect"
  667. "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/api/errs"
  668. context "github.com/kataras/iris/v12/context"
  669. "go.mongodb.org/mongo-driver/bson"
  670. "go.mongodb.org/mongo-driver/bson/primitive"
  671. )
  672. `))
  673. getStmtsTmpl, getStmtsErr := ParseTemplate(`
  674. func Get{{.entity}}ByID(
  675. ctx context.Context,
  676. id interface{},
  677. ) (
  678. entity *{{.entity}},
  679. err *errs.Error,
  680. ) {
  681. var errd error
  682. entity = &{{.entity}}{}
  683. value := reflect.ValueOf(id)
  684. if value.Kind() == reflect.Ptr {
  685. id = value.Elem()
  686. }
  687. if idString, ok := id.(string); ok {
  688. if id, errd = primitive.ObjectIDFromHex(idString); errd != nil {
  689. return
  690. }
  691. }
  692. options := Filter{{.entity}}Options(ctx)
  693. options.Query = &bson.M{"_id": id}
  694. options.Entity = entity
  695. if _, err = Api.FindOne(options); err != nil {
  696. return
  697. }
  698. return
  699. }
  700. `)
  701. if getStmtsErr != nil {
  702. return getStmtsErr
  703. }
  704. for _, entity := range entities {
  705. entityInfo := project.ResponseEntity(entity.ID)
  706. if entityInfo.IsGeneric || entity.Type != "object" {
  707. continue
  708. }
  709. context := map[string]interface{}{
  710. "entity": strings.Title(entity.ID),
  711. }
  712. out, _ := TemplateToString(getStmtsTmpl, context)
  713. file.Add(G.Id(out).Line())
  714. }
  715. if err := Write(
  716. fmt.Sprintf("../project/include/go/models/get_helpers.go"),
  717. file,
  718. ); err != nil {
  719. return err
  720. }
  721. return nil
  722. }