@restforgejs/platform 4.1.1 → 4.3.1

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 (340) hide show
  1. package/SECURITY.md +83 -4
  2. package/bin/sdf-tools.exe +0 -0
  3. package/build-info.json +2 -2
  4. package/cli/consumer-deploy.js +1 -1
  5. package/cli/consumer.js +1 -1
  6. package/generators/cli/dashboard/create.js +4 -1
  7. package/generators/cli/endpoint/create.js +43 -4
  8. package/generators/cli/key/generate.js +2 -1
  9. package/generators/cli/key/revoke.js +2 -1
  10. package/generators/cli/payload/diff.js +3 -2
  11. package/generators/cli/payload/generate.js +3 -2
  12. package/generators/cli/payload/sync.js +3 -2
  13. package/generators/cli/payload/validate.js +3 -2
  14. package/generators/cli/processor/create.js +14 -3
  15. package/generators/cli/project/delete.js +2 -1
  16. package/generators/cli/query/validate.js +3 -2
  17. package/generators/cli/schema/apply.js +526 -0
  18. package/generators/cli/schema/describe.js +3 -2
  19. package/generators/cli/schema/diff.js +322 -0
  20. package/generators/cli/schema/generate-ddl.js +7 -10
  21. package/generators/cli/schema/init.js +95 -172
  22. package/generators/cli/schema/introspect.js +3 -2
  23. package/generators/cli/schema/list.js +3 -2
  24. package/generators/cli/schema/migrate.js +13 -18
  25. package/generators/cli/schema/models.js +8 -12
  26. package/generators/cli/schema/template.js +222 -0
  27. package/generators/cli/schema/validate.js +8 -12
  28. package/generators/cli-entry.js +17 -2
  29. package/generators/lib/dbschema-kit/apply-engine.js +582 -0
  30. package/generators/lib/dbschema-kit/diff-engine.js +703 -0
  31. package/generators/lib/dbschema-kit/diff-reporter.js +272 -0
  32. package/generators/lib/dbschema-kit/emitters/alter-table.js +275 -0
  33. package/generators/lib/migration/audit-table-runner.js +213 -215
  34. package/generators/lib/payload/endpoint-schema-validator.js +171 -0
  35. package/generators/lib/payload/payload-runner.js +137 -220
  36. package/generators/lib/payload/schema-diff.js +277 -0
  37. package/generators/lib/templates/dashboard-catalog.js +1 -437
  38. package/generators/lib/templates/db-connection-env.js +1 -212
  39. package/generators/lib/templates/dbschema-catalog.js +1 -489
  40. package/generators/lib/templates/field-validation-catalog.js +1 -531
  41. package/generators/lib/templates/mysql-template.js +1 -3863
  42. package/generators/lib/templates/oracle-template.js +1 -3915
  43. package/generators/lib/templates/postgres-template.js +1 -5838
  44. package/generators/lib/templates/query-declarative-catalog.js +1 -199
  45. package/generators/lib/templates/sqlite-template.js +1 -3440
  46. package/generators/lib/utils/audit-columns.js +181 -0
  47. package/generators/lib/utils/cli-output.js +17 -0
  48. package/generators/lib/utils/database-introspector.js +16 -13
  49. package/generators/lib/utils/env-manager.js +6 -0
  50. package/generators/lib/utils/path-validator.js +71 -0
  51. package/generators/lib/validators/payload-validator.js +1 -2
  52. package/integrity-manifest.json +28 -10
  53. package/package.json +11 -3
  54. package/scripts/verify-integrity.js +1 -1
  55. package/server.js +1 -1
  56. package/src/components/handlers/adjust_handler.js +1 -1
  57. package/src/components/handlers/audit_handler.js +1 -1
  58. package/src/components/handlers/delete_handler.js +1 -1
  59. package/src/components/handlers/export_handler.js +1 -1
  60. package/src/components/handlers/import_handler.js +1 -1
  61. package/src/components/handlers/insert_handler.js +1 -1
  62. package/src/components/handlers/update_handler.js +1 -1
  63. package/src/components/handlers/upload_handler.js +1 -1
  64. package/src/components/handlers/workflow_handler.js +1 -1
  65. package/src/components/integrations/webhook.js +1 -1
  66. package/src/consumers/baseConsumer.js +1 -1
  67. package/src/consumers/declarativeMapper.js +1 -1
  68. package/src/consumers/handlers/apiHandler.js +1 -1
  69. package/src/consumers/handlers/consoleHandler.js +1 -1
  70. package/src/consumers/handlers/databaseHandler.js +1 -1
  71. package/src/consumers/handlers/index.js +1 -1
  72. package/src/consumers/handlers/kafkaHandler.js +1 -1
  73. package/src/consumers/index.js +1 -1
  74. package/src/consumers/messageTransformer.js +1 -1
  75. package/src/consumers/validator.js +1 -1
  76. package/src/core/db/dialect/base-dialect.js +1 -1
  77. package/src/core/db/dialect/index.js +1 -1
  78. package/src/core/db/dialect/mysql-dialect.js +1 -1
  79. package/src/core/db/dialect/oracle-dialect.js +1 -1
  80. package/src/core/db/dialect/postgres-dialect.js +1 -1
  81. package/src/core/db/dialect/sqlite-dialect.js +1 -1
  82. package/src/core/db/flatten-helper.js +1 -1
  83. package/src/core/db/query-builder-error.js +1 -1
  84. package/src/core/db/query-builder.js +1 -1
  85. package/src/core/db/relation-helper.js +1 -1
  86. package/src/core/handlers/delete_handler.js +1 -1
  87. package/src/core/handlers/insert_handler.js +1 -1
  88. package/src/core/handlers/update_handler.js +1 -1
  89. package/src/core/models/base-model.js +1 -1
  90. package/src/core/utils/cache-manager.js +1 -1
  91. package/src/core/utils/component-engine.js +1 -1
  92. package/src/core/utils/context-builder.js +1 -1
  93. package/src/core/utils/datetime-formatter.js +1 -1
  94. package/src/core/utils/datetime-parser.js +1 -1
  95. package/src/core/utils/db.js +1 -1
  96. package/src/core/utils/logger.js +1 -1
  97. package/src/core/utils/payload-loader.js +1 -1
  98. package/src/core/utils/security-checks.js +1 -1
  99. package/src/middleware/body-options.js +1 -1
  100. package/src/middleware/cors.js +1 -1
  101. package/src/middleware/idempotency.js +1 -1
  102. package/src/middleware/rate-limiter.js +1 -1
  103. package/src/middleware/request-logger.js +1 -1
  104. package/src/middleware/security-headers.js +1 -1
  105. package/src/models/base-model-mysql.js +1 -1
  106. package/src/models/base-model-oracle.js +1 -1
  107. package/src/models/base-model-sqlite.js +1 -1
  108. package/src/models/base-model.js +1 -1
  109. package/src/pro/caching/redis-client.js +1 -1
  110. package/src/pro/caching/redis-helper.js +1 -1
  111. package/src/pro/consumers/baseConsumer.js +1 -1
  112. package/src/pro/consumers/declarativeMapper.js +1 -1
  113. package/src/pro/consumers/handlers/apiHandler.js +1 -1
  114. package/src/pro/consumers/handlers/consoleHandler.js +1 -1
  115. package/src/pro/consumers/handlers/databaseHandler.js +1 -1
  116. package/src/pro/consumers/handlers/index.js +1 -1
  117. package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
  118. package/src/pro/consumers/index.js +1 -1
  119. package/src/pro/consumers/messageTransformer.js +1 -1
  120. package/src/pro/consumers/validator.js +1 -1
  121. package/src/pro/database/base-model-mysql.js +1 -1
  122. package/src/pro/database/base-model-oracle.js +1 -1
  123. package/src/pro/database/base-model-sqlite.js +1 -1
  124. package/src/pro/database/db-mysql.js +1 -1
  125. package/src/pro/database/db-oracle.js +1 -1
  126. package/src/pro/database/db-sqlite.js +1 -1
  127. package/src/pro/excel/excel-generator.js +1 -1
  128. package/src/pro/excel/excel-parser.js +1 -1
  129. package/src/pro/excel/export-service.js +1 -1
  130. package/src/pro/excel/export_handler.js +1 -1
  131. package/src/pro/excel/import-service.js +1 -1
  132. package/src/pro/excel/import-validator.js +1 -1
  133. package/src/pro/excel/import_handler.js +1 -1
  134. package/src/pro/excel/upsert-builder.js +1 -1
  135. package/src/pro/idgen/idgen-routes.js +1 -1
  136. package/src/pro/integrations/lookup-resolver.js +1 -1
  137. package/src/pro/integrations/upload-handler-v2.js +1 -1
  138. package/src/pro/integrations/upload-handler.js +1 -1
  139. package/src/pro/integrations/webhook.js +1 -1
  140. package/src/pro/locking/lock-routes.js +1 -1
  141. package/src/pro/locking/resource-lock-manager.js +1 -1
  142. package/src/pro/messaging/kafkaConsumerService.js +1 -1
  143. package/src/pro/messaging/kafkaService.js +1 -1
  144. package/src/pro/messaging/messagehubService.js +1 -1
  145. package/src/pro/messaging/rabbitmqService.js +1 -1
  146. package/src/pro/scheduler/job-manager.js +1 -1
  147. package/src/pro/scheduler/job-routes.js +1 -1
  148. package/src/pro/scheduler/job-validator.js +1 -1
  149. package/src/pro/storage/base-storage-provider.js +1 -1
  150. package/src/pro/storage/file-metadata-helper.js +1 -1
  151. package/src/pro/storage/index.js +1 -1
  152. package/src/pro/storage/local-storage-provider.js +1 -1
  153. package/src/pro/storage/s3-storage-provider.js +1 -1
  154. package/src/pro/storage/upload-cleanup-job.js +1 -1
  155. package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
  156. package/src/pro/storage/upload-pending-tracker.js +1 -1
  157. package/src/pro/websocket/broadcast-helper.js +1 -1
  158. package/src/pro/websocket/index.js +1 -1
  159. package/src/pro/websocket/livesync-server.js +1 -1
  160. package/src/pro/websocket/ws-broadcaster.js +1 -1
  161. package/src/services/export-service.js +1 -1
  162. package/src/services/import-service.js +1 -1
  163. package/src/services/kafkaConsumerService.js +1 -1
  164. package/src/services/kafkaService.js +1 -1
  165. package/src/services/messagehubService.js +1 -1
  166. package/src/services/rabbitmqService.js +1 -1
  167. package/src/utils/cache-invalidation-registry.js +1 -1
  168. package/src/utils/cache-manager.js +1 -1
  169. package/src/utils/component-engine.js +1 -1
  170. package/src/utils/config-extractor.js +1 -1
  171. package/src/utils/consumerLogger.js +1 -1
  172. package/src/utils/context-builder.js +1 -1
  173. package/src/utils/dashboard-helpers.js +1 -1
  174. package/src/utils/dateHelper.js +1 -1
  175. package/src/utils/datetime-formatter.js +1 -1
  176. package/src/utils/datetime-parser.js +1 -1
  177. package/src/utils/db-bootstrap.js +1 -1
  178. package/src/utils/db-mysql.js +1 -1
  179. package/src/utils/db-oracle.js +1 -1
  180. package/src/utils/db-sqlite.js +1 -1
  181. package/src/utils/db.js +1 -1
  182. package/src/utils/demo-generator.js +1 -1
  183. package/src/utils/excel-generator.js +1 -1
  184. package/src/utils/excel-parser.js +1 -1
  185. package/src/utils/file-watcher.js +1 -1
  186. package/src/utils/id-generator.js +1 -1
  187. package/src/utils/idempotency-manager.js +1 -1
  188. package/src/utils/import-validator.js +1 -1
  189. package/src/utils/license-client.js +1 -1
  190. package/src/utils/lock-manager.js +1 -1
  191. package/src/utils/logger.js +1 -1
  192. package/src/utils/lookup-resolver.js +1 -1
  193. package/src/utils/payload-loader.js +1 -1
  194. package/src/utils/processor-response.js +1 -1
  195. package/src/utils/rabbitmq.js +1 -1
  196. package/src/utils/redis-client.js +1 -1
  197. package/src/utils/redis-helper.js +1 -1
  198. package/src/utils/request-scope.js +1 -1
  199. package/src/utils/security-checks.js +1 -1
  200. package/src/utils/service-resolver.js +1 -1
  201. package/src/utils/shutdown-coordinator.js +1 -1
  202. package/src/utils/trusted-keys.js +1 -1
  203. package/src/utils/upload-handler.js +1 -1
  204. package/src/utils/upsert-builder.js +1 -1
  205. package/src/utils/workflow-hook-executor.js +1 -1
  206. package/generators/metadata/global.json +0 -58
  207. package/generators/metadata/test-mysql-workbench.json +0 -118
  208. package/generators/metadata/test-mysql.json +0 -56
  209. package/generators/metadata/test-oracle-workbench.json +0 -118
  210. package/generators/metadata/test-oracle.json +0 -56
  211. package/generators/metadata/test-pg-workbench.json +0 -118
  212. package/generators/metadata/test-pg.json +0 -56
  213. package/generators/scripts/obfuscate-source.js +0 -356
  214. package/generators/scripts/validate-catalog.js +0 -430
  215. package/generators/scripts/validate-dbschema-catalog.js +0 -708
  216. package/generators/tests/baseline/mysql/mini_inventory_item/src/models/mini-inventory/item.js +0 -944
  217. package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
  218. package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory.js +0 -336
  219. package/generators/tests/baseline/oracle/mini_inventory_item/src/models/mini-inventory/item.js +0 -1002
  220. package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
  221. package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory.js +0 -336
  222. package/generators/tests/baseline/postgres/mini_inventory_item/src/models/mini-inventory/item.js +0 -1333
  223. package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory/item.js +0 -1173
  224. package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory.js +0 -496
  225. package/generators/tests/fixtures/payloads/custom-sensitive.json +0 -27
  226. package/generators/tests/fixtures/payloads/dynamic-search-optout.json +0 -23
  227. package/generators/tests/fixtures/payloads/login-with-password.json +0 -22
  228. package/generators/tests/fixtures/payloads/order-process.json +0 -52
  229. package/generators/tests/fixtures/payloads/with-inline-sql.json +0 -26
  230. package/generators/tests/integration-tahap4b/README.md +0 -145
  231. package/generators/tests/integration-tahap4b/run-concurrent.js +0 -77
  232. package/generators/tests/integration-tahap4b/seed.sql +0 -53
  233. package/generators/tests/integration-tahap4b/verify.sql +0 -110
  234. package/generators/tests/unit/cli/create-dashboard.test.js +0 -505
  235. package/generators/tests/unit/cli/create-processor.test.js +0 -319
  236. package/generators/tests/unit/cli/dispatch-dashboard.test.js +0 -149
  237. package/generators/tests/unit/lib/dashboard-generator.test.js +0 -895
  238. package/generators/tests/unit/lib/dashboard-validator.test.js +0 -354
  239. package/generators/tests/unit/lib/dbschema-kit/apply-executor.test.js +0 -437
  240. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-introspect.test.js +0 -393
  241. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-generate-ddl.test.js +0 -104
  242. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-init.test.js +0 -119
  243. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-list.test.js +0 -48
  244. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-migrate.test.js +0 -175
  245. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-validate.test.js +0 -102
  246. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-models.test.js +0 -43
  247. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/all-schemas-listing.js +0 -84
  248. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/connection-error.js +0 -13
  249. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/empty.js +0 -12
  250. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/multi-schema.js +0 -124
  251. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/single-schema-inventory.js +0 -64
  252. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/two-tables.js +0 -66
  253. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/connection-error.js +0 -9
  254. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/partial.js +0 -29
  255. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/rollback.js +0 -26
  256. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/success.js +0 -43
  257. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/audit/events.js +0 -18
  258. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/inventory/products.js +0 -9
  259. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/users.js +0 -8
  260. package/generators/tests/unit/lib/dbschema-kit/connection.test.js +0 -112
  261. package/generators/tests/unit/lib/dbschema-kit/ddl-generator.test.js +0 -205
  262. package/generators/tests/unit/lib/dbschema-kit/define-model.test.js +0 -56
  263. package/generators/tests/unit/lib/dbschema-kit/dialect/index.test.js +0 -46
  264. package/generators/tests/unit/lib/dbschema-kit/dialect/mysql.test.js +0 -126
  265. package/generators/tests/unit/lib/dbschema-kit/dialect/oracle.test.js +0 -126
  266. package/generators/tests/unit/lib/dbschema-kit/dialect/postgres.test.js +0 -131
  267. package/generators/tests/unit/lib/dbschema-kit/dialect/sqlite.test.js +0 -126
  268. package/generators/tests/unit/lib/dbschema-kit/driver-loader.test.js +0 -93
  269. package/generators/tests/unit/lib/dbschema-kit/emitters/create-index.test.js +0 -173
  270. package/generators/tests/unit/lib/dbschema-kit/emitters/create-table.test.js +0 -376
  271. package/generators/tests/unit/lib/dbschema-kit/emitters/drop-table.test.js +0 -78
  272. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/invalid-dialect.env +0 -6
  273. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-dialect.env +0 -5
  274. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-host.env +0 -5
  275. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/oracle-valid.env +0 -6
  276. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/postgres-valid.env +0 -7
  277. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/sqlite-valid.env +0 -2
  278. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/category.js +0 -11
  279. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/item_product.js +0 -11
  280. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound.js +0 -24
  281. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound_item.js +0 -28
  282. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/supplier.js +0 -9
  283. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/warehouse.js +0 -9
  284. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-invalid/orphan.js +0 -17
  285. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/category.js +0 -11
  286. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/item_product.js +0 -11
  287. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/supplier.js +0 -9
  288. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/warehouse.js +0 -9
  289. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound.js +0 -24
  290. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound_item.js +0 -28
  291. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/audit/events.js +0 -18
  292. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/inventory/products.js +0 -9
  293. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/public/users.js +0 -9
  294. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/extra/category.js +0 -8
  295. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/master/category.js +0 -8
  296. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/bar.js +0 -8
  297. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/foo.js +0 -8
  298. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/empty-folder/README.md +0 -1
  299. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-export/plain.js +0 -3
  300. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-schema/bad.js +0 -6
  301. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/legacy-pattern/legacy.js +0 -12
  302. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/audit/products.js +0 -9
  303. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/inventory/products.js +0 -9
  304. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/a/products.js +0 -8
  305. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/b/products.js +0 -8
  306. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/nested-deep/a/b/c/deep_table.js +0 -8
  307. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/.hidden/ignored.js +0 -7
  308. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/category.js +0 -8
  309. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/supplier.js +0 -8
  310. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound.js +0 -8
  311. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound_item.js +0 -8
  312. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/category.js +0 -8
  313. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/item_product.js +0 -9
  314. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-single/category.js +0 -8
  315. package/generators/tests/unit/lib/dbschema-kit/integration.test.js +0 -217
  316. package/generators/tests/unit/lib/dbschema-kit/introspect-mapper.test.js +0 -403
  317. package/generators/tests/unit/lib/dbschema-kit/ir-builder.test.js +0 -390
  318. package/generators/tests/unit/lib/dbschema-kit/loader.test.js +0 -128
  319. package/generators/tests/unit/lib/dbschema-kit/naming.test.js +0 -170
  320. package/generators/tests/unit/lib/dbschema-kit/parser/shorthand-parser.test.js +0 -237
  321. package/generators/tests/unit/lib/dbschema-kit/schema-printer.test.js +0 -251
  322. package/generators/tests/unit/lib/dbschema-kit/statement-modifier.test.js +0 -105
  323. package/generators/tests/unit/lib/dbschema-kit/statement-splitter.test.js +0 -165
  324. package/generators/tests/unit/lib/dbschema-kit/topological-sort.test.js +0 -135
  325. package/generators/tests/unit/lib/dbschema-kit/validator/check-compatibility-validator.test.js +0 -373
  326. package/generators/tests/unit/lib/dbschema-kit/validator/circular-relation-validator.test.js +0 -454
  327. package/generators/tests/unit/lib/dbschema-kit/validator/cross-model-validator.test.js +0 -512
  328. package/generators/tests/unit/lib/dbschema-kit/validator/enhanced-validate-integration.test.js +0 -390
  329. package/generators/tests/unit/lib/dbschema-kit/validator/naming-convention-validator.test.js +0 -306
  330. package/generators/tests/unit/lib/dbschema-kit/validator/schema-validator.test.js +0 -443
  331. package/generators/tests/unit/lib/dbschema-kit/validator/type-compatibility-validator.test.js +0 -440
  332. package/generators/tests/unit/lib/dbschema-kit/validator/validator-reporter.test.js +0 -172
  333. package/generators/tests/unit/lib/metadata-manager-dashboard.test.js +0 -256
  334. package/generators/tests/unit/lib/payload-validator-fieldpolicy.test.js +0 -240
  335. package/generators/tests/unit/lib/processor-validation-generator.test.js +0 -300
  336. package/generators/tests/unit/lib/sensitive-field-masker.test.js +0 -170
  337. package/generators/tests/unit/lib/sql-table-extractor.test.js +0 -119
  338. package/scripts/generate-integrity-manifest.js +0 -124
  339. package/scripts/snapshot-cli-contracts.js +0 -194
  340. package/scripts/verify-publish.js +0 -56
