sonamu 0.4.9 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/{base-model-C24du9JT.d.ts → base-model-Br6krkwK.d.ts} +1 -1
  2. package/dist/{base-model-IZdmwmB5.d.mts → base-model-BvVra-8f.d.mts} +1 -1
  3. package/dist/bin/cli.js +51 -51
  4. package/dist/bin/cli.mjs +2 -2
  5. package/dist/{chunk-OTL37JQ4.mjs → chunk-634GIW42.mjs} +10 -8
  6. package/dist/chunk-634GIW42.mjs.map +1 -0
  7. package/dist/{chunk-AK547YMV.mjs → chunk-A2BDNO7E.mjs} +2 -2
  8. package/dist/{chunk-LD7OHPVK.js → chunk-GUKIIOZI.js} +108 -106
  9. package/dist/chunk-GUKIIOZI.js.map +1 -0
  10. package/dist/{chunk-IV7ZWWBN.mjs → chunk-GUV6I64Y.mjs} +69 -40
  11. package/dist/chunk-GUV6I64Y.mjs.map +1 -0
  12. package/dist/{chunk-2VEHSKNA.js → chunk-KX4762I3.js} +69 -40
  13. package/dist/chunk-KX4762I3.js.map +1 -0
  14. package/dist/{chunk-L3RJSG2K.mjs → chunk-PGPMEMK6.mjs} +2 -2
  15. package/dist/{chunk-IDNBP4MH.js → chunk-QIHV5UYF.js} +4 -4
  16. package/dist/{chunk-GHF56FO6.js → chunk-Z53BUBO4.js} +7 -7
  17. package/dist/database/drivers/knex/base-model.d.mts +2 -2
  18. package/dist/database/drivers/knex/base-model.d.ts +2 -2
  19. package/dist/database/drivers/knex/base-model.js +8 -8
  20. package/dist/database/drivers/knex/base-model.mjs +3 -3
  21. package/dist/database/drivers/kysely/base-model.d.mts +2 -2
  22. package/dist/database/drivers/kysely/base-model.d.ts +2 -2
  23. package/dist/database/drivers/kysely/base-model.js +9 -9
  24. package/dist/database/drivers/kysely/base-model.mjs +3 -3
  25. package/dist/index.d.mts +13 -5
  26. package/dist/index.d.ts +13 -5
  27. package/dist/index.js +19 -7
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +15 -3
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/{model-Dbbfpk2X.d.ts → model-DWoinpJ7.d.mts} +79 -9
  32. package/dist/{model-Dbbfpk2X.d.mts → model-DWoinpJ7.d.ts} +79 -9
  33. package/package.json +1 -1
  34. package/src/api/base-frame.ts +14 -0
  35. package/src/api/decorators.ts +2 -1
  36. package/src/entity/entity-utils.ts +1 -0
  37. package/src/entity/migrator.ts +8 -6
  38. package/src/index.ts +1 -0
  39. package/src/syncer/syncer.ts +76 -39
  40. package/src/templates/service.template.ts +4 -6
  41. package/src/types/types.ts +19 -7
  42. package/dist/chunk-2VEHSKNA.js.map +0 -1
  43. package/dist/chunk-IV7ZWWBN.mjs.map +0 -1
  44. package/dist/chunk-LD7OHPVK.js.map +0 -1
  45. package/dist/chunk-OTL37JQ4.mjs.map +0 -1
  46. /package/dist/{chunk-AK547YMV.mjs.map → chunk-A2BDNO7E.mjs.map} +0 -0
  47. /package/dist/{chunk-L3RJSG2K.mjs.map → chunk-PGPMEMK6.mjs.map} +0 -0
  48. /package/dist/{chunk-IDNBP4MH.js.map → chunk-QIHV5UYF.js.map} +0 -0
  49. /package/dist/{chunk-GHF56FO6.js.map → chunk-Z53BUBO4.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/exceptions/error-handler.ts","../src/entity/entity-utils.ts"],"sourcesContent":["import { FastifyInstance } from \"fastify\";\nimport { ZodIssue } from \"zod\";\nimport { isSoException } from \"./so-exceptions\";\n\nexport function setupErrorHandler(server: FastifyInstance) {\n server.setErrorHandler((error, request, reply) => {\n error.statusCode ??= 400;\n\n if (isSoException(error) && error.payload && Array.isArray(error.payload)) {\n const issues = error.payload as ZodIssue[];\n const [issue] = issues;\n const message = `${issue.message} (${issue.path.join(\"/\")})`;\n\n request.log.error(`${error.statusCode} ${message}`);\n reply.status(error.statusCode <= 501 ? error.statusCode : 501).send({\n name: error.name,\n code: error.code,\n message: message,\n validationErrors: error.validation,\n issues,\n });\n } else {\n request.log.error(`${error.statusCode} ${error.message}`);\n reply.status(error.statusCode <= 501 ? error.statusCode : 501).send({\n name: error.name,\n code: error.code,\n message: error.message,\n validationErrors: error.validation,\n });\n }\n });\n}\n","import inflection from \"inflection\";\nimport {\n BelongsToOneRelationProp,\n BigIntegerProp,\n BooleanProp,\n DateProp,\n DateTimeProp,\n DecimalProp,\n DistributiveOmit,\n DoubleProp,\n EnumProp,\n FloatProp,\n HasManyRelationProp,\n IntegerProp,\n JsonProp,\n ManyToManyRelationProp,\n OneToOneRelationProp,\n EntityIndex,\n StringProp,\n TextProp,\n TimeProp,\n TimestampProp,\n UuidProp,\n VirtualProp,\n} from \"../types/types\";\nimport { asArray } from \"../utils/model\";\n\nexport const p = {\n integer,\n bigInteger,\n text,\n string,\n float,\n double,\n decimal,\n boolean,\n date,\n dateTime,\n time,\n timestamp,\n json,\n uuid,\n enums,\n virtual,\n relationOneToOne,\n relationBelongsToOne,\n relationHasMany,\n relationManyToMany,\n};\n\nfunction integer(\n name: string,\n option?: Omit<IntegerProp, \"name\" | \"type\">\n): IntegerProp {\n return {\n name,\n type: \"integer\",\n ...option,\n };\n}\nfunction bigInteger(\n name: string,\n option?: Omit<BigIntegerProp, \"name\" | \"type\">\n): BigIntegerProp {\n return {\n name,\n type: \"bigInteger\",\n ...option,\n };\n}\nfunction text(name: string, option: Omit<TextProp, \"name\" | \"type\">): TextProp {\n return {\n name,\n type: \"text\",\n ...option,\n };\n}\nfunction string(\n name: string,\n option: Omit<StringProp, \"name\" | \"type\">\n): StringProp {\n return {\n name,\n type: \"string\",\n ...option,\n };\n}\nfunction float(\n name: string,\n option?: Omit<FloatProp, \"name\" | \"type\">\n): FloatProp {\n return {\n name,\n type: \"float\",\n precision: 8,\n scale: 2,\n ...option,\n };\n}\nfunction double(\n name: string,\n option?: Omit<DoubleProp, \"name\" | \"type\">\n): DoubleProp {\n return {\n name,\n type: \"double\",\n precision: 8,\n scale: 2,\n ...option,\n };\n}\nfunction decimal(\n name: string,\n option?: Omit<DecimalProp, \"name\" | \"type\">\n): DecimalProp {\n return {\n name,\n type: \"decimal\",\n precision: 8,\n scale: 2,\n ...option,\n };\n}\nfunction boolean(\n name: string,\n option?: Omit<BooleanProp, \"name\" | \"type\">\n): BooleanProp {\n return {\n name,\n type: \"boolean\",\n ...option,\n };\n}\nfunction date(\n name: string,\n option?: Omit<DateProp, \"name\" | \"type\"> & { now?: true }\n): DateProp {\n if (option?.now === true) {\n delete option.now;\n option.dbDefault = \"CURRENT_TIMESTAMP\";\n }\n return {\n name,\n type: \"date\",\n ...option,\n };\n}\nfunction dateTime(\n name: string,\n option?: Omit<DateTimeProp, \"name\" | \"type\"> & { now?: true }\n): DateTimeProp {\n if (option?.now === true) {\n delete option.now;\n option.dbDefault = \"CURRENT_TIMESTAMP\";\n }\n return {\n name,\n type: \"datetime\",\n ...option,\n };\n}\nfunction time(\n name: string,\n option?: Omit<TimeProp, \"name\" | \"type\"> & { now?: true }\n): TimeProp {\n if (option?.now === true) {\n delete option.now;\n option.dbDefault = \"CURRENT_TIMESTAMP\";\n }\n return {\n name,\n type: \"time\",\n ...option,\n };\n}\nfunction timestamp(\n name: string,\n option?: Omit<TimestampProp, \"name\" | \"type\"> & { now?: true }\n): TimestampProp {\n if (option?.now === true) {\n delete option.now;\n option.dbDefault = \"CURRENT_TIMESTAMP\";\n }\n return {\n name,\n type: \"timestamp\",\n ...option,\n };\n}\nfunction json(name: string, option: Omit<JsonProp, \"name\" | \"type\">): JsonProp {\n return {\n name,\n type: \"json\",\n ...option,\n };\n}\nfunction uuid(name: string, option: Omit<UuidProp, \"name\" | \"type\">): UuidProp {\n return {\n name,\n type: \"uuid\",\n ...option,\n };\n}\nfunction enums(\n name: string,\n option: Omit<EnumProp, \"name\" | \"type\" | \"id\"> & { id?: string }\n): EnumProp {\n return {\n name,\n type: \"enum\",\n id: option.id ?? `$Model${inflection.camelize(name)}`,\n ...option,\n };\n}\nfunction virtual(\n name: string,\n option: Omit<VirtualProp, \"name\" | \"type\" | \"dbDefault\" | \"toFilter\">\n): VirtualProp {\n return {\n name,\n type: \"virtual\",\n ...option,\n };\n}\nfunction relationOneToOne(\n name: string,\n option: DistributiveOmit<\n OneToOneRelationProp,\n \"name\" | \"type\" | \"relationType\"\n >\n): OneToOneRelationProp {\n return {\n name,\n type: \"relation\",\n relationType: \"OneToOne\",\n ...option,\n };\n}\nfunction relationBelongsToOne(\n name: string,\n option: Omit<BelongsToOneRelationProp, \"name\" | \"type\" | \"relationType\">\n): BelongsToOneRelationProp {\n return {\n name,\n type: \"relation\",\n relationType: \"BelongsToOne\",\n ...option,\n };\n}\nfunction relationHasMany(\n name: string,\n option: Omit<HasManyRelationProp, \"name\" | \"type\" | \"relationType\">\n): HasManyRelationProp {\n return {\n name,\n type: \"relation\",\n relationType: \"HasMany\",\n ...option,\n };\n}\nfunction relationManyToMany(\n name: string,\n option: Omit<ManyToManyRelationProp, \"name\" | \"type\" | \"relationType\">\n): ManyToManyRelationProp {\n return {\n name,\n type: \"relation\",\n relationType: \"ManyToMany\",\n ...option,\n };\n}\n\nexport const i = {\n index,\n unique,\n};\n\nfunction index(columns: string | string[]): EntityIndex {\n return {\n type: \"index\",\n columns: asArray(columns),\n };\n}\n\nfunction unique(columns: string | string[]): EntityIndex {\n return {\n type: \"unique\",\n columns: asArray(columns),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIO,SAAS,kBAAkB,QAAyB;AACzD,SAAO,gBAAgB,CAAC,OAAO,SAAS,UAAU;AAChD,UAAM,eAAe;AAErB,QAAI,cAAc,KAAK,KAAK,MAAM,WAAW,MAAM,QAAQ,MAAM,OAAO,GAAG;AACzE,YAAM,SAAS,MAAM;AACrB,YAAM,CAAC,KAAK,IAAI;AAChB,YAAM,UAAU,GAAG,MAAM,OAAO,KAAK,MAAM,KAAK,KAAK,GAAG,CAAC;AAEzD,cAAQ,IAAI,MAAM,GAAG,MAAM,UAAU,IAAI,OAAO,EAAE;AAClD,YAAM,OAAO,MAAM,cAAc,MAAM,MAAM,aAAa,GAAG,EAAE,KAAK;AAAA,QAClE,MAAM,MAAM;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ;AAAA,QACA,kBAAkB,MAAM;AAAA,QACxB;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,cAAQ,IAAI,MAAM,GAAG,MAAM,UAAU,IAAI,MAAM,OAAO,EAAE;AACxD,YAAM,OAAO,MAAM,cAAc,MAAM,MAAM,aAAa,GAAG,EAAE,KAAK;AAAA,QAClE,MAAM,MAAM;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,kBAAkB,MAAM;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH;;;AC/BA,OAAO,gBAAgB;AA2BhB,IAAM,IAAI;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,QACP,MACA,QACa;AACb,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,WACP,MACA,QACgB;AAChB,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KAAK,MAAc,QAAmD;AAC7E,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,OACP,MACA,QACY;AACZ,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,MACP,MACA,QACW;AACX,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO;AAAA,IACP,GAAG;AAAA,EACL;AACF;AACA,SAAS,OACP,MACA,QACY;AACZ,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO;AAAA,IACP,GAAG;AAAA,EACL;AACF;AACA,SAAS,QACP,MACA,QACa;AACb,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO;AAAA,IACP,GAAG;AAAA,EACL;AACF;AACA,SAAS,QACP,MACA,QACa;AACb,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KACP,MACA,QACU;AACV,MAAI,QAAQ,QAAQ,MAAM;AACxB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,SACP,MACA,QACc;AACd,MAAI,QAAQ,QAAQ,MAAM;AACxB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KACP,MACA,QACU;AACV,MAAI,QAAQ,QAAQ,MAAM;AACxB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,UACP,MACA,QACe;AACf,MAAI,QAAQ,QAAQ,MAAM;AACxB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KAAK,MAAc,QAAmD;AAC7E,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KAAK,MAAc,QAAmD;AAC7E,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,MACP,MACA,QACU;AACV,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,IAAI,OAAO,MAAM,SAAS,WAAW,SAAS,IAAI,CAAC;AAAA,IACnD,GAAG;AAAA,EACL;AACF;AACA,SAAS,QACP,MACA,QACa;AACb,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,iBACP,MACA,QAIsB;AACtB,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACF;AACA,SAAS,qBACP,MACA,QAC0B;AAC1B,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACF;AACA,SAAS,gBACP,MACA,QACqB;AACrB,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACF;AACA,SAAS,mBACP,MACA,QACwB;AACxB,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACF;AAEO,IAAM,IAAI;AAAA,EACf;AAAA,EACA;AACF;AAEA,SAAS,MAAM,SAAyC;AACtD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,QAAQ,OAAO;AAAA,EAC1B;AACF;AAEA,SAAS,OAAO,SAAyC;AACvD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,QAAQ,OAAO;AAAA,EAC1B;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/api/base-frame.ts","../src/exceptions/error-handler.ts","../src/entity/entity-utils.ts"],"sourcesContent":["import { Knex } from \"knex\";\nimport { DB } from \"../database/db\";\nimport { DBPreset } from \"../database/types\";\nimport { UpsertBuilder } from \"../database/upsert-builder\";\n\nexport abstract class BaseFrameClass {\n getDB(which: DBPreset): Knex {\n return DB.getDB(which) as Knex;\n }\n\n getUpsertBuilder() {\n return new UpsertBuilder<\"knex\">();\n }\n}\n","import { FastifyInstance } from \"fastify\";\nimport { ZodIssue } from \"zod\";\nimport { isSoException } from \"./so-exceptions\";\n\nexport function setupErrorHandler(server: FastifyInstance) {\n server.setErrorHandler((error, request, reply) => {\n error.statusCode ??= 400;\n\n if (isSoException(error) && error.payload && Array.isArray(error.payload)) {\n const issues = error.payload as ZodIssue[];\n const [issue] = issues;\n const message = `${issue.message} (${issue.path.join(\"/\")})`;\n\n request.log.error(`${error.statusCode} ${message}`);\n reply.status(error.statusCode <= 501 ? error.statusCode : 501).send({\n name: error.name,\n code: error.code,\n message: message,\n validationErrors: error.validation,\n issues,\n });\n } else {\n request.log.error(`${error.statusCode} ${error.message}`);\n reply.status(error.statusCode <= 501 ? error.statusCode : 501).send({\n name: error.name,\n code: error.code,\n message: error.message,\n validationErrors: error.validation,\n });\n }\n });\n}\n","import inflection from \"inflection\";\nimport {\n BelongsToOneRelationProp,\n BigIntegerProp,\n BooleanProp,\n DateProp,\n DateTimeProp,\n DecimalProp,\n DistributiveOmit,\n DoubleProp,\n EnumProp,\n FloatProp,\n HasManyRelationProp,\n IntegerProp,\n JsonProp,\n ManyToManyRelationProp,\n OneToOneRelationProp,\n EntityIndex,\n StringProp,\n TextProp,\n TimeProp,\n TimestampProp,\n UuidProp,\n VirtualProp,\n} from \"../types/types\";\nimport { asArray } from \"../utils/model\";\n\nexport const p = {\n integer,\n bigInteger,\n text,\n string,\n float,\n double,\n decimal,\n boolean,\n date,\n dateTime,\n time,\n timestamp,\n json,\n uuid,\n enums,\n virtual,\n relationOneToOne,\n relationBelongsToOne,\n relationHasMany,\n relationManyToMany,\n};\n\nfunction integer(\n name: string,\n option?: Omit<IntegerProp, \"name\" | \"type\">\n): IntegerProp {\n return {\n name,\n type: \"integer\",\n ...option,\n };\n}\nfunction bigInteger(\n name: string,\n option?: Omit<BigIntegerProp, \"name\" | \"type\">\n): BigIntegerProp {\n return {\n name,\n type: \"bigInteger\",\n ...option,\n };\n}\nfunction text(name: string, option: Omit<TextProp, \"name\" | \"type\">): TextProp {\n return {\n name,\n type: \"text\",\n ...option,\n };\n}\nfunction string(\n name: string,\n option: Omit<StringProp, \"name\" | \"type\">\n): StringProp {\n return {\n name,\n type: \"string\",\n ...option,\n };\n}\nfunction float(\n name: string,\n option?: Omit<FloatProp, \"name\" | \"type\">\n): FloatProp {\n return {\n name,\n type: \"float\",\n precision: 8,\n scale: 2,\n ...option,\n };\n}\nfunction double(\n name: string,\n option?: Omit<DoubleProp, \"name\" | \"type\">\n): DoubleProp {\n return {\n name,\n type: \"double\",\n precision: 8,\n scale: 2,\n ...option,\n };\n}\nfunction decimal(\n name: string,\n option?: Omit<DecimalProp, \"name\" | \"type\">\n): DecimalProp {\n return {\n name,\n type: \"decimal\",\n precision: 8,\n scale: 2,\n ...option,\n };\n}\nfunction boolean(\n name: string,\n option?: Omit<BooleanProp, \"name\" | \"type\">\n): BooleanProp {\n return {\n name,\n type: \"boolean\",\n ...option,\n };\n}\nfunction date(\n name: string,\n option?: Omit<DateProp, \"name\" | \"type\"> & { now?: true }\n): DateProp {\n if (option?.now === true) {\n delete option.now;\n option.dbDefault = \"CURRENT_TIMESTAMP\";\n }\n return {\n name,\n type: \"date\",\n ...option,\n };\n}\nfunction dateTime(\n name: string,\n option?: Omit<DateTimeProp, \"name\" | \"type\"> & { now?: true }\n): DateTimeProp {\n if (option?.now === true) {\n delete option.now;\n option.dbDefault = \"CURRENT_TIMESTAMP\";\n }\n return {\n name,\n type: \"datetime\",\n ...option,\n };\n}\nfunction time(\n name: string,\n option?: Omit<TimeProp, \"name\" | \"type\"> & { now?: true }\n): TimeProp {\n if (option?.now === true) {\n delete option.now;\n option.dbDefault = \"CURRENT_TIMESTAMP\";\n }\n return {\n name,\n type: \"time\",\n ...option,\n };\n}\nfunction timestamp(\n name: string,\n option?: Omit<TimestampProp, \"name\" | \"type\"> & { now?: true }\n): TimestampProp {\n if (option?.now === true) {\n delete option.now;\n option.dbDefault = \"CURRENT_TIMESTAMP\";\n }\n return {\n name,\n type: \"timestamp\",\n ...option,\n };\n}\nfunction json(name: string, option: Omit<JsonProp, \"name\" | \"type\">): JsonProp {\n return {\n name,\n type: \"json\",\n ...option,\n };\n}\nfunction uuid(name: string, option: Omit<UuidProp, \"name\" | \"type\">): UuidProp {\n return {\n name,\n type: \"uuid\",\n ...option,\n };\n}\nfunction enums(\n name: string,\n option: Omit<EnumProp, \"name\" | \"type\" | \"id\"> & { id?: string }\n): EnumProp {\n return {\n name,\n type: \"enum\",\n id: option.id ?? `$Model${inflection.camelize(name)}`,\n ...option,\n };\n}\nfunction virtual(\n name: string,\n option: Omit<VirtualProp, \"name\" | \"type\" | \"dbDefault\" | \"toFilter\">\n): VirtualProp {\n return {\n name,\n type: \"virtual\",\n ...option,\n };\n}\nfunction relationOneToOne(\n name: string,\n option: DistributiveOmit<\n OneToOneRelationProp,\n \"name\" | \"type\" | \"relationType\"\n >\n): OneToOneRelationProp {\n return {\n name,\n type: \"relation\",\n relationType: \"OneToOne\",\n ...option,\n };\n}\nfunction relationBelongsToOne(\n name: string,\n option: Omit<BelongsToOneRelationProp, \"name\" | \"type\" | \"relationType\">\n): BelongsToOneRelationProp {\n option.useConstraint = (option.useConstraint ?? true) as false;\n return {\n name,\n type: \"relation\",\n relationType: \"BelongsToOne\",\n ...option,\n };\n}\nfunction relationHasMany(\n name: string,\n option: Omit<HasManyRelationProp, \"name\" | \"type\" | \"relationType\">\n): HasManyRelationProp {\n return {\n name,\n type: \"relation\",\n relationType: \"HasMany\",\n ...option,\n };\n}\nfunction relationManyToMany(\n name: string,\n option: Omit<ManyToManyRelationProp, \"name\" | \"type\" | \"relationType\">\n): ManyToManyRelationProp {\n return {\n name,\n type: \"relation\",\n relationType: \"ManyToMany\",\n ...option,\n };\n}\n\nexport const i = {\n index,\n unique,\n};\n\nfunction index(columns: string | string[]): EntityIndex {\n return {\n type: \"index\",\n columns: asArray(columns),\n };\n}\n\nfunction unique(columns: string | string[]): EntityIndex {\n return {\n type: \"unique\",\n columns: asArray(columns),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKO,IAAe,iBAAf,MAA8B;AAAA,EACnC,MAAM,OAAuB;AAC3B,WAAO,GAAG,MAAM,KAAK;AAAA,EACvB;AAAA,EAEA,mBAAmB;AACjB,WAAO,IAAI,cAAsB;AAAA,EACnC;AACF;;;ACTO,SAAS,kBAAkB,QAAyB;AACzD,SAAO,gBAAgB,CAAC,OAAO,SAAS,UAAU;AAChD,UAAM,eAAe;AAErB,QAAI,cAAc,KAAK,KAAK,MAAM,WAAW,MAAM,QAAQ,MAAM,OAAO,GAAG;AACzE,YAAM,SAAS,MAAM;AACrB,YAAM,CAAC,KAAK,IAAI;AAChB,YAAM,UAAU,GAAG,MAAM,OAAO,KAAK,MAAM,KAAK,KAAK,GAAG,CAAC;AAEzD,cAAQ,IAAI,MAAM,GAAG,MAAM,UAAU,IAAI,OAAO,EAAE;AAClD,YAAM,OAAO,MAAM,cAAc,MAAM,MAAM,aAAa,GAAG,EAAE,KAAK;AAAA,QAClE,MAAM,MAAM;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ;AAAA,QACA,kBAAkB,MAAM;AAAA,QACxB;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,cAAQ,IAAI,MAAM,GAAG,MAAM,UAAU,IAAI,MAAM,OAAO,EAAE;AACxD,YAAM,OAAO,MAAM,cAAc,MAAM,MAAM,aAAa,GAAG,EAAE,KAAK;AAAA,QAClE,MAAM,MAAM;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,kBAAkB,MAAM;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH;;;AC/BA,OAAO,gBAAgB;AA2BhB,IAAM,IAAI;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,QACP,MACA,QACa;AACb,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,WACP,MACA,QACgB;AAChB,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KAAK,MAAc,QAAmD;AAC7E,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,OACP,MACA,QACY;AACZ,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,MACP,MACA,QACW;AACX,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO;AAAA,IACP,GAAG;AAAA,EACL;AACF;AACA,SAAS,OACP,MACA,QACY;AACZ,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO;AAAA,IACP,GAAG;AAAA,EACL;AACF;AACA,SAAS,QACP,MACA,QACa;AACb,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,WAAW;AAAA,IACX,OAAO;AAAA,IACP,GAAG;AAAA,EACL;AACF;AACA,SAAS,QACP,MACA,QACa;AACb,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KACP,MACA,QACU;AACV,MAAI,QAAQ,QAAQ,MAAM;AACxB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,SACP,MACA,QACc;AACd,MAAI,QAAQ,QAAQ,MAAM;AACxB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KACP,MACA,QACU;AACV,MAAI,QAAQ,QAAQ,MAAM;AACxB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,UACP,MACA,QACe;AACf,MAAI,QAAQ,QAAQ,MAAM;AACxB,WAAO,OAAO;AACd,WAAO,YAAY;AAAA,EACrB;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KAAK,MAAc,QAAmD;AAC7E,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,KAAK,MAAc,QAAmD;AAC7E,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,MACP,MACA,QACU;AACV,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,IAAI,OAAO,MAAM,SAAS,WAAW,SAAS,IAAI,CAAC;AAAA,IACnD,GAAG;AAAA,EACL;AACF;AACA,SAAS,QACP,MACA,QACa;AACb,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL;AACF;AACA,SAAS,iBACP,MACA,QAIsB;AACtB,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACF;AACA,SAAS,qBACP,MACA,QAC0B;AAC1B,SAAO,gBAAiB,OAAO,iBAAiB;AAChD,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACF;AACA,SAAS,gBACP,MACA,QACqB;AACrB,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACF;AACA,SAAS,mBACP,MACA,QACwB;AACxB,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACF;AAEO,IAAM,IAAI;AAAA,EACf;AAAA,EACA;AACF;AAEA,SAAS,MAAM,SAAyC;AACtD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,QAAQ,OAAO;AAAA,EAC1B;AACF;AAEA,SAAS,OAAO,SAAyC;AACvD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,QAAQ,OAAO;AAAA,EAC1B;AACF;","names":[]}
