@restforgejs/platform 4.2.8 → 4.3.2
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.
- package/SECURITY.md +83 -4
- package/bin/sdf-tools.exe +0 -0
- package/build-info.json +2 -2
- package/cli/consumer-deploy.js +1 -1
- package/cli/consumer.js +1 -1
- package/generators/cli/dashboard/create.js +4 -1
- package/generators/cli/endpoint/create.js +1 -1
- package/generators/cli/key/generate.js +2 -1
- package/generators/cli/key/revoke.js +2 -1
- package/generators/cli/payload/diff.js +3 -2
- package/generators/cli/payload/generate.js +3 -2
- package/generators/cli/payload/sync.js +3 -2
- package/generators/cli/payload/validate.js +3 -2
- package/generators/cli/processor/create.js +14 -3
- package/generators/cli/project/delete.js +2 -1
- package/generators/cli/query/validate.js +3 -2
- package/generators/cli/schema/apply.js +3 -2
- package/generators/cli/schema/describe.js +3 -2
- package/generators/cli/schema/diff.js +3 -2
- package/generators/cli/schema/introspect.js +3 -2
- package/generators/cli/schema/list.js +3 -2
- package/generators/cli/schema/migrate.js +3 -2
- package/generators/lib/migration/audit-table-runner.js +213 -215
- package/generators/lib/payload/payload-runner.js +1 -1
- package/generators/lib/templates/dashboard-catalog.js +1 -437
- package/generators/lib/templates/db-connection-env.js +1 -212
- package/generators/lib/templates/dbschema-catalog.js +1 -489
- package/generators/lib/templates/field-validation-catalog.js +1 -531
- package/generators/lib/templates/mysql-template.js +1 -3863
- package/generators/lib/templates/oracle-template.js +1 -3915
- package/generators/lib/templates/postgres-template.js +1 -5838
- package/generators/lib/templates/query-declarative-catalog.js +1 -199
- package/generators/lib/templates/sqlite-template.js +1 -3440
- package/generators/lib/utils/env-manager.js +6 -0
- package/generators/lib/utils/path-validator.js +71 -0
- package/generators/lib/validators/payload-validator.js +1 -2
- package/integrity-manifest.json +28 -10
- package/package.json +11 -3
- package/scripts/verify-integrity.js +1 -1
- package/server.js +1 -1
- package/src/components/handlers/adjust_handler.js +1 -1
- package/src/components/handlers/audit_handler.js +1 -1
- package/src/components/handlers/delete_handler.js +1 -1
- package/src/components/handlers/export_handler.js +1 -1
- package/src/components/handlers/import_handler.js +1 -1
- package/src/components/handlers/insert_handler.js +1 -1
- package/src/components/handlers/update_handler.js +1 -1
- package/src/components/handlers/upload_handler.js +1 -1
- package/src/components/handlers/workflow_handler.js +1 -1
- package/src/components/integrations/webhook.js +1 -1
- package/src/consumers/baseConsumer.js +1 -1
- package/src/consumers/declarativeMapper.js +1 -1
- package/src/consumers/handlers/apiHandler.js +1 -1
- package/src/consumers/handlers/consoleHandler.js +1 -1
- package/src/consumers/handlers/databaseHandler.js +1 -1
- package/src/consumers/handlers/index.js +1 -1
- package/src/consumers/handlers/kafkaHandler.js +1 -1
- package/src/consumers/index.js +1 -1
- package/src/consumers/messageTransformer.js +1 -1
- package/src/consumers/validator.js +1 -1
- package/src/core/db/dialect/base-dialect.js +1 -1
- package/src/core/db/dialect/index.js +1 -1
- package/src/core/db/dialect/mysql-dialect.js +1 -1
- package/src/core/db/dialect/oracle-dialect.js +1 -1
- package/src/core/db/dialect/postgres-dialect.js +1 -1
- package/src/core/db/dialect/sqlite-dialect.js +1 -1
- package/src/core/db/flatten-helper.js +1 -1
- package/src/core/db/query-builder-error.js +1 -1
- package/src/core/db/query-builder.js +1 -1
- package/src/core/db/relation-helper.js +1 -1
- package/src/core/handlers/delete_handler.js +1 -1
- package/src/core/handlers/insert_handler.js +1 -1
- package/src/core/handlers/update_handler.js +1 -1
- package/src/core/models/base-model.js +1 -1
- package/src/core/utils/cache-manager.js +1 -1
- package/src/core/utils/component-engine.js +1 -1
- package/src/core/utils/context-builder.js +1 -1
- package/src/core/utils/datetime-formatter.js +1 -1
- package/src/core/utils/datetime-parser.js +1 -1
- package/src/core/utils/db.js +1 -1
- package/src/core/utils/logger.js +1 -1
- package/src/core/utils/payload-loader.js +1 -1
- package/src/core/utils/security-checks.js +1 -1
- package/src/middleware/body-options.js +1 -1
- package/src/middleware/cors.js +1 -1
- package/src/middleware/idempotency.js +1 -1
- package/src/middleware/rate-limiter.js +1 -1
- package/src/middleware/request-logger.js +1 -1
- package/src/middleware/security-headers.js +1 -1
- package/src/models/base-model-mysql.js +1 -1
- package/src/models/base-model-oracle.js +1 -1
- package/src/models/base-model-sqlite.js +1 -1
- package/src/models/base-model.js +1 -1
- package/src/pro/caching/redis-client.js +1 -1
- package/src/pro/caching/redis-helper.js +1 -1
- package/src/pro/consumers/baseConsumer.js +1 -1
- package/src/pro/consumers/declarativeMapper.js +1 -1
- package/src/pro/consumers/handlers/apiHandler.js +1 -1
- package/src/pro/consumers/handlers/consoleHandler.js +1 -1
- package/src/pro/consumers/handlers/databaseHandler.js +1 -1
- package/src/pro/consumers/handlers/index.js +1 -1
- package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
- package/src/pro/consumers/index.js +1 -1
- package/src/pro/consumers/messageTransformer.js +1 -1
- package/src/pro/consumers/validator.js +1 -1
- package/src/pro/database/base-model-mysql.js +1 -1
- package/src/pro/database/base-model-oracle.js +1 -1
- package/src/pro/database/base-model-sqlite.js +1 -1
- package/src/pro/database/db-mysql.js +1 -1
- package/src/pro/database/db-oracle.js +1 -1
- package/src/pro/database/db-sqlite.js +1 -1
- package/src/pro/excel/excel-generator.js +1 -1
- package/src/pro/excel/excel-parser.js +1 -1
- package/src/pro/excel/export-service.js +1 -1
- package/src/pro/excel/export_handler.js +1 -1
- package/src/pro/excel/import-service.js +1 -1
- package/src/pro/excel/import-validator.js +1 -1
- package/src/pro/excel/import_handler.js +1 -1
- package/src/pro/excel/upsert-builder.js +1 -1
- package/src/pro/idgen/idgen-routes.js +1 -1
- package/src/pro/integrations/lookup-resolver.js +1 -1
- package/src/pro/integrations/upload-handler-v2.js +1 -1
- package/src/pro/integrations/upload-handler.js +1 -1
- package/src/pro/integrations/webhook.js +1 -1
- package/src/pro/locking/lock-routes.js +1 -1
- package/src/pro/locking/resource-lock-manager.js +1 -1
- package/src/pro/messaging/kafkaConsumerService.js +1 -1
- package/src/pro/messaging/kafkaService.js +1 -1
- package/src/pro/messaging/messagehubService.js +1 -1
- package/src/pro/messaging/rabbitmqService.js +1 -1
- package/src/pro/scheduler/job-manager.js +1 -1
- package/src/pro/scheduler/job-routes.js +1 -1
- package/src/pro/scheduler/job-validator.js +1 -1
- package/src/pro/storage/base-storage-provider.js +1 -1
- package/src/pro/storage/file-metadata-helper.js +1 -1
- package/src/pro/storage/index.js +1 -1
- package/src/pro/storage/local-storage-provider.js +1 -1
- package/src/pro/storage/s3-storage-provider.js +1 -1
- package/src/pro/storage/upload-cleanup-job.js +1 -1
- package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
- package/src/pro/storage/upload-pending-tracker.js +1 -1
- package/src/pro/websocket/broadcast-helper.js +1 -1
- package/src/pro/websocket/index.js +1 -1
- package/src/pro/websocket/livesync-server.js +1 -1
- package/src/pro/websocket/ws-broadcaster.js +1 -1
- package/src/services/export-service.js +1 -1
- package/src/services/import-service.js +1 -1
- package/src/services/kafkaConsumerService.js +1 -1
- package/src/services/kafkaService.js +1 -1
- package/src/services/messagehubService.js +1 -1
- package/src/services/rabbitmqService.js +1 -1
- package/src/utils/cache-invalidation-registry.js +1 -1
- package/src/utils/cache-manager.js +1 -1
- package/src/utils/component-engine.js +1 -1
- package/src/utils/config-extractor.js +1 -1
- package/src/utils/consumerLogger.js +1 -1
- package/src/utils/context-builder.js +1 -1
- package/src/utils/dashboard-helpers.js +1 -1
- package/src/utils/dateHelper.js +1 -1
- package/src/utils/datetime-formatter.js +1 -1
- package/src/utils/datetime-parser.js +1 -1
- package/src/utils/db-bootstrap.js +1 -1
- package/src/utils/db-mysql.js +1 -1
- package/src/utils/db-oracle.js +1 -1
- package/src/utils/db-sqlite.js +1 -1
- package/src/utils/db.js +1 -1
- package/src/utils/demo-generator.js +1 -1
- package/src/utils/excel-generator.js +1 -1
- package/src/utils/excel-parser.js +1 -1
- package/src/utils/file-watcher.js +1 -1
- package/src/utils/id-generator.js +1 -1
- package/src/utils/idempotency-manager.js +1 -1
- package/src/utils/import-validator.js +1 -1
- package/src/utils/license-client.js +1 -1
- package/src/utils/lock-manager.js +1 -1
- package/src/utils/logger.js +1 -1
- package/src/utils/lookup-resolver.js +1 -1
- package/src/utils/payload-loader.js +1 -1
- package/src/utils/processor-response.js +1 -1
- package/src/utils/rabbitmq.js +1 -1
- package/src/utils/redis-client.js +1 -1
- package/src/utils/redis-helper.js +1 -1
- package/src/utils/request-scope.js +1 -1
- package/src/utils/security-checks.js +1 -1
- package/src/utils/service-resolver.js +1 -1
- package/src/utils/shutdown-coordinator.js +1 -1
- package/src/utils/trusted-keys.js +1 -1
- package/src/utils/upload-handler.js +1 -1
- package/src/utils/upsert-builder.js +1 -1
- package/src/utils/workflow-hook-executor.js +1 -1
- package/generators/metadata/global.json +0 -58
- package/generators/metadata/test-mysql-workbench.json +0 -118
- package/generators/metadata/test-mysql.json +0 -56
- package/generators/metadata/test-oracle-workbench.json +0 -118
- package/generators/metadata/test-oracle.json +0 -56
- package/generators/metadata/test-pg-workbench.json +0 -118
- package/generators/metadata/test-pg.json +0 -56
- package/generators/scripts/obfuscate-source.js +0 -356
- package/generators/scripts/validate-catalog.js +0 -430
- package/generators/scripts/validate-dbschema-catalog.js +0 -708
- package/generators/tests/baseline/mysql/mini_inventory_item/src/models/mini-inventory/item.js +0 -944
- package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
- package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory.js +0 -336
- package/generators/tests/baseline/oracle/mini_inventory_item/src/models/mini-inventory/item.js +0 -1002
- package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
- package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory.js +0 -336
- package/generators/tests/baseline/postgres/mini_inventory_item/src/models/mini-inventory/item.js +0 -1333
- package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory/item.js +0 -1173
- package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory.js +0 -496
- package/generators/tests/fixtures/payloads/custom-sensitive.json +0 -27
- package/generators/tests/fixtures/payloads/dynamic-search-optout.json +0 -23
- package/generators/tests/fixtures/payloads/login-with-password.json +0 -22
- package/generators/tests/fixtures/payloads/order-process.json +0 -52
- package/generators/tests/fixtures/payloads/with-inline-sql.json +0 -26
- package/generators/tests/integration-tahap4b/README.md +0 -145
- package/generators/tests/integration-tahap4b/run-concurrent.js +0 -77
- package/generators/tests/integration-tahap4b/seed.sql +0 -53
- package/generators/tests/integration-tahap4b/verify.sql +0 -110
- package/generators/tests/unit/cli/create-dashboard.test.js +0 -505
- package/generators/tests/unit/cli/create-processor.test.js +0 -319
- package/generators/tests/unit/cli/dispatch-dashboard.test.js +0 -149
- package/generators/tests/unit/lib/dashboard-generator.test.js +0 -895
- package/generators/tests/unit/lib/dashboard-validator.test.js +0 -354
- package/generators/tests/unit/lib/dbschema-kit/apply-executor.test.js +0 -437
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-introspect.test.js +0 -393
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-generate-ddl.test.js +0 -104
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-init.test.js +0 -119
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-list.test.js +0 -48
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-migrate.test.js +0 -175
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-validate.test.js +0 -102
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-models.test.js +0 -43
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/all-schemas-listing.js +0 -84
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/connection-error.js +0 -13
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/empty.js +0 -12
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/multi-schema.js +0 -124
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/single-schema-inventory.js +0 -64
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/two-tables.js +0 -66
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/connection-error.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/partial.js +0 -29
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/rollback.js +0 -26
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/success.js +0 -43
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/audit/events.js +0 -18
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/users.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/connection.test.js +0 -112
- package/generators/tests/unit/lib/dbschema-kit/ddl-generator.test.js +0 -205
- package/generators/tests/unit/lib/dbschema-kit/define-model.test.js +0 -56
- package/generators/tests/unit/lib/dbschema-kit/dialect/index.test.js +0 -46
- package/generators/tests/unit/lib/dbschema-kit/dialect/mysql.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/dialect/oracle.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/dialect/postgres.test.js +0 -131
- package/generators/tests/unit/lib/dbschema-kit/dialect/sqlite.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/driver-loader.test.js +0 -93
- package/generators/tests/unit/lib/dbschema-kit/emitters/create-index.test.js +0 -173
- package/generators/tests/unit/lib/dbschema-kit/emitters/create-table.test.js +0 -376
- package/generators/tests/unit/lib/dbschema-kit/emitters/drop-table.test.js +0 -78
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/invalid-dialect.env +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-dialect.env +0 -5
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-host.env +0 -5
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/oracle-valid.env +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/postgres-valid.env +0 -7
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/sqlite-valid.env +0 -2
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/category.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/item_product.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound.js +0 -24
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound_item.js +0 -28
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/supplier.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/warehouse.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-invalid/orphan.js +0 -17
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/category.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/item_product.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/supplier.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/warehouse.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound.js +0 -24
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound_item.js +0 -28
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/audit/events.js +0 -18
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/public/users.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/extra/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/master/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/bar.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/foo.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/empty-folder/README.md +0 -1
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-export/plain.js +0 -3
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-schema/bad.js +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/legacy-pattern/legacy.js +0 -12
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/audit/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/a/products.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/b/products.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/nested-deep/a/b/c/deep_table.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/.hidden/ignored.js +0 -7
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/supplier.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound_item.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/item_product.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-single/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/integration.test.js +0 -217
- package/generators/tests/unit/lib/dbschema-kit/introspect-mapper.test.js +0 -403
- package/generators/tests/unit/lib/dbschema-kit/ir-builder.test.js +0 -390
- package/generators/tests/unit/lib/dbschema-kit/loader.test.js +0 -128
- package/generators/tests/unit/lib/dbschema-kit/naming.test.js +0 -170
- package/generators/tests/unit/lib/dbschema-kit/parser/shorthand-parser.test.js +0 -237
- package/generators/tests/unit/lib/dbschema-kit/schema-printer.test.js +0 -251
- package/generators/tests/unit/lib/dbschema-kit/statement-modifier.test.js +0 -105
- package/generators/tests/unit/lib/dbschema-kit/statement-splitter.test.js +0 -165
- package/generators/tests/unit/lib/dbschema-kit/topological-sort.test.js +0 -135
- package/generators/tests/unit/lib/dbschema-kit/validator/check-compatibility-validator.test.js +0 -373
- package/generators/tests/unit/lib/dbschema-kit/validator/circular-relation-validator.test.js +0 -454
- package/generators/tests/unit/lib/dbschema-kit/validator/cross-model-validator.test.js +0 -512
- package/generators/tests/unit/lib/dbschema-kit/validator/enhanced-validate-integration.test.js +0 -390
- package/generators/tests/unit/lib/dbschema-kit/validator/naming-convention-validator.test.js +0 -306
- package/generators/tests/unit/lib/dbschema-kit/validator/schema-validator.test.js +0 -443
- package/generators/tests/unit/lib/dbschema-kit/validator/type-compatibility-validator.test.js +0 -440
- package/generators/tests/unit/lib/dbschema-kit/validator/validator-reporter.test.js +0 -172
- package/generators/tests/unit/lib/metadata-manager-dashboard.test.js +0 -256
- package/generators/tests/unit/lib/payload-validator-fieldpolicy.test.js +0 -240
- package/generators/tests/unit/lib/processor-validation-generator.test.js +0 -300
- package/generators/tests/unit/lib/sensitive-field-masker.test.js +0 -170
- package/generators/tests/unit/lib/sql-table-extractor.test.js +0 -119
- package/scripts/generate-integrity-manifest.js +0 -124
- package/scripts/snapshot-cli-contracts.js +0 -194
- package/scripts/verify-publish.js +0 -56
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const test = require('node:test');
|
|
4
|
-
const assert = require('node:assert');
|
|
5
|
-
|
|
6
|
-
const { buildIR } = require('../../../../lib/dbschema-kit/ir-builder');
|
|
7
|
-
|
|
8
|
-
// =====================================================
|
|
9
|
-
// Happy path
|
|
10
|
-
// =====================================================
|
|
11
|
-
|
|
12
|
-
test('ir-builder: single field tanpa constraint', () => {
|
|
13
|
-
const ir = buildIR('foo', { fields: { id: 'uuid pk' } });
|
|
14
|
-
assert.strictEqual(ir.tableName, 'foo');
|
|
15
|
-
assert.deepStrictEqual(ir.fields.id, { type: 'uuid', pk: true, notnull: true });
|
|
16
|
-
assert.deepStrictEqual(ir.primaryKey, ['id']);
|
|
17
|
-
assert.deepStrictEqual(ir.indexes, []);
|
|
18
|
-
assert.deepStrictEqual(ir.uniques, []);
|
|
19
|
-
assert.deepStrictEqual(ir.relations, {});
|
|
20
|
-
assert.deepStrictEqual(ir.checks, []);
|
|
21
|
-
assert.strictEqual(ir._meta.hasSinglePkShorthand, true);
|
|
22
|
-
assert.strictEqual(ir._meta.hasCompositePrimaryKey, false);
|
|
23
|
-
assert.deepStrictEqual(ir._meta.autoGeneratedRelations, []);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('ir-builder: field dengan multiple constraint mempertahankan property hasil parse', () => {
|
|
27
|
-
const ir = buildIR('foo', {
|
|
28
|
-
fields: {
|
|
29
|
-
id: 'uuid pk',
|
|
30
|
-
code: 'string:20 unique notnull'
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
assert.strictEqual(ir.fields.code.type, 'string');
|
|
34
|
-
assert.strictEqual(ir.fields.code.length, 20);
|
|
35
|
-
assert.strictEqual(ir.fields.code.unique, true);
|
|
36
|
-
assert.strictEqual(ir.fields.code.notnull, true);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('ir-builder: composite primary key auto-marks notnull pada semua field', () => {
|
|
40
|
-
const ir = buildIR('inventory_balance', {
|
|
41
|
-
fields: {
|
|
42
|
-
a: 'uuid',
|
|
43
|
-
b: 'uuid',
|
|
44
|
-
c: 'date'
|
|
45
|
-
},
|
|
46
|
-
primaryKey: ['a', 'b']
|
|
47
|
-
});
|
|
48
|
-
assert.deepStrictEqual(ir.primaryKey, ['a', 'b']);
|
|
49
|
-
assert.strictEqual(ir.fields.a.notnull, true);
|
|
50
|
-
assert.strictEqual(ir.fields.b.notnull, true);
|
|
51
|
-
assert.strictEqual(ir.fields.c.notnull, undefined);
|
|
52
|
-
assert.strictEqual(ir._meta.hasCompositePrimaryKey, true);
|
|
53
|
-
assert.strictEqual(ir._meta.hasSinglePkShorthand, false);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test('ir-builder: single pk shorthand auto-marks notnull dan emit ke primaryKey array', () => {
|
|
57
|
-
const ir = buildIR('category', {
|
|
58
|
-
fields: { category_id: 'uuid pk' }
|
|
59
|
-
});
|
|
60
|
-
assert.deepStrictEqual(ir.primaryKey, ['category_id']);
|
|
61
|
-
assert.strictEqual(ir.fields.category_id.notnull, true);
|
|
62
|
-
assert.strictEqual(ir.fields.category_id.pk, true);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test('ir-builder: single column index', () => {
|
|
66
|
-
const ir = buildIR('foo', {
|
|
67
|
-
fields: { id: 'uuid pk', name: 'string:50' },
|
|
68
|
-
indexes: ['name']
|
|
69
|
-
});
|
|
70
|
-
assert.deepStrictEqual(ir.indexes, [{ columns: ['name'], composite: false }]);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('ir-builder: composite index', () => {
|
|
74
|
-
const ir = buildIR('foo', {
|
|
75
|
-
fields: { id: 'uuid pk', a: 'string:20', b: 'string:20' },
|
|
76
|
-
indexes: [['a', 'b']]
|
|
77
|
-
});
|
|
78
|
-
assert.deepStrictEqual(ir.indexes, [{ columns: ['a', 'b'], composite: true }]);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('ir-builder: mix single dan composite index', () => {
|
|
82
|
-
const ir = buildIR('foo', {
|
|
83
|
-
fields: { id: 'uuid pk', a: 'string:20', b: 'string:20', c: 'string:20' },
|
|
84
|
-
indexes: ['a', ['b', 'c']]
|
|
85
|
-
});
|
|
86
|
-
assert.deepStrictEqual(ir.indexes, [
|
|
87
|
-
{ columns: ['a'], composite: false },
|
|
88
|
-
{ columns: ['b', 'c'], composite: true }
|
|
89
|
-
]);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('ir-builder: composite unique', () => {
|
|
93
|
-
const ir = buildIR('stock_inbound_item', {
|
|
94
|
-
fields: { id: 'uuid pk', stock_inbound_id: 'uuid', line_number: 'integer' },
|
|
95
|
-
uniques: [['stock_inbound_id', 'line_number']]
|
|
96
|
-
});
|
|
97
|
-
assert.deepStrictEqual(ir.uniques, [{ columns: ['stock_inbound_id', 'line_number'] }]);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test('ir-builder: fk shorthand auto-promote ke relations entry', () => {
|
|
101
|
-
const ir = buildIR('item_product', {
|
|
102
|
-
fields: {
|
|
103
|
-
item_product_id: 'string:36 pk',
|
|
104
|
-
category_id: 'string:36 fk:category.category_id notnull'
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
assert.ok(ir.relations.category, 'relation `category` should exist');
|
|
108
|
-
assert.strictEqual(ir.relations.category.type, 'belongsTo');
|
|
109
|
-
assert.strictEqual(ir.relations.category.target, 'category');
|
|
110
|
-
assert.strictEqual(ir.relations.category.localKey, 'category_id');
|
|
111
|
-
assert.strictEqual(ir.relations.category.references, 'category_id');
|
|
112
|
-
assert.strictEqual(ir.relations.category._autoGenerated, true);
|
|
113
|
-
assert.strictEqual(ir.relations.category._sourceField, 'category_id');
|
|
114
|
-
assert.deepStrictEqual(ir._meta.autoGeneratedRelations, ['category']);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test('ir-builder: derivasi nama relation dari field berakhiran _id (strip suffix)', () => {
|
|
118
|
-
const ir = buildIR('item_product', {
|
|
119
|
-
fields: {
|
|
120
|
-
id: 'uuid pk',
|
|
121
|
-
category_id: 'string:36 fk:category.category_id'
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
assert.ok(ir.relations.category);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test('ir-builder: derivasi nama relation untuk field tanpa suffix _id', () => {
|
|
128
|
-
const ir = buildIR('purchase_order', {
|
|
129
|
-
fields: {
|
|
130
|
-
id: 'uuid pk',
|
|
131
|
-
created_by: 'string:36 fk:user.id'
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
assert.ok(ir.relations.created_by_user, 'relation name should be `created_by_user`');
|
|
135
|
-
assert.strictEqual(ir.relations.created_by_user.target, 'user');
|
|
136
|
-
assert.strictEqual(ir.relations.created_by_user.localKey, 'created_by');
|
|
137
|
-
assert.strictEqual(ir.relations.created_by_user.references, 'id');
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test('ir-builder: relations eksplisit dengan custom onDelete dan default target', () => {
|
|
141
|
-
const ir = buildIR('stock_inbound', {
|
|
142
|
-
fields: {
|
|
143
|
-
id: 'uuid pk',
|
|
144
|
-
supplier_id: 'string:36'
|
|
145
|
-
},
|
|
146
|
-
relations: {
|
|
147
|
-
supplier: {
|
|
148
|
-
type: 'belongsTo',
|
|
149
|
-
localKey: 'supplier_id',
|
|
150
|
-
references: 'supplier_id',
|
|
151
|
-
onDelete: 'setNull'
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
assert.strictEqual(ir.relations.supplier.target, 'supplier');
|
|
156
|
-
assert.strictEqual(ir.relations.supplier.onDelete, 'setNull');
|
|
157
|
-
assert.strictEqual(ir.relations.supplier._autoGenerated, false);
|
|
158
|
-
assert.strictEqual(ir.relations.supplier._sourceField, null);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
test('ir-builder: relations eksplisit dengan target eksplisit (multiple FK ke target sama)', () => {
|
|
162
|
-
const ir = buildIR('purchase_order', {
|
|
163
|
-
fields: {
|
|
164
|
-
id: 'string:36 pk',
|
|
165
|
-
created_by: 'string:36'
|
|
166
|
-
},
|
|
167
|
-
relations: {
|
|
168
|
-
creator: {
|
|
169
|
-
type: 'belongsTo',
|
|
170
|
-
target: 'user',
|
|
171
|
-
localKey: 'created_by',
|
|
172
|
-
references: 'id'
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
assert.strictEqual(ir.relations.creator.target, 'user');
|
|
177
|
-
assert.strictEqual(ir.relations.creator.localKey, 'created_by');
|
|
178
|
-
assert.strictEqual(ir.relations.creator.references, 'id');
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
test('ir-builder: multiple relations ke target tabel yang sama dengan localKey berbeda', () => {
|
|
182
|
-
const ir = buildIR('purchase_order', {
|
|
183
|
-
fields: {
|
|
184
|
-
id: 'string:36 pk',
|
|
185
|
-
created_by: 'string:36',
|
|
186
|
-
updated_by: 'string:36'
|
|
187
|
-
},
|
|
188
|
-
relations: {
|
|
189
|
-
creator: { type: 'belongsTo', target: 'user', localKey: 'created_by', references: 'id' },
|
|
190
|
-
updater: { type: 'belongsTo', target: 'user', localKey: 'updated_by', references: 'id' }
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
assert.strictEqual(ir.relations.creator.target, 'user');
|
|
194
|
-
assert.strictEqual(ir.relations.creator.localKey, 'created_by');
|
|
195
|
-
assert.strictEqual(ir.relations.updater.target, 'user');
|
|
196
|
-
assert.strictEqual(ir.relations.updater.localKey, 'updated_by');
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test('ir-builder: auto-index untuk fk shorthand di field-level', () => {
|
|
200
|
-
const ir = buildIR('item_product', {
|
|
201
|
-
fields: {
|
|
202
|
-
id: 'uuid pk',
|
|
203
|
-
category_id: 'string:36 fk:category.category_id'
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
assert.strictEqual(ir.fields.category_id.index, true);
|
|
207
|
-
const hasIdx = ir.indexes.some((i) => i.columns.length === 1 && i.columns[0] === 'category_id');
|
|
208
|
-
assert.ok(hasIdx, 'indexes should include category_id');
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
test('ir-builder: auto-index untuk relations belongsTo eksplisit', () => {
|
|
212
|
-
const ir = buildIR('stock_inbound', {
|
|
213
|
-
fields: {
|
|
214
|
-
id: 'uuid pk',
|
|
215
|
-
warehouse_id: 'string:36'
|
|
216
|
-
},
|
|
217
|
-
relations: {
|
|
218
|
-
warehouse: { type: 'belongsTo', localKey: 'warehouse_id', references: 'warehouse_id' }
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
assert.strictEqual(ir.fields.warehouse_id.index, true);
|
|
222
|
-
const hasIdx = ir.indexes.some((i) => i.columns.length === 1 && i.columns[0] === 'warehouse_id');
|
|
223
|
-
assert.ok(hasIdx, 'indexes should include warehouse_id');
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
test('ir-builder: auto-index dedupe ketika user juga menulis field di indexes', () => {
|
|
227
|
-
const ir = buildIR('stock_inbound', {
|
|
228
|
-
fields: {
|
|
229
|
-
id: 'uuid pk',
|
|
230
|
-
warehouse_id: 'string:36'
|
|
231
|
-
},
|
|
232
|
-
indexes: ['warehouse_id'],
|
|
233
|
-
relations: {
|
|
234
|
-
warehouse: { type: 'belongsTo', localKey: 'warehouse_id', references: 'warehouse_id' }
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
const matches = ir.indexes.filter((i) => i.columns.length === 1 && i.columns[0] === 'warehouse_id');
|
|
238
|
-
assert.strictEqual(matches.length, 1, 'warehouse_id should not be duplicated in indexes');
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
test('ir-builder: checks normalisasi entry dengan operator `in`', () => {
|
|
242
|
-
const ir = buildIR('stock_inbound', {
|
|
243
|
-
fields: { id: 'uuid pk', status: "string:20 default:'draft'" },
|
|
244
|
-
checks: [{ field: 'status', in: ['draft', 'closed'] }]
|
|
245
|
-
});
|
|
246
|
-
assert.strictEqual(ir.checks.length, 1);
|
|
247
|
-
assert.strictEqual(ir.checks[0].field, 'status');
|
|
248
|
-
assert.strictEqual(ir.checks[0].op, 'in');
|
|
249
|
-
assert.deepStrictEqual(ir.checks[0].value, ['draft', 'closed']);
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
test('ir-builder: field dengan autoUpdate token (parser Fase 1 belum support, di-strip oleh IR builder)', () => {
|
|
253
|
-
const ir = buildIR('foo', {
|
|
254
|
-
fields: {
|
|
255
|
-
id: 'uuid pk',
|
|
256
|
-
updated_at: 'timestamp autoUpdate'
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
assert.strictEqual(ir.fields.updated_at.type, 'timestamp');
|
|
260
|
-
assert.strictEqual(ir.fields.updated_at.autoUpdate, true);
|
|
261
|
-
assert.strictEqual(ir.fields.updated_at.default, undefined);
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
// =====================================================
|
|
265
|
-
// Edge case (defer ke validator)
|
|
266
|
-
// =====================================================
|
|
267
|
-
|
|
268
|
-
test('ir-builder: konflik pk shorthand + primaryKey option keep both, tidak throw', () => {
|
|
269
|
-
const ir = buildIR('foo', {
|
|
270
|
-
fields: {
|
|
271
|
-
a: 'uuid pk',
|
|
272
|
-
b: 'uuid'
|
|
273
|
-
},
|
|
274
|
-
primaryKey: ['a', 'b']
|
|
275
|
-
});
|
|
276
|
-
assert.deepStrictEqual(ir.primaryKey, ['a', 'b']);
|
|
277
|
-
assert.strictEqual(ir._meta.hasSinglePkShorthand, true);
|
|
278
|
-
assert.strictEqual(ir._meta.hasCompositePrimaryKey, true);
|
|
279
|
-
assert.strictEqual(ir.fields.a.pk, true);
|
|
280
|
-
assert.strictEqual(ir.fields.a.notnull, true);
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
test('ir-builder: auto-name collision dengan eksplisit memakai suffix _auto', () => {
|
|
284
|
-
const ir = buildIR('item_product', {
|
|
285
|
-
fields: {
|
|
286
|
-
id: 'uuid pk',
|
|
287
|
-
category_id: 'string:36 fk:category.category_id'
|
|
288
|
-
},
|
|
289
|
-
relations: {
|
|
290
|
-
category: {
|
|
291
|
-
type: 'belongsTo',
|
|
292
|
-
localKey: 'category_id',
|
|
293
|
-
references: 'category_id',
|
|
294
|
-
onDelete: 'cascade'
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
assert.ok(ir.relations.category, 'explicit relation should be preserved');
|
|
299
|
-
assert.strictEqual(ir.relations.category._autoGenerated, false);
|
|
300
|
-
assert.strictEqual(ir.relations.category.onDelete, 'cascade');
|
|
301
|
-
assert.ok(ir.relations.category_auto, 'auto-generated relation should use suffix `_auto`');
|
|
302
|
-
assert.strictEqual(ir.relations.category_auto._autoGenerated, true);
|
|
303
|
-
assert.deepStrictEqual(ir._meta.autoGeneratedRelations, ['category_auto']);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
test('ir-builder: relations eksplisit dengan localKey ke field tidak existing tidak throw', () => {
|
|
307
|
-
const ir = buildIR('foo', {
|
|
308
|
-
fields: { id: 'uuid pk' },
|
|
309
|
-
relations: {
|
|
310
|
-
bar: { type: 'belongsTo', localKey: 'nonexistent_field', references: 'id' }
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
assert.ok(ir.relations.bar);
|
|
314
|
-
assert.strictEqual(ir.relations.bar.localKey, 'nonexistent_field');
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
test('ir-builder: check dengan multiple operator di-flag _invalid', () => {
|
|
318
|
-
const ir = buildIR('foo', {
|
|
319
|
-
fields: { id: 'uuid pk', x: 'integer' },
|
|
320
|
-
checks: [{ field: 'x', gt: 0, lt: 100 }]
|
|
321
|
-
});
|
|
322
|
-
assert.strictEqual(ir.checks.length, 1);
|
|
323
|
-
assert.strictEqual(ir.checks[0]._invalid, true);
|
|
324
|
-
assert.strictEqual(ir.checks[0]._reason, 'multiple operators');
|
|
325
|
-
assert.strictEqual(ir.checks[0].field, 'x');
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
test('ir-builder: check tanpa operator di-flag _invalid', () => {
|
|
329
|
-
const ir = buildIR('foo', {
|
|
330
|
-
fields: { id: 'uuid pk', x: 'integer' },
|
|
331
|
-
checks: [{ field: 'x' }]
|
|
332
|
-
});
|
|
333
|
-
assert.strictEqual(ir.checks.length, 1);
|
|
334
|
-
assert.strictEqual(ir.checks[0]._invalid, true);
|
|
335
|
-
assert.strictEqual(ir.checks[0]._reason, 'no operator');
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
// =====================================================
|
|
339
|
-
// Structural error case (boleh throw)
|
|
340
|
-
// =====================================================
|
|
341
|
-
|
|
342
|
-
test('ir-builder: tableName bukan string atau empty harus throw', () => {
|
|
343
|
-
assert.throws(() => buildIR('', { fields: { id: 'uuid pk' } }), /Table name must be a non-empty string/);
|
|
344
|
-
assert.throws(() => buildIR(null, { fields: { id: 'uuid pk' } }), /Table name must be a non-empty string/);
|
|
345
|
-
assert.throws(() => buildIR(123, { fields: { id: 'uuid pk' } }), /Table name must be a non-empty string/);
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
test('ir-builder: options.fields tidak ada atau bukan plain object harus throw', () => {
|
|
349
|
-
assert.throws(() => buildIR('foo', {}), /options\.fields must be a plain object/);
|
|
350
|
-
assert.throws(() => buildIR('foo', { fields: null }), /options\.fields must be a plain object/);
|
|
351
|
-
assert.throws(() => buildIR('foo', { fields: [] }), /options\.fields must be a plain object/);
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
test('ir-builder: options.fields empty object harus throw', () => {
|
|
355
|
-
assert.throws(() => buildIR('foo', { fields: {} }), /options\.fields must have at least one field/);
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
test('ir-builder: parser error propagated dengan context tableName', () => {
|
|
359
|
-
assert.throws(
|
|
360
|
-
() => buildIR('foo', { fields: { code: 'string:20 uniqe' } }),
|
|
361
|
-
/^Error: Table 'foo': Field 'code': unknown constraint 'uniqe'$/
|
|
362
|
-
);
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
// =====================================================
|
|
366
|
-
// Phase 13: schema namespace support
|
|
367
|
-
// =====================================================
|
|
368
|
-
|
|
369
|
-
test('ir-builder: IR.qualifiedName == <schema>.<table> bila schema diberikan', () => {
|
|
370
|
-
const ir = buildIR('products', {
|
|
371
|
-
schema: 'inventory',
|
|
372
|
-
fields: { id: 'uuid pk' }
|
|
373
|
-
});
|
|
374
|
-
assert.strictEqual(ir.schemaName, 'inventory');
|
|
375
|
-
assert.strictEqual(ir.tableName, 'products');
|
|
376
|
-
assert.strictEqual(ir.qualifiedName, 'inventory.products');
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
test('ir-builder: IR.qualifiedName == tableName bila schema null', () => {
|
|
380
|
-
const ir = buildIR('products', { fields: { id: 'uuid pk' } });
|
|
381
|
-
assert.strictEqual(ir.schemaName, null);
|
|
382
|
-
assert.strictEqual(ir.qualifiedName, 'products');
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
test('ir-builder: options.schema bukan string harus throw', () => {
|
|
386
|
-
assert.throws(
|
|
387
|
-
() => buildIR('products', { schema: 42, fields: { id: 'uuid pk' } }),
|
|
388
|
-
/^Error: Table 'products': options\.schema must be a string or null$/
|
|
389
|
-
);
|
|
390
|
-
});
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const test = require('node:test');
|
|
4
|
-
const assert = require('node:assert');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
|
|
7
|
-
const { loadSchemaFolder } = require('../../../../lib/dbschema-kit/loader');
|
|
8
|
-
|
|
9
|
-
const FIXTURES = path.join(__dirname, 'fixtures', 'loader');
|
|
10
|
-
|
|
11
|
-
test('loader: folder dengan 1 file valid return Map dengan 1 entry, tableName sebagai key', () => {
|
|
12
|
-
const map = loadSchemaFolder(path.join(FIXTURES, 'valid-single'));
|
|
13
|
-
assert.strictEqual(map.size, 1);
|
|
14
|
-
assert.ok(map.has('category'), "key 'category' harus ada");
|
|
15
|
-
assert.strictEqual(map.get('category').tableName, 'category');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('loader: folder dengan multiple file valid return Map dengan multiple entries', () => {
|
|
19
|
-
const map = loadSchemaFolder(path.join(FIXTURES, 'valid-multiple'));
|
|
20
|
-
assert.strictEqual(map.size, 2);
|
|
21
|
-
assert.ok(map.has('category'));
|
|
22
|
-
assert.ok(map.has('item_product'));
|
|
23
|
-
assert.strictEqual(map.get('item_product').fields.item_product_id.pk, true);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('loader: folder tidak exist throw', () => {
|
|
27
|
-
assert.throws(
|
|
28
|
-
() => loadSchemaFolder(path.join(FIXTURES, 'nonexistent-folder')),
|
|
29
|
-
/^Error: Schema folder not found:/
|
|
30
|
-
);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('loader: folder berisi file non-js (README.md) skip dan return Map kosong', () => {
|
|
34
|
-
const map = loadSchemaFolder(path.join(FIXTURES, 'empty-folder'));
|
|
35
|
-
assert.strictEqual(map.size, 0);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('loader: duplicate tableName antar file throw dengan info kedua file', () => {
|
|
39
|
-
// fs.readdirSync mengembalikan entry alfabetis: bar.js (di-load duluan), lalu foo.js (collision).
|
|
40
|
-
assert.throws(
|
|
41
|
-
() => loadSchemaFolder(path.join(FIXTURES, 'duplicate-tablename')),
|
|
42
|
-
/^Error: Duplicate table name 'same_name' in files: bar\.js, foo\.js$/
|
|
43
|
-
);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test('loader: file tidak export factory function throw dengan instruksi migration', () => {
|
|
47
|
-
assert.throws(
|
|
48
|
-
() => loadSchemaFolder(path.join(FIXTURES, 'invalid-export')),
|
|
49
|
-
/^Error: Schema file 'plain\.js' must export a factory function\. Use: module\.exports = \(\{ defineModel \}\) => defineModel\(\.\.\.\)$/
|
|
50
|
-
);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('loader: file mengandung schema invalid (single-model violation) throw wrapped error dengan filename context', () => {
|
|
54
|
-
assert.throws(
|
|
55
|
-
() => loadSchemaFolder(path.join(FIXTURES, 'invalid-schema')),
|
|
56
|
-
/^Error: Failed to load schema file 'bad\.js': Table name must be snake_case/
|
|
57
|
-
);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('loader: factory function pattern (module.exports = ({ defineModel }) => defineModel(...)) load sukses', () => {
|
|
61
|
-
const map = loadSchemaFolder(path.join(FIXTURES, 'valid-single'));
|
|
62
|
-
assert.strictEqual(map.size, 1);
|
|
63
|
-
const ir = map.get('category');
|
|
64
|
-
assert.ok(ir, 'IR harus ter-load');
|
|
65
|
-
assert.strictEqual(ir.tableName, 'category');
|
|
66
|
-
assert.ok(ir.fields, 'IR harus punya properti fields');
|
|
67
|
-
assert.strictEqual(ir.fields.category_id.pk, true);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test('loader: pattern lama (module.exports = defineModel(...) direct) throw error dengan instruksi migration', () => {
|
|
71
|
-
assert.throws(
|
|
72
|
-
() => loadSchemaFolder(path.join(FIXTURES, 'legacy-pattern')),
|
|
73
|
-
/^Error: Schema file 'legacy\.js' must export a factory function\. Use: module\.exports = \(\{ defineModel \}\) => defineModel\(\.\.\.\)$/
|
|
74
|
-
);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('loader: recursive scan folder dengan 2 subfolder (master, transactions) load 4 model', () => {
|
|
78
|
-
const map = loadSchemaFolder(path.join(FIXTURES, 'recursive-multi-folder'));
|
|
79
|
-
assert.strictEqual(map.size, 4, 'harus load 4 model dari subfolder master + transactions');
|
|
80
|
-
assert.ok(map.has('category'));
|
|
81
|
-
assert.ok(map.has('supplier'));
|
|
82
|
-
assert.ok(map.has('stock_inbound'));
|
|
83
|
-
assert.ok(map.has('stock_inbound_item'));
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('loader: recursive scan skip hidden folder (.hidden), file di dalamnya tidak masuk Map', () => {
|
|
87
|
-
const map = loadSchemaFolder(path.join(FIXTURES, 'recursive-multi-folder'));
|
|
88
|
-
assert.ok(!map.has('hidden_ignored'), "tabel di .hidden/ tidak boleh ter-load");
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('loader: recursive scan skip folder node_modules, file di dalamnya tidak masuk Map', () => {
|
|
92
|
-
const map = loadSchemaFolder(path.join(FIXTURES, 'recursive-multi-folder'));
|
|
93
|
-
assert.ok(!map.has('nm_junk'), "tabel di node_modules/ tidak boleh ter-load");
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('loader: duplicate tableName di subfolder berbeda throw dengan info kedua relative path', () => {
|
|
97
|
-
assert.throws(
|
|
98
|
-
() => loadSchemaFolder(path.join(FIXTURES, 'duplicate-subfolder')),
|
|
99
|
-
/^Error: Duplicate table name 'category' in files: extra\/category\.js, master\/category\.js$/
|
|
100
|
-
);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test('loader: recursive scan folder nested 3+ level (a/b/c/foo.js) tetap load file', () => {
|
|
104
|
-
const map = loadSchemaFolder(path.join(FIXTURES, 'nested-deep'));
|
|
105
|
-
assert.strictEqual(map.size, 1, 'harus load 1 model dari nested deep folder');
|
|
106
|
-
assert.ok(map.has('deep_table'));
|
|
107
|
-
assert.strictEqual(map.get('deep_table').tableName, 'deep_table');
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// =====================================================
|
|
111
|
-
// Phase 13: schema namespace support
|
|
112
|
-
// =====================================================
|
|
113
|
-
|
|
114
|
-
test('loader: dua file dengan tableName sama tapi schema beda load sukses, Map keyed by qualified name', () => {
|
|
115
|
-
const map = loadSchemaFolder(path.join(FIXTURES, 'multi-schema-distinct'));
|
|
116
|
-
assert.strictEqual(map.size, 2, 'harus load 2 model walaupun tableName sama');
|
|
117
|
-
assert.ok(map.has('inventory.products'), 'qualified key inventory.products harus ada');
|
|
118
|
-
assert.ok(map.has('audit.products'), 'qualified key audit.products harus ada');
|
|
119
|
-
assert.strictEqual(map.get('inventory.products').schemaName, 'inventory');
|
|
120
|
-
assert.strictEqual(map.get('audit.products').schemaName, 'audit');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('loader: dua file dengan qualified name sama (schema + table identik) → duplicate error dengan qualified name', () => {
|
|
124
|
-
assert.throws(
|
|
125
|
-
() => loadSchemaFolder(path.join(FIXTURES, 'multi-schema-duplicate')),
|
|
126
|
-
/^Error: Duplicate table name 'inventory\.products' in files: a\/products\.js, b\/products\.js$/
|
|
127
|
-
);
|
|
128
|
-
});
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const test = require('node:test');
|
|
4
|
-
const assert = require('node:assert');
|
|
5
|
-
const crypto = require('node:crypto');
|
|
6
|
-
|
|
7
|
-
const { generateConstraintName, deriveCompositeShortName, shortenIdentifier } = require('../../../../lib/dbschema-kit/naming');
|
|
8
|
-
|
|
9
|
-
test('naming: generateConstraintName tanpa suffix menghasilkan prefix_table', () => {
|
|
10
|
-
assert.strictEqual(generateConstraintName('pk', 'category', ''), 'pk_category');
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test('naming: generateConstraintName tanpa suffix (undefined) menghasilkan prefix_table', () => {
|
|
14
|
-
assert.strictEqual(generateConstraintName('pk', 'category'), 'pk_category');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('naming: generateConstraintName dengan suffix menghasilkan prefix_table_suffix', () => {
|
|
18
|
-
assert.strictEqual(generateConstraintName('uq', 'category', 'code'), 'uq_category_code');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test('naming: generateConstraintName foreign key', () => {
|
|
22
|
-
assert.strictEqual(
|
|
23
|
-
generateConstraintName('fk', 'stock_inbound', 'warehouse'),
|
|
24
|
-
'fk_stock_inbound_warehouse'
|
|
25
|
-
);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('naming: generateConstraintName index single column', () => {
|
|
29
|
-
assert.strictEqual(
|
|
30
|
-
generateConstraintName('idx', 'stock_inbound', 'inbound_date'),
|
|
31
|
-
'idx_stock_inbound_inbound_date'
|
|
32
|
-
);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test('naming: generateConstraintName check single', () => {
|
|
36
|
-
assert.strictEqual(
|
|
37
|
-
generateConstraintName('chk', 'item_product', 'uom'),
|
|
38
|
-
'chk_item_product_uom'
|
|
39
|
-
);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('naming: generateConstraintName total tepat 30 char tetap as-is', () => {
|
|
43
|
-
const name = generateConstraintName('idx', 'stock_inbound', 'inbound_date');
|
|
44
|
-
assert.strictEqual(name.length, 30);
|
|
45
|
-
assert.strictEqual(name, 'idx_stock_inbound_inbound_date');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('naming: generateConstraintName > 30 char menghasilkan 22+1+7 dengan md5 hash', () => {
|
|
49
|
-
const original = 'fk_stock_inbound_item_stock_inbound';
|
|
50
|
-
assert.strictEqual(original.length, 35);
|
|
51
|
-
|
|
52
|
-
const expectedHash = crypto.createHash('md5').update(original).digest('hex').slice(0, 7);
|
|
53
|
-
const expected = `${original.slice(0, 22)}_${expectedHash}`;
|
|
54
|
-
|
|
55
|
-
const result = generateConstraintName('fk', 'stock_inbound_item', 'stock_inbound');
|
|
56
|
-
assert.strictEqual(result.length, 30);
|
|
57
|
-
assert.strictEqual(result, expected);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('naming: generateConstraintName deterministic — panggil 2x dengan input sama menghasilkan output sama', () => {
|
|
61
|
-
const a = generateConstraintName('fk', 'stock_inbound_item', 'stock_inbound');
|
|
62
|
-
const b = generateConstraintName('fk', 'stock_inbound_item', 'stock_inbound');
|
|
63
|
-
assert.strictEqual(a, b);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('naming: generateConstraintName beda input menghasilkan beda hash', () => {
|
|
67
|
-
const a = generateConstraintName('fk', 'stock_inbound_item', 'stock_inbound');
|
|
68
|
-
const b = generateConstraintName('fk', 'stock_inbound_item', 'stock_outbound_xx');
|
|
69
|
-
assert.notStrictEqual(a, b);
|
|
70
|
-
assert.strictEqual(a.length, 30);
|
|
71
|
-
assert.strictEqual(b.length, 30);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('naming: deriveCompositeShortName total <= 30 char join dengan underscore', () => {
|
|
75
|
-
assert.strictEqual(
|
|
76
|
-
deriveCompositeShortName(['stock_inbound_id', 'line_number']),
|
|
77
|
-
'stock_inbound_id_line_number'
|
|
78
|
-
);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('naming: deriveCompositeShortName dua kolom pendek', () => {
|
|
82
|
-
assert.strictEqual(deriveCompositeShortName(['a', 'b']), 'a_b');
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test('naming: deriveCompositeShortName total > 30 char fallback ke kolom terakhir', () => {
|
|
86
|
-
assert.strictEqual(
|
|
87
|
-
deriveCompositeShortName(['stock_inbound_id', 'item_product_id']),
|
|
88
|
-
'item_product_id'
|
|
89
|
-
);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('naming: deriveCompositeShortName tiga kolom panjang fallback ke kolom terakhir', () => {
|
|
93
|
-
assert.strictEqual(
|
|
94
|
-
deriveCompositeShortName(['long_col_name1', 'long_col_name2', 'long_col_name3']),
|
|
95
|
-
'long_col_name3'
|
|
96
|
-
);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test('naming: deriveCompositeShortName throw bila columns kosong', () => {
|
|
100
|
-
assert.throws(() => deriveCompositeShortName([]), /Columns must be a non-empty array/);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
|
-
// maxLength parameter (per-dialect identifier cap)
|
|
105
|
-
// ---------------------------------------------------------------------------
|
|
106
|
-
|
|
107
|
-
test('naming: generateConstraintName dengan maxLength=63 keep nama panjang as-is', () => {
|
|
108
|
-
// Original: 'fk_stock_inbound_item_stock_inbound' = 35 char, < 63 → tidak di-hash
|
|
109
|
-
const result = generateConstraintName('fk', 'stock_inbound_item', 'stock_inbound', 63);
|
|
110
|
-
assert.strictEqual(result, 'fk_stock_inbound_item_stock_inbound');
|
|
111
|
-
assert.strictEqual(result.length, 35);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test('naming: generateConstraintName dengan maxLength=63 hash hanya bila > 63', () => {
|
|
115
|
-
const original = 'fk_very_long_table_name_with_many_words_and_extra_padding_chars_xxx';
|
|
116
|
-
assert.ok(original.length > 63);
|
|
117
|
-
|
|
118
|
-
const expectedHash = crypto.createHash('md5').update(original).digest('hex').slice(0, 7);
|
|
119
|
-
const expected = `${original.slice(0, 63 - 8)}_${expectedHash}`; // 63 - 7 - 1 = 55
|
|
120
|
-
|
|
121
|
-
const result = generateConstraintName('fk', 'very_long_table_name_with_many_words_and_extra_padding_chars', 'xxx', 63);
|
|
122
|
-
assert.strictEqual(result.length, 63);
|
|
123
|
-
assert.strictEqual(result, expected);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
test('naming: generateConstraintName dengan maxLength=128 (Oracle 19c) keep panjang', () => {
|
|
127
|
-
const result = generateConstraintName('fk', 'stock_inbound_item', 'stock_inbound', 128);
|
|
128
|
-
assert.strictEqual(result, 'fk_stock_inbound_item_stock_inbound');
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
test('naming: generateConstraintName maxLength undefined fallback ke 30 (default legacy)', () => {
|
|
132
|
-
// explicit undefined → still hashed at 30 char limit
|
|
133
|
-
const a = generateConstraintName('fk', 'stock_inbound_item', 'stock_inbound');
|
|
134
|
-
const b = generateConstraintName('fk', 'stock_inbound_item', 'stock_inbound', undefined);
|
|
135
|
-
assert.strictEqual(a, b);
|
|
136
|
-
assert.strictEqual(a.length, 30);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
test('naming: deriveCompositeShortName dengan maxLength=63 tidak fallback bila join < 63', () => {
|
|
140
|
-
// 'stock_inbound_id_item_product_id' = 31 char, < 63 → join utuh
|
|
141
|
-
assert.strictEqual(
|
|
142
|
-
deriveCompositeShortName(['stock_inbound_id', 'item_product_id'], 63),
|
|
143
|
-
'stock_inbound_id_item_product_id'
|
|
144
|
-
);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test('naming: deriveCompositeShortName dengan maxLength=63 fallback bila join > 63', () => {
|
|
148
|
-
// join total > 63 → return last column
|
|
149
|
-
assert.strictEqual(
|
|
150
|
-
deriveCompositeShortName(['col_aaaaaaaaaaaaa', 'col_bbbbbbbbbbbbbb', 'col_cccccccccccccc', 'col_ddddddddddddd'], 63),
|
|
151
|
-
'col_ddddddddddddd'
|
|
152
|
-
);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
test('naming: shortenIdentifier short name returns as-is', () => {
|
|
156
|
-
assert.strictEqual(shortenIdentifier('short_name'), 'short_name');
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
test('naming: shortenIdentifier > 30 char default → truncate + hash', () => {
|
|
160
|
-
const original = 'this_is_a_very_long_check_constraint_name';
|
|
161
|
-
assert.ok(original.length > 30);
|
|
162
|
-
const result = shortenIdentifier(original);
|
|
163
|
-
assert.strictEqual(result.length, 30);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
test('naming: shortenIdentifier maxLength=63 keep nama < 63 as-is', () => {
|
|
167
|
-
const original = 'this_is_a_very_long_check_constraint_name';
|
|
168
|
-
assert.ok(original.length < 63);
|
|
169
|
-
assert.strictEqual(shortenIdentifier(original, 63), original);
|
|
170
|
-
});
|