@@ -1,390 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * End-to-end integration tests for dbschema:validate CLI.
5
- *
6
- * Drives the CLI as a subprocess against on-disk fixture folders so the
7
- * full pipeline (load → cross-model → type-compat → circular → check-compat
8
- * → naming) is exercised, including the reporter (human + JSON) and
9
- * exit-code semantics.
10
- *
11
- * Each test writes its fixture into a temp directory via fs.mkdtempSync to
12
- * keep tests isolated. No shared state between tests.
13
- */
14
-
15
- const test = require('node:test');
16
- const assert = require('node:assert');
17
- const fs = require('node:fs');
18
- const os = require('node:os');
19
- const path = require('node:path');
20
- const { spawnSync } = require('node:child_process');
21
-
22
- const REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..', '..');
23
- const CLI_SCRIPT = path.join(REPO_ROOT, 'cli', 'dbschema-validate.js');
24
-
25
- function runCli(args, options = {}) {
26
- const result = spawnSync(process.execPath, [CLI_SCRIPT, ...args], {
27
- encoding: 'utf8',
28
- env: { ...process.env, NO_COLOR: '1' },
29
- ...options
30
- });
31
- return {
32
- stdout: result.stdout || '',
33
- stderr: result.stderr || '',
34
- code: result.status
35
- };
36
- }
37
-
38
- function mktmp(name) {
39
- return fs.mkdtempSync(path.join(os.tmpdir(), `dbsk-validate-int-${name}-`));
40
- }
41
-
42
- function writeSchema(dir, fileName, contents) {
43
- fs.writeFileSync(path.join(dir, fileName), contents, 'utf8');
44
- }
45
-
46
- // =====================================================
47
- // Clean schema
48
- // =====================================================
49
-
50
- test('integration: clean schema → exit 0, 0 issues di JSON', () => {
51
- const dir = mktmp('clean');
52
- try {
53
- writeSchema(dir, 'category.js', `
54
- 'use strict';
55
- module.exports = ({ defineModel }) => defineModel('category', {
56
- fields: { category_id: 'string:36 pk', name: 'string:100 notnull' }
57
- });
58
- `);
59
- writeSchema(dir, 'product.js', `
60
- 'use strict';
61
- module.exports = ({ defineModel }) => defineModel('product', {
62
- fields: {
63
- product_id: 'string:36 pk',
64
- category_id: 'string:36 notnull',
65
- price: 'decimal:15,2'
66
- },
67
- relations: {
68
- category: { type: 'belongsTo', target: 'category', localKey: 'category_id', references: 'category_id' }
69
- },
70
- checks: [{ field: 'price', gte: 0 }]
71
- });
72
- `);
73
-
74
- const result = runCli([dir, '--format', 'json']);
75
- assert.strictEqual(result.code, 0, `expected exit 0. stderr: ${result.stderr}`);
76
- const report = JSON.parse(result.stdout);
77
- assert.strictEqual(report.schemaVersion, '1.0');
78
- assert.strictEqual(report.summary.modelsLoaded, 2);
79
- assert.strictEqual(report.summary.errorCount, 0);
80
- assert.strictEqual(report.summary.warningCount, 0);
81
- assert.deepStrictEqual(report.issues, []);
82
- } finally {
83
- fs.rmSync(dir, { recursive: true, force: true });
84
- }
85
- });
86
-
87
- // =====================================================
88
- // Cross-model + type-compat in same run
89
- // =====================================================
90
-
91
- test('integration: schema dengan cross-model error dan FK type-mismatch → kedua kategori ter-collect', () => {
92
- const dir = mktmp('multi-cat');
93
- try {
94
- writeSchema(dir, 'category.js', `
95
- 'use strict';
96
- module.exports = ({ defineModel }) => defineModel('category', {
97
- fields: { category_id: 'string:36 pk' }
98
- });
99
- `);
100
- writeSchema(dir, 'product.js', `
101
- 'use strict';
102
- module.exports = ({ defineModel }) => defineModel('product', {
103
- fields: {
104
- product_id: 'string:36 pk',
105
- category_id: 'integer notnull', // FK type mismatch with target
106
- missing_ref: 'string:36'
107
- },
108
- relations: {
109
- category: { type: 'belongsTo', target: 'category', localKey: 'category_id', references: 'category_id' },
110
- missing: { type: 'belongsTo', target: 'nonexistent_table', localKey: 'missing_ref', references: 'id' }
111
- }
112
- });
113
- `);
114
-
115
- const result = runCli([dir, '--format', 'json']);
116
- assert.strictEqual(result.code, 1);
117
-
118
- const report = JSON.parse(result.stdout);
119
- const codes = report.issues.map((i) => i.code).sort();
120
- assert.ok(codes.includes('relation-unknown-target'), `missing relation-unknown-target. codes=${codes.join(',')}`);
121
- assert.ok(codes.includes('fk-type-mismatch'), `missing fk-type-mismatch. codes=${codes.join(',')}`);
122
- } finally {
123
- fs.rmSync(dir, { recursive: true, force: true });
124
- }
125
- });
126
-
127
- // =====================================================
128
- // Circular relation
129
- // =====================================================
130
-
131
- test('integration: mandatory cycle A ↔ B → circular-mandatory-relation error', () => {
132
- const dir = mktmp('cycle');
133
- try {
134
- writeSchema(dir, 'a.js', `
135
- 'use strict';
136
- module.exports = ({ defineModel }) => defineModel('a', {
137
- fields: { a_id: 'string:36 pk', b_id: 'string:36 notnull' },
138
- relations: { to_b: { type: 'belongsTo', target: 'b', localKey: 'b_id', references: 'b_id' } }
139
- });
140
- `);
141
- writeSchema(dir, 'b.js', `
142
- 'use strict';
143
- module.exports = ({ defineModel }) => defineModel('b', {
144
- fields: { b_id: 'string:36 pk', a_id: 'string:36 notnull' },
145
- relations: { to_a: { type: 'belongsTo', target: 'a', localKey: 'a_id', references: 'a_id' } }
146
- });
147
- `);
148
-
149
- const result = runCli([dir, '--format', 'json']);
150
- assert.strictEqual(result.code, 1);
151
-
152
- const report = JSON.parse(result.stdout);
153
- const cycle = report.issues.find((i) => i.code === 'circular-mandatory-relation');
154
- assert.ok(cycle, 'expected circular-mandatory-relation issue');
155
- assert.match(cycle.message, /a → b → a/);
156
- } finally {
157
- fs.rmSync(dir, { recursive: true, force: true });
158
- }
159
- });
160
-
161
- // =====================================================
162
- // Check constraint compatibility
163
- // =====================================================
164
-
165
- test('integration: check constraint dengan op-type incompat → check-op-incompatible-with-type error', () => {
166
- const dir = mktmp('check');
167
- try {
168
- writeSchema(dir, 'user.js', `
169
- 'use strict';
170
- module.exports = ({ defineModel }) => defineModel('user', {
171
- fields: { user_id: 'string:36 pk', is_active: 'boolean' },
172
- checks: [{ field: 'is_active', gt: 0 }]
173
- });
174
- `);
175
-
176
- const result = runCli([dir, '--format', 'json']);
177
- assert.strictEqual(result.code, 1);
178
-
179
- const report = JSON.parse(result.stdout);
180
- const issue = report.issues.find((i) => i.code === 'check-op-incompatible-with-type');
181
- assert.ok(issue, 'expected check-op-incompatible-with-type issue');
182
- assert.strictEqual(issue.field, 'is_active');
183
- } finally {
184
- fs.rmSync(dir, { recursive: true, force: true });
185
- }
186
- });
187
-
188
- // =====================================================
189
- // Naming convention (opt-in via --dialect)
190
- // =====================================================
191
-
192
- test('integration: schema "order" tanpa --dialect → 0 warning naming', () => {
193
- const dir = mktmp('naming-default');
194
- try {
195
- writeSchema(dir, 'order.js', `
196
- 'use strict';
197
- module.exports = ({ defineModel }) => defineModel('order', {
198
- fields: { order_id: 'string:36 pk', total: 'decimal:15,2' }
199
- });
200
- `);
201
-
202
- const result = runCli([dir, '--format', 'json', '--strict']);
203
- assert.strictEqual(result.code, 0);
204
-
205
- const report = JSON.parse(result.stdout);
206
- const namingIssues = report.issues.filter((i) =>
207
- i.code.startsWith('reserved-keyword') || i.code === 'identifier-too-long'
208
- );
209
- assert.strictEqual(namingIssues.length, 0, 'naming check must stay off without --dialect');
210
- } finally {
211
- fs.rmSync(dir, { recursive: true, force: true });
212
- }
213
- });
214
-
215
- test('integration: schema "order" dengan --dialect postgres --strict → reserved-keyword-table warning', () => {
216
- const dir = mktmp('naming-pg');
217
- try {
218
- writeSchema(dir, 'order.js', `
219
- 'use strict';
220
- module.exports = ({ defineModel }) => defineModel('order', {
221
- fields: { order_id: 'string:36 pk', total: 'decimal:15,2' }
222
- });
223
- `);
224
-
225
- const result = runCli([dir, '--format', 'json', '--dialect', 'postgres', '--strict']);
226
- assert.strictEqual(result.code, 0, 'warning alone must not exit 1');
227
-
228
- const report = JSON.parse(result.stdout);
229
- const warning = report.issues.find((i) => i.code === 'reserved-keyword-table');
230
- assert.ok(warning, 'expected reserved-keyword-table warning');
231
- assert.strictEqual(warning.severity, 'warning');
232
- assert.strictEqual(warning.table, 'order');
233
- } finally {
234
- fs.rmSync(dir, { recursive: true, force: true });
235
- }
236
- });
237
-
238
- // =====================================================
239
- // Strict / strict-warnings exit-code semantics
240
- // =====================================================
241
-
242
- test('integration: hanya warning + default → exit 0 (warning di-suppress)', () => {
243
- const dir = mktmp('warn-default');
244
- try {
245
- // FK length mismatch → warning
246
- writeSchema(dir, 'cat.js', `
247
- 'use strict';
248
- module.exports = ({ defineModel }) => defineModel('cat', {
249
- fields: { cat_id: 'string:50 pk' }
250
- });
251
- `);
252
- writeSchema(dir, 'prod.js', `
253
- 'use strict';
254
- module.exports = ({ defineModel }) => defineModel('prod', {
255
- fields: { prod_id: 'string:36 pk', cat_id: 'string:36 notnull' },
256
- relations: { cat: { type: 'belongsTo', target: 'cat', localKey: 'cat_id', references: 'cat_id' } }
257
- });
258
- `);
259
-
260
- const result = runCli([dir]);
261
- assert.strictEqual(result.code, 0, `expected exit 0. stderr: ${result.stderr}`);
262
- } finally {
263
- fs.rmSync(dir, { recursive: true, force: true });
264
- }
265
- });
266
-
267
- test('integration: hanya warning + --strict-warnings → exit 1', () => {
268
- const dir = mktmp('warn-strict');
269
- try {
270
- writeSchema(dir, 'cat.js', `
271
- 'use strict';
272
- module.exports = ({ defineModel }) => defineModel('cat', {
273
- fields: { cat_id: 'string:50 pk' }
274
- });
275
- `);
276
- writeSchema(dir, 'prod.js', `
277
- 'use strict';
278
- module.exports = ({ defineModel }) => defineModel('prod', {
279
- fields: { prod_id: 'string:36 pk', cat_id: 'string:36 notnull' },
280
- relations: { cat: { type: 'belongsTo', target: 'cat', localKey: 'cat_id', references: 'cat_id' } }
281
- });
282
- `);
283
-
284
- const result = runCli([dir, '--strict-warnings']);
285
- assert.strictEqual(result.code, 1, `--strict-warnings must elevate warning to exit 1`);
286
- } finally {
287
- fs.rmSync(dir, { recursive: true, force: true });
288
- }
289
- });
290
-
291
- // =====================================================
292
- // JSON contract — all 4 validator categories in one report
293
- // =====================================================
294
-
295
- test('integration: schema dengan violation di 4 kategori → semua ter-emit di JSON report', () => {
296
- const dir = mktmp('all-cats');
297
- try {
298
- writeSchema(dir, 'a.js', `
299
- 'use strict';
300
- // Mandatory self-reference → circular-mandatory-relation
301
- module.exports = ({ defineModel }) => defineModel('a_self', {
302
- fields: { a_id: 'string:36 pk', parent_id: 'string:36 notnull' },
303
- relations: { parent: { type: 'belongsTo', target: 'a_self', localKey: 'parent_id', references: 'a_id' } }
304
- });
305
- `);
306
- writeSchema(dir, 'b.js', `
307
- 'use strict';
308
- // Unknown FK target → relation-unknown-target
309
- module.exports = ({ defineModel }) => defineModel('b_orphan', {
310
- fields: { b_id: 'string:36 pk', x_id: 'string:36 notnull' },
311
- relations: { x: { type: 'belongsTo', target: 'nonexistent', localKey: 'x_id', references: 'id' } }
312
- });
313
- `);
314
- writeSchema(dir, 'c.js', `
315
- 'use strict';
316
- // FK type mismatch with d_master + check-op incompat
317
- module.exports = ({ defineModel }) => defineModel('c_data', {
318
- fields: {
319
- c_id: 'string:36 pk',
320
- d_id: 'integer notnull', // mismatch: target is string:36
321
- flag: 'boolean'
322
- },
323
- relations: { d: { type: 'belongsTo', target: 'd_master', localKey: 'd_id', references: 'd_id' } },
324
- checks: [{ field: 'flag', gt: 0 }]
325
- });
326
- `);
327
- writeSchema(dir, 'd.js', `
328
- 'use strict';
329
- module.exports = ({ defineModel }) => defineModel('d_master', {
330
- fields: { d_id: 'string:36 pk' }
331
- });
332
- `);
333
-
334
- const result = runCli([dir, '--format', 'json']);
335
- assert.strictEqual(result.code, 1);
336
-
337
- const report = JSON.parse(result.stdout);
338
- const codes = new Set(report.issues.map((i) => i.code));
339
-
340
- assert.ok(codes.has('relation-unknown-target'), 'expected cross-model rule');
341
- assert.ok(codes.has('fk-type-mismatch'), 'expected type-compat rule');
342
- assert.ok(codes.has('circular-mandatory-relation'), 'expected circular rule');
343
- assert.ok(codes.has('check-op-incompatible-with-type'), 'expected check-compat rule');
344
-
345
- // JSON contract sanity check
346
- for (const issue of report.issues) {
347
- assert.ok(['error', 'warning'].includes(issue.severity));
348
- assert.strictEqual(typeof issue.code, 'string');
349
- assert.strictEqual(typeof issue.message, 'string');
350
- }
351
- } finally {
352
- fs.rmSync(dir, { recursive: true, force: true });
353
- }
354
- });
355
-
356
- // =====================================================
357
- // Usage errors (exit 2)
358
- // =====================================================
359
-
360
- test('integration: --dialect invalid → exit 2 dengan usage error', () => {
361
- const dir = mktmp('usage-dialect');
362
- try {
363
- writeSchema(dir, 'a.js', `
364
- 'use strict';
365
- module.exports = ({ defineModel }) => defineModel('a', { fields: { a_id: 'string:36 pk' } });
366
- `);
367
-
368
- const result = runCli([dir, '--dialect', 'mongodb']);
369
- assert.strictEqual(result.code, 2);
370
- assert.match(result.stderr, /Invalid dialect 'mongodb'/);
371
- } finally {
372
- fs.rmSync(dir, { recursive: true, force: true });
373
- }
374
- });
375
-
376
- test('integration: --format invalid → exit 2 dengan usage error', () => {
377
- const dir = mktmp('usage-format');
378
- try {
379
- writeSchema(dir, 'a.js', `
380
- 'use strict';
381
- module.exports = ({ defineModel }) => defineModel('a', { fields: { a_id: 'string:36 pk' } });
382
- `);
383
-
384
- const result = runCli([dir, '--format', 'xml']);
385
- assert.strictEqual(result.code, 2);
386
- assert.match(result.stderr, /Invalid format 'xml'/);
387
- } finally {
388
- fs.rmSync(dir, { recursive: true, force: true });
389
- }
390
- });
@@ -1,306 +0,0 @@
1
- 'use strict';
2
-
3
- const test = require('node:test');
4
- const assert = require('node:assert');
5
-
6
- const { validateNamingConventions } = require('../../../../../lib/dbschema-kit/validator/naming-convention-validator');
7
-
8
- function makeModel(tableName, opts = {}) {
9
- const schemaName = opts.schemaName || null;
10
- const model = {
11
- schemaName,
12
- tableName,
13
- qualifiedName: schemaName ? `${schemaName}.${tableName}` : tableName,
14
- fields: opts.fields || {},
15
- primaryKey: opts.primaryKey || [],
16
- indexes: [],
17
- uniques: [],
18
- relations: opts.relations || {},
19
- checks: opts.checks || [],
20
- _meta: {
21
- hasSinglePkShorthand: false,
22
- hasCompositePrimaryKey: false,
23
- autoGeneratedRelations: []
24
- }
25
- };
26
- if (opts.filePath) {
27
- Object.defineProperty(model, '_filePath', {
28
- value: opts.filePath,
29
- enumerable: false,
30
- writable: false,
31
- configurable: false
32
- });
33
- }
34
- return model;
35
- }
36
-
37
- function mapOf(model) {
38
- const map = new Map();
39
- map.set(model.qualifiedName, model);
40
- return map;
41
- }
42
-
43
- // =====================================================
44
- // No-op scenarios
45
- // =====================================================
46
-
47
- test('naming: no dialect → 0 issues', () => {
48
- const models = mapOf(makeModel('order', {
49
- fields: { order_id: { type: 'uuid', pk: true, notnull: true } }
50
- }));
51
- assert.deepStrictEqual(validateNamingConventions(models, null), []);
52
- assert.deepStrictEqual(validateNamingConventions(models, undefined), []);
53
- assert.deepStrictEqual(validateNamingConventions(models, ''), []);
54
- });
55
-
56
- test('naming: unsupported dialect → 0 issues', () => {
57
- const models = mapOf(makeModel('order', {
58
- fields: { order_id: { type: 'uuid', pk: true, notnull: true } }
59
- }));
60
- assert.deepStrictEqual(validateNamingConventions(models, 'mongodb'), []);
61
- });
62
-
63
- test('naming: empty Map → 0 issues', () => {
64
- assert.deepStrictEqual(validateNamingConventions(new Map(), 'postgres'), []);
65
- });
66
-
67
- test('naming: clean schema (no reserved, normal length) → 0 issues', () => {
68
- const models = mapOf(makeModel('product', {
69
- fields: {
70
- product_id: { type: 'uuid', pk: true, notnull: true },
71
- product_name: { type: 'string', length: 100 }
72
- }
73
- }));
74
- assert.deepStrictEqual(validateNamingConventions(models, 'postgres'), []);
75
- });
76
-
77
- // =====================================================
78
- // Reserved keyword — table
79
- // =====================================================
80
-
81
- test('naming: postgres table named "order" → reserved-keyword-table warning', () => {
82
- const models = mapOf(makeModel('order', {
83
- fields: { order_id: { type: 'uuid', pk: true, notnull: true } }
84
- }));
85
- const issues = validateNamingConventions(models, 'postgres');
86
- assert.strictEqual(issues.length, 1);
87
- assert.strictEqual(issues[0].severity, 'warning');
88
- assert.strictEqual(issues[0].code, 'reserved-keyword-table');
89
- assert.match(issues[0].message, /Table name 'order' is a reserved keyword in postgres/);
90
- });
91
-
92
- test('naming: mysql table named "key" → reserved-keyword-table warning', () => {
93
- const models = mapOf(makeModel('key', {
94
- fields: { key_id: { type: 'uuid', pk: true, notnull: true } }
95
- }));
96
- const issues = validateNamingConventions(models, 'mysql');
97
- assert.strictEqual(issues.length, 1);
98
- assert.strictEqual(issues[0].code, 'reserved-keyword-table');
99
- });
100
-
101
- test('naming: oracle table named "user" → reserved-keyword-table warning', () => {
102
- const models = mapOf(makeModel('user', {
103
- fields: { user_id: { type: 'uuid', pk: true, notnull: true } }
104
- }));
105
- const issues = validateNamingConventions(models, 'oracle');
106
- assert.strictEqual(issues.length, 1);
107
- assert.strictEqual(issues[0].code, 'reserved-keyword-table');
108
- });
109
-
110
- test('naming: sqlite table named "transaction" → reserved-keyword-table warning', () => {
111
- const models = mapOf(makeModel('transaction', {
112
- fields: { transaction_id: { type: 'uuid', pk: true, notnull: true } }
113
- }));
114
- const issues = validateNamingConventions(models, 'sqlite');
115
- assert.strictEqual(issues.length, 1);
116
- assert.strictEqual(issues[0].code, 'reserved-keyword-table');
117
- });
118
-
119
- test('naming: case-insensitive comparison — table "ORDER" still flagged', () => {
120
- // dbschema-kit normally enforces snake_case at single-model validation, so
121
- // "ORDER" would never make it past defineModel. We still test the
122
- // case-insensitive comparison here to guarantee the check is robust if
123
- // upstream rules ever relax.
124
- const models = mapOf(makeModel('ORDER', {
125
- fields: { order_id: { type: 'uuid', pk: true, notnull: true } }
126
- }));
127
- const issues = validateNamingConventions(models, 'postgres');
128
- assert.strictEqual(issues.length, 1);
129
- assert.strictEqual(issues[0].code, 'reserved-keyword-table');
130
- });
131
-
132
- // =====================================================
133
- // Reserved keyword — field
134
- // =====================================================
135
-
136
- test('naming: mysql field named "key" → reserved-keyword-field warning', () => {
137
- const models = mapOf(makeModel('lookup', {
138
- fields: {
139
- lookup_id: { type: 'uuid', pk: true, notnull: true },
140
- key: { type: 'string', length: 50 }
141
- }
142
- }));
143
- const issues = validateNamingConventions(models, 'mysql');
144
- assert.strictEqual(issues.length, 1);
145
- assert.strictEqual(issues[0].severity, 'warning');
146
- assert.strictEqual(issues[0].code, 'reserved-keyword-field');
147
- assert.strictEqual(issues[0].field, 'key');
148
- assert.match(issues[0].message, /reserved keyword in mysql/);
149
- });
150
-
151
- test('naming: postgres field named "user" → reserved-keyword-field warning', () => {
152
- const models = mapOf(makeModel('audit_log', {
153
- fields: {
154
- audit_log_id: { type: 'uuid', pk: true, notnull: true },
155
- user: { type: 'string', length: 50 }
156
- }
157
- }));
158
- const issues = validateNamingConventions(models, 'postgres');
159
- assert.strictEqual(issues.length, 1);
160
- assert.strictEqual(issues[0].code, 'reserved-keyword-field');
161
- assert.strictEqual(issues[0].field, 'user');
162
- });
163
-
164
- test('naming: oracle field named "level" → reserved-keyword-field warning', () => {
165
- const models = mapOf(makeModel('priority', {
166
- fields: {
167
- priority_id: { type: 'uuid', pk: true, notnull: true },
168
- level: { type: 'integer' }
169
- }
170
- }));
171
- const issues = validateNamingConventions(models, 'oracle');
172
- assert.strictEqual(issues.length, 1);
173
- assert.strictEqual(issues[0].code, 'reserved-keyword-field');
174
- });
175
-
176
- // =====================================================
177
- // Identifier length limit
178
- // =====================================================
179
-
180
- test('naming: oracle table name 130 chars exceeds 128 limit → identifier-too-long warning', () => {
181
- const longName = 't'.repeat(130);
182
- const models = mapOf(makeModel(longName, {
183
- fields: { id: { type: 'uuid', pk: true, notnull: true } }
184
- }));
185
- const issues = validateNamingConventions(models, 'oracle');
186
- // Both an identifier-too-long for the table itself
187
- assert.ok(issues.some((i) => i.code === 'identifier-too-long' && !i.field));
188
- const tableLengthIssue = issues.find((i) => i.code === 'identifier-too-long' && !i.field);
189
- assert.match(tableLengthIssue.message, /length 130, exceeds oracle limit 128/);
190
- });
191
-
192
- test('naming: postgres table name 65 chars exceeds 63 limit → identifier-too-long warning', () => {
193
- const longName = 't'.repeat(65);
194
- const models = mapOf(makeModel(longName, {
195
- fields: { id: { type: 'uuid', pk: true, notnull: true } }
196
- }));
197
- const issues = validateNamingConventions(models, 'postgres');
198
- const tooLong = issues.find((i) => i.code === 'identifier-too-long' && !i.field);
199
- assert.ok(tooLong, 'expected identifier-too-long warning for table');
200
- assert.match(tooLong.message, /length 65, exceeds postgres limit 63/);
201
- });
202
-
203
- test('naming: mysql field name 70 chars exceeds 64 limit → identifier-too-long warning', () => {
204
- const longField = 'f'.repeat(70);
205
- const models = mapOf(makeModel('payment', {
206
- fields: {
207
- payment_id: { type: 'uuid', pk: true, notnull: true },
208
- [longField]: { type: 'string', length: 100 }
209
- }
210
- }));
211
- const issues = validateNamingConventions(models, 'mysql');
212
- const tooLong = issues.find((i) => i.code === 'identifier-too-long' && i.field === longField);
213
- assert.ok(tooLong, 'expected identifier-too-long warning for field');
214
- assert.match(tooLong.message, /length 70, exceeds mysql limit 64/);
215
- });
216
-
217
- test('naming: sqlite table 100 chars → identifier-too-long warning at sqlite limit', () => {
218
- // SQLite is technically permissive but lib/dbschema-kit/dialect/sqlite.js
219
- // sets maxIdentifierLength: 63 for cross-dialect portability.
220
- const longName = 't'.repeat(100);
221
- const models = mapOf(makeModel(longName, {
222
- fields: { id: { type: 'uuid', pk: true, notnull: true } }
223
- }));
224
- const issues = validateNamingConventions(models, 'sqlite');
225
- assert.ok(issues.some((i) => i.code === 'identifier-too-long' && !i.field));
226
- });
227
-
228
- // =====================================================
229
- // Multiple issues per model
230
- // =====================================================
231
-
232
- test('naming: reserved table + reserved field → 2 warnings', () => {
233
- const models = mapOf(makeModel('order', {
234
- fields: {
235
- order_id: { type: 'uuid', pk: true, notnull: true },
236
- group: { type: 'string', length: 50 }
237
- }
238
- }));
239
- const issues = validateNamingConventions(models, 'postgres');
240
- assert.strictEqual(issues.length, 2);
241
- const codes = issues.map((i) => i.code).sort();
242
- assert.deepStrictEqual(codes, ['reserved-keyword-field', 'reserved-keyword-table']);
243
- });
244
-
245
- test('naming: reserved table + table also too long → 2 warnings (table)', () => {
246
- // Combine a reserved token in a too-long identifier
247
- const longName = 'order' + 'x'.repeat(60); // 65 chars, "order" prefix isn't a full-token match
248
- const models = mapOf(makeModel(longName, {
249
- fields: { id: { type: 'uuid', pk: true, notnull: true } }
250
- }));
251
- // Only identifier-too-long: 'orderxxx...' is not a reserved keyword
252
- // (case-insensitive full-token match, not substring).
253
- const issues = validateNamingConventions(models, 'postgres');
254
- assert.strictEqual(issues.length, 1);
255
- assert.strictEqual(issues[0].code, 'identifier-too-long');
256
- });
257
-
258
- // =====================================================
259
- // Decoration
260
- // =====================================================
261
-
262
- test('naming: Issue di-decorate dengan file path bila _filePath ada di model', () => {
263
- const models = mapOf(makeModel('order', {
264
- filePath: '/abs/schema/order.js',
265
- fields: { order_id: { type: 'uuid', pk: true, notnull: true } }
266
- }));
267
- const issues = validateNamingConventions(models, 'postgres');
268
- assert.strictEqual(issues.length, 1);
269
- assert.strictEqual(issues[0].file, '/abs/schema/order.js');
270
- assert.strictEqual(issues[0].table, 'order');
271
- });
272
-
273
- // =====================================================
274
- // Multi-table
275
- // =====================================================
276
-
277
- test('naming: 2 tabel masing-masing punya reserved table → 2 warnings', () => {
278
- const models = new Map();
279
- models.set('order', makeModel('order', {
280
- fields: { order_id: { type: 'uuid', pk: true, notnull: true } }
281
- }));
282
- models.set('group', makeModel('group', {
283
- fields: { group_id: { type: 'uuid', pk: true, notnull: true } }
284
- }));
285
- const issues = validateNamingConventions(models, 'postgres');
286
- assert.strictEqual(issues.length, 2);
287
- for (const issue of issues) {
288
- assert.strictEqual(issue.code, 'reserved-keyword-table');
289
- }
290
- });
291
-
292
- // =====================================================
293
- // Non-reserved common identifiers
294
- // =====================================================
295
-
296
- test('naming: common safe identifiers (id, name, created_at, updated_at) not flagged in postgres', () => {
297
- const models = mapOf(makeModel('product', {
298
- fields: {
299
- id: { type: 'uuid', pk: true, notnull: true },
300
- name: { type: 'string', length: 100 },
301
- created_at: { type: 'timestamp' },
302
- updated_at: { type: 'timestamp' }
303
- }
304
- }));
305
- assert.deepStrictEqual(validateNamingConventions(models, 'postgres'), []);
306
- });