@@ -100,16 +100,18 @@ type OneToOneRelationProp = _RelationProp & {
100
100
  customJoinClause?: string;
101
101
  } & ({
102
102
  hasJoinColumn: true;
103
- onUpdate: RelationOn;
104
- onDelete: RelationOn;
103
+ useConstraint?: boolean;
104
+ onUpdate?: RelationOn;
105
+ onDelete?: RelationOn;
105
106
  } | {
106
107
  hasJoinColumn: false;
107
108
  });
108
109
  type BelongsToOneRelationProp = _RelationProp & {
109
110
  relationType: "BelongsToOne";
110
111
  customJoinClause?: string;
111
- onUpdate: RelationOn;
112
- onDelete: RelationOn;
112
+ useConstraint?: boolean;
113
+ onUpdate?: RelationOn;
114
+ onDelete?: RelationOn;
113
115
  };
114
116
  type HasManyRelationProp = _RelationProp & {
115
117
  relationType: "HasMany";
@@ -467,11 +469,59 @@ declare const TemplateOptions: z.ZodObject<{
467
469
  entityId: string;
468
470
  }>;
469
471
  service: z.ZodObject<{
470
- entityId: z.ZodString;
472
+ namesRecord: z.ZodObject<{
473
+ fs: z.ZodString;
474
+ fsPlural: z.ZodString;
475
+ camel: z.ZodString;
476
+ camelPlural: z.ZodString;
477
+ capital: z.ZodString;
478
+ capitalPlural: z.ZodString;
479
+ upper: z.ZodString;
480
+ constant: z.ZodString;
481
+ }, "strip", z.ZodTypeAny, {
482
+ fs: string;
483
+ fsPlural: string;
484
+ camel: string;
485
+ camelPlural: string;
486
+ capital: string;
487
+ capitalPlural: string;
488
+ upper: string;
489
+ constant: string;
490
+ }, {
491
+ fs: string;
492
+ fsPlural: string;
493
+ camel: string;
494
+ camelPlural: string;
495
+ capital: string;
496
+ capitalPlural: string;
497
+ upper: string;
498
+ constant: string;
499
+ }>;
500
+ modelTsPath: z.ZodString;
471
501
  }, "strip", z.ZodTypeAny, {
472
- entityId: string;
502
+ namesRecord: {
503
+ fs: string;
504
+ fsPlural: string;
505
+ camel: string;
506
+ camelPlural: string;
507
+ capital: string;
508
+ capitalPlural: string;
509
+ upper: string;
510
+ constant: string;
511
+ };
512
+ modelTsPath: string;
473
513
  }, {
474
- entityId: string;
514
+ namesRecord: {
515
+ fs: string;
516
+ fsPlural: string;
517
+ camel: string;
518
+ camelPlural: string;
519
+ capital: string;
520
+ capitalPlural: string;
521
+ upper: string;
522
+ constant: string;
523
+ };
524
+ modelTsPath: string;
475
525
  }>;
476
526
  view_list: z.ZodObject<{
477
527
  entityId: z.ZodString;
@@ -609,7 +659,17 @@ declare const TemplateOptions: z.ZodObject<{
609
659
  entityId: string;
610
660
  };
611
661
  service: {
612
- entityId: string;
662
+ namesRecord: {
663
+ fs: string;
664
+ fsPlural: string;
665
+ camel: string;
666
+ camelPlural: string;
667
+ capital: string;
668
+ capitalPlural: string;
669
+ upper: string;
670
+ constant: string;
671
+ };
672
+ modelTsPath: string;
613
673
  };
614
674
  view_list: {
615
675
  entityId: string;
@@ -681,7 +741,17 @@ declare const TemplateOptions: z.ZodObject<{
681
741
  entityId: string;
682
742
  };
683
743
  service: {
684
- entityId: string;
744
+ namesRecord: {
745
+ fs: string;
746
+ fsPlural: string;
747
+ camel: string;
748
+ camelPlural: string;
749
+ capital: string;
750
+ capitalPlural: string;
751
+ upper: string;
752
+ constant: string;
753
+ };
754
+ modelTsPath: string;
685
755
  };
686
756
  view_list: {
687
757
  entityId: string;
@@ -100,16 +100,18 @@ type OneToOneRelationProp = _RelationProp & {
100
100
  customJoinClause?: string;
101
101
  } & ({
102
102
  hasJoinColumn: true;
103
- onUpdate: RelationOn;
104
- onDelete: RelationOn;
103
+ useConstraint?: boolean;
104
+ onUpdate?: RelationOn;
105
+ onDelete?: RelationOn;
105
106
  } | {
106
107
  hasJoinColumn: false;
107
108
  });
108
109
  type BelongsToOneRelationProp = _RelationProp & {
109
110
  relationType: "BelongsToOne";
110
111
  customJoinClause?: string;
111
- onUpdate: RelationOn;
112
- onDelete: RelationOn;
112
+ useConstraint?: boolean;
113
+ onUpdate?: RelationOn;
114
+ onDelete?: RelationOn;
113
115
  };
114
116
  type HasManyRelationProp = _RelationProp & {
115
117
  relationType: "HasMany";
@@ -467,11 +469,59 @@ declare const TemplateOptions: z.ZodObject<{
467
469
  entityId: string;
468
470
  }>;
469
471
  service: z.ZodObject<{
470
- entityId: z.ZodString;
472
+ namesRecord: z.ZodObject<{
473
+ fs: z.ZodString;
474
+ fsPlural: z.ZodString;
475
+ camel: z.ZodString;
476
+ camelPlural: z.ZodString;
477
+ capital: z.ZodString;
478
+ capitalPlural: z.ZodString;
479
+ upper: z.ZodString;
480
+ constant: z.ZodString;
481
+ }, "strip", z.ZodTypeAny, {
482
+ fs: string;
483
+ fsPlural: string;
484
+ camel: string;
485
+ camelPlural: string;
486
+ capital: string;
487
+ capitalPlural: string;
488
+ upper: string;
489
+ constant: string;
490
+ }, {
491
+ fs: string;
492
+ fsPlural: string;
493
+ camel: string;
494
+ camelPlural: string;
495
+ capital: string;
496
+ capitalPlural: string;
497
+ upper: string;
498
+ constant: string;
499
+ }>;
500
+ modelTsPath: z.ZodString;
471
501
  }, "strip", z.ZodTypeAny, {
472
- entityId: string;
502
+ namesRecord: {
503
+ fs: string;
504
+ fsPlural: string;
505
+ camel: string;
506
+ camelPlural: string;
507
+ capital: string;
508
+ capitalPlural: string;
509
+ upper: string;
510
+ constant: string;
511
+ };
512
+ modelTsPath: string;
473
513
  }, {
474
- entityId: string;
514
+ namesRecord: {
515
+ fs: string;
516
+ fsPlural: string;
517
+ camel: string;
518
+ camelPlural: string;
519
+ capital: string;
520
+ capitalPlural: string;
521
+ upper: string;
522
+ constant: string;
523
+ };
524
+ modelTsPath: string;
475
525
  }>;
476
526
  view_list: z.ZodObject<{
477
527
  entityId: z.ZodString;
@@ -609,7 +659,17 @@ declare const TemplateOptions: z.ZodObject<{
609
659
  entityId: string;
610
660
  };
611
661
  service: {
612
- entityId: string;
662
+ namesRecord: {
663
+ fs: string;
664
+ fsPlural: string;
665
+ camel: string;
666
+ camelPlural: string;
667
+ capital: string;
668
+ capitalPlural: string;
669
+ upper: string;
670
+ constant: string;
671
+ };
672
+ modelTsPath: string;
613
673
  };
614
674
  view_list: {
615
675
  entityId: string;
@@ -681,7 +741,17 @@ declare const TemplateOptions: z.ZodObject<{
681
741
  entityId: string;
682
742
  };
683
743
  service: {
684
- entityId: string;
744
+ namesRecord: {
745
+ fs: string;
746
+ fsPlural: string;
747
+ camel: string;
748
+ camelPlural: string;
749
+ capital: string;
750
+ capitalPlural: string;
751
+ upper: string;
752
+ constant: string;
753
+ };
754
+ modelTsPath: string;
685
755
  };
686
756
  view_list: {
687
757
  entityId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonamu",
3
- "version": "0.4.9",
3
+ "version": "0.4.11",
4
4
  "description": "Sonamu — TypeScript Fullstack API Framework",
5
5
  "keywords": [
6
6
  "typescript",
@@ -0,0 +1,14 @@
1
+ import { Knex } from "knex";
2
+ import { DB } from "../database/db";
3
+ import { DBPreset } from "../database/types";
4
+ import { UpsertBuilder } from "../database/upsert-builder";
5
+
6
+ export abstract class BaseFrameClass {
7
+ getDB(which: DBPreset): Knex {
8
+ return DB.getDB(which) as Knex;
9
+ }
10
+
11
+ getUpsertBuilder() {
12
+ return new UpsertBuilder<"knex">();
13
+ }
14
+ }
@@ -49,8 +49,9 @@ export function api(options: ApiDecoratorOptions = {}) {
49
49
  return function (target: Object, propertyKey: string) {
50
50
  const modelName = target.constructor.name.match(/(.+)Class$/)![1];
51
51
  const methodName = propertyKey;
52
+
52
53
  const defaultPath = `/${inflection.camelize(
53
- modelName.replace(/Model$/, ""),
54
+ modelName.replace(/Model$/, "").replace(/Frame$/, ""),
54
55
  true
55
56
  )}/${inflection.camelize(propertyKey, true)}`;
56
57
 
@@ -240,6 +240,7 @@ function relationBelongsToOne(
240
240
  name: string,
241
241
  option: Omit<BelongsToOneRelationProp, "name" | "type" | "relationType">
242
242
  ): BelongsToOneRelationProp {
243
+ option.useConstraint = (option.useConstraint ?? true) as false;
243
244
  return {
244
245
  name,
245
246
  type: "relation",
@@ -1246,12 +1246,14 @@ export class Migrator {
1246
1246
  unsigned: true,
1247
1247
  nullable: prop.nullable ?? false,
1248
1248
  });
1249
- r.foreigns.push({
1250
- columns: [idColumnName],
1251
- to: `${inflection.underscore(inflection.pluralize(prop.with)).toLowerCase()}.id`,
1252
- onUpdate: prop.onUpdate,
1253
- onDelete: prop.onDelete,
1254
- });
1249
+ if ((prop.useConstraint ?? true) === true) {
1250
+ r.foreigns.push({
1251
+ columns: [idColumnName],
1252
+ to: `${inflection.underscore(inflection.pluralize(prop.with)).toLowerCase()}.id`,
1253
+ onUpdate: prop.onUpdate ?? "RESTRICT",
1254
+ onDelete: prop.onDelete ?? "RESTRICT",
1255
+ });
1256
+ }
1255
1257
  }
1256
1258
 
1257
1259
  return r;
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export * from "./api/code-converters";
2
2
  export * from "./api/context";
3
3
  export * from "./api/decorators";
4
4
  export * from "./api/sonamu";
5
+ export * from "./api/base-frame";
5
6
  export * from "./database/db";
6
7
  export * from "./database/upsert-builder";
7
8
  export * from "./database/types";
@@ -5,7 +5,7 @@ import crypto from "crypto";
5
5
  import equal from "fast-deep-equal";
6
6
  import _ from "lodash";
7
7
  import inflection from "inflection";
8
- import { EntityManager } from "../entity/entity-manager";
8
+ import { EntityManager, EntityNamesRecord } from "../entity/entity-manager";
9
9
  import ts from "typescript";
10
10
  import {
11
11
  ApiParam,
@@ -79,7 +79,13 @@ import { Template__kysely_interface } from "../templates/kysely_types.template";
79
79
  import { DB } from "../database/db";
80
80
  import { setTimeout as setTimeoutPromises } from "timers/promises";
81
81
 
82
- type FileType = "model" | "types" | "functions" | "generated" | "entity";
82
+ type FileType =
83
+ | "model"
84
+ | "types"
85
+ | "functions"
86
+ | "generated"
87
+ | "entity"
88
+ | "frame";
83
89
  type GlobPattern = {
84
90
  [key in FileType]: string;
85
91
  };
@@ -200,7 +206,7 @@ export class Syncer {
200
206
  // 다른 부분 찾아 액션
201
207
  const diffGroups = _.groupBy(diffFiles, (r) => {
202
208
  const matched = r.match(
203
- /\.(model|types|functions|entity|generated)\.[tj]s/
209
+ /\.(model|types|functions|entity|generated|frame)\.[tj]s/
204
210
  );
205
211
  return matched![1];
206
212
  }) as unknown as DiffGroups;
@@ -255,12 +261,44 @@ export class Syncer {
255
261
  }
256
262
 
257
263
  // 트리거: model
258
- if (diffTypes.includes("model")) {
259
- const entityIds = this.getEntityIdFromPath(diffGroups["model"]);
264
+ if (diffTypes.includes("model") || diffTypes.includes("frame")) {
260
265
  console.log("// 액션: 서비스 생성");
261
- await this.actionGenerateServices(entityIds);
266
+ const mergedGroup = [
267
+ ...(diffGroups["model"] ?? []),
268
+ ...(diffGroups["frame"] ?? []),
269
+ ];
270
+ const params: { namesRecord: EntityNamesRecord; modelTsPath: string }[] =
271
+ mergedGroup.map((modelPath) => {
272
+ if (modelPath.endsWith(".model.js")) {
273
+ const entityId = this.getEntityIdFromPath([modelPath])[0];
274
+ return {
275
+ namesRecord: EntityManager.getNamesFromId(entityId),
276
+ modelTsPath: path.join(
277
+ Sonamu.apiRootPath,
278
+ modelPath
279
+ .replace("/dist/", "/src/")
280
+ .replace(".model.js", ".model.ts")
281
+ ),
282
+ };
283
+ }
284
+ if (modelPath.endsWith("frame.js")) {
285
+ const [, frameName] = modelPath.match(/.+\/(.+)\.frame.js$/) ?? [];
286
+ return {
287
+ namesRecord: EntityManager.getNamesFromId(frameName),
288
+ modelTsPath: path.join(
289
+ Sonamu.apiRootPath,
290
+ modelPath
291
+ .replace("/dist/", "/src/")
292
+ .replace(".frame.js", ".frame.ts")
293
+ ),
294
+ };
295
+ }
296
+ throw new Error("not reachable");
297
+ });
298
+ await this.actionGenerateServices(params);
299
+
262
300
  console.log("// 액션: HTTP파일 생성");
263
- await this.actionGenerateHttps(entityIds);
301
+ await this.actionGenerateHttps();
264
302
  }
265
303
 
266
304
  // 저장
@@ -292,19 +330,18 @@ export class Syncer {
292
330
  .flat();
293
331
  }
294
332
 
295
- async actionGenerateServices(entityIds: string[]): Promise<string[]> {
333
+ async actionGenerateServices(
334
+ paramsArray: {
335
+ namesRecord: EntityNamesRecord;
336
+ modelTsPath: string;
337
+ }[]
338
+ ): Promise<string[]> {
296
339
  return (
297
340
  await Promise.all(
298
- entityIds.map(async (entityId) =>
299
- this.generateTemplate(
300
- "service",
301
- {
302
- entityId,
303
- },
304
- {
305
- overwrite: true,
306
- }
307
- )
341
+ paramsArray.map(async (params) =>
342
+ this.generateTemplate("service", params, {
343
+ overwrite: true,
344
+ })
308
345
  )
309
346
  )
310
347
  )
@@ -312,10 +349,10 @@ export class Syncer {
312
349
  .flat();
313
350
  }
314
351
 
315
- async actionGenerateHttps(entityIds: string[]): Promise<string[]> {
352
+ async actionGenerateHttps(): Promise<string[]> {
316
353
  const [res] = await this.generateTemplate(
317
354
  "generated_http",
318
- { entityId: entityIds[0] },
355
+ {},
319
356
  { overwrite: true }
320
357
  );
321
358
  return res;
@@ -383,6 +420,7 @@ export class Syncer {
383
420
  functions: Sonamu.apiRootPath + "/src/application/**/*.functions.ts",
384
421
  /* compiled-JS 체크 */
385
422
  model: Sonamu.apiRootPath + "/dist/application/**/*.model.js",
423
+ frame: Sonamu.apiRootPath + "/dist/application/**/*.frame.js",
386
424
  };
387
425
 
388
426
  const filePaths = (
@@ -525,6 +563,12 @@ export class Syncer {
525
563
  method.methodName === api.methodName
526
564
  );
527
565
  });
566
+ if (currentModelApis.length === 0) {
567
+ // const p = path.join(tmpdir(), "sonamu-syncer-error.json");
568
+ // writeFileSync(p, JSON.stringify(registeredApis, null, 2));
569
+ // execSync(`open ${p}`);
570
+ throw new Error(`현재 파일에 사전 등록된 API가 없습니다. ${filePath}`);
571
+ }
528
572
 
529
573
  // 등록된 API에 현재 메소드 타입 정보 확장
530
574
  const extendedApis = currentModelApis.map((api) => {
@@ -722,7 +766,7 @@ export class Syncer {
722
766
  async autoloadApis() {
723
767
  const pathPattern = path.join(
724
768
  Sonamu.apiRootPath,
725
- "/src/application/**/*.model.ts"
769
+ "/src/application/**/*.{model,frame}.ts"
726
770
  );
727
771
  // console.debug(chalk.yellow(`autoload:APIs @ ${pathPattern}`));
728
772
 
@@ -737,7 +781,7 @@ export class Syncer {
737
781
  async autoloadModels(): Promise<{ [modelName: string]: unknown }> {
738
782
  const pathPattern = path.join(
739
783
  Sonamu.apiRootPath,
740
- "dist/application/**/*.model.js"
784
+ "dist/application/**/*.{model,frame}.js"
741
785
  );
742
786
  // console.debug(chalk.yellow(`autoload:models @ ${pathPattern}`));
743
787
 
@@ -752,7 +796,9 @@ export class Syncer {
752
796
  .map(({ imported }) => Object.entries(imported))
753
797
  .flat();
754
798
  this.models = Object.fromEntries(
755
- functions.filter(([name]) => name.endsWith("Model"))
799
+ functions.filter(
800
+ ([name]) => name.endsWith("Model") || name.endsWith("Frame")
801
+ )
756
802
  );
757
803
  return this.models;
758
804
  }
@@ -839,22 +885,13 @@ export class Syncer {
839
885
  const template: Template = this.getTemplate(key);
840
886
 
841
887
  let extra: unknown[] = [];
842
- if (
843
- ["service", "generated_http", "model", "view_list", "view_form"].includes(
844
- key
845
- )
846
- ) {
847
- const entityId = (options as TemplateOptions["service"]).entityId;
848
-
849
- if (key === "service" || key === "generated_http") {
850
- // service 필요 정보 (API 리스트)
851
- const entity = EntityManager.get(entityId!);
852
- const modelTsPath = `${path.join(
853
- Sonamu.apiRootPath,
854
- "/src/application"
855
- )}/${entity.names.fs}/${entity.names.fs}.model.ts`;
856
- extra = [await this.readApisFromFile(modelTsPath)];
857
- } else if (key === "view_list" || key === "model") {
888
+ if (key === "service") {
889
+ // service 필요 정보 (API 리스트)
890
+ const { modelTsPath } = options as TemplateOptions["service"];
891
+ extra = [await this.readApisFromFile(modelTsPath)];
892
+ } else if (["model", "view_list", "view_form"].includes(key)) {
893
+ const entityId = (options as TemplateOptions["model"]).entityId;
894
+ if (key === "view_list" || key === "model") {
858
895
  // view_list 필요 정보 (컬럼 노드, 리스트파라미터 노드)
859
896
  const columnsNode = await this.getColumnsNode(entityId, "A");
860
897
  const listParamsZodType = await this.getZodTypeById(
@@ -1,7 +1,7 @@
1
1
  import inflection from "inflection";
2
2
  import _ from "lodash";
3
3
  import { TemplateOptions } from "../types/types";
4
- import { EntityManager, EntityNamesRecord } from "../entity/entity-manager";
4
+ import { EntityNamesRecord } from "../entity/entity-manager";
5
5
  import { ApiParamType, ApiParam } from "../types/types";
6
6
  import {
7
7
  apiParamTypeToTsType,
@@ -24,9 +24,7 @@ export class Template__service extends Template {
24
24
  };
25
25
  }
26
26
 
27
- render({ entityId }: TemplateOptions["service"], apis: ExtendedApi[]) {
28
- const names = EntityManager.getNamesFromId(entityId);
29
-
27
+ render({ namesRecord }: TemplateOptions["service"], apis: ExtendedApi[]) {
30
28
  // 서비스 TypeSource
31
29
  const { lines, importKeys } = this.getTypeSource(apis);
32
30
 
@@ -36,7 +34,7 @@ export class Template__service extends Template {
36
34
  );
37
35
 
38
36
  return {
39
- ...this.getTargetAndPath(names),
37
+ ...this.getTargetAndPath(namesRecord),
40
38
  body: lines.join("\n"),
41
39
  importKeys: importKeys.filter(
42
40
  (key) => ["ListResult"].includes(key) === false
@@ -154,7 +152,7 @@ export class Template__service extends Template {
154
152
  })
155
153
  .join("\n\n");
156
154
 
157
- return `export namespace ${modelName.replace(/Model$/, "Service")} {
155
+ return `export namespace ${modelName.replace(/Model$/, "Service").replace(/Frame$/, "Service")} {
158
156
  ${methodCodes}
159
157
  }`;
160
158
  })
@@ -124,8 +124,8 @@ type _RelationProp = {
124
124
  type: "relation";
125
125
  name: string;
126
126
  with: string;
127
- nullable?: boolean;
128
- toFilter?: true;
127
+ nullable?: boolean; // DEFAULT: false
128
+ toFilter?: true; // DEFAULT: false
129
129
  desc?: string;
130
130
  };
131
131
  export type OneToOneRelationProp = _RelationProp & {
@@ -134,8 +134,9 @@ export type OneToOneRelationProp = _RelationProp & {
134
134
  } & (
135
135
  | {
136
136
  hasJoinColumn: true;
137
- onUpdate: RelationOn;
138
- onDelete: RelationOn;
137
+ useConstraint?: boolean; // DEFAULT: true
138
+ onUpdate?: RelationOn; // DEFAULT: RESTRICT
139
+ onDelete?: RelationOn; // DEFAULT: RESTRICT
139
140
  }
140
141
  | {
141
142
  hasJoinColumn: false;
@@ -144,8 +145,9 @@ export type OneToOneRelationProp = _RelationProp & {
144
145
  export type BelongsToOneRelationProp = _RelationProp & {
145
146
  relationType: "BelongsToOne";
146
147
  customJoinClause?: string;
147
- onUpdate: RelationOn;
148
- onDelete: RelationOn;
148
+ useConstraint?: boolean; // DEFAULT: true
149
+ onUpdate?: RelationOn; // DEFAULT: RESTRICT
150
+ onDelete?: RelationOn; // DEFAULT: RESTRICT
149
151
  };
150
152
  export type HasManyRelationProp = _RelationProp & {
151
153
  relationType: "HasMany";
@@ -684,7 +686,17 @@ export const TemplateOptions = z.object({
684
686
  entityId: z.string(),
685
687
  }),
686
688
  service: z.object({
687
- entityId: z.string(),
689
+ namesRecord: z.object({
690
+ fs: z.string(),
691
+ fsPlural: z.string(),
692
+ camel: z.string(),
693
+ camelPlural: z.string(),
694
+ capital: z.string(),
695
+ capitalPlural: z.string(),
696
+ upper: z.string(),
697
+ constant: z.string(),
698
+ }),
699
+ modelTsPath: z.string(),
688
700
  }),
689
701
  view_list: z.object({
690
702
  entityId: z.string(),