@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.
- 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 +43 -4
- 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 +526 -0
- package/generators/cli/schema/describe.js +3 -2
- package/generators/cli/schema/diff.js +322 -0
- package/generators/cli/schema/generate-ddl.js +7 -10
- package/generators/cli/schema/init.js +95 -172
- package/generators/cli/schema/introspect.js +3 -2
- package/generators/cli/schema/list.js +3 -2
- package/generators/cli/schema/migrate.js +13 -18
- package/generators/cli/schema/models.js +8 -12
- package/generators/cli/schema/template.js +222 -0
- package/generators/cli/schema/validate.js +8 -12
- package/generators/cli-entry.js +17 -2
- package/generators/lib/dbschema-kit/apply-engine.js +582 -0
- package/generators/lib/dbschema-kit/diff-engine.js +703 -0
- package/generators/lib/dbschema-kit/diff-reporter.js +272 -0
- package/generators/lib/dbschema-kit/emitters/alter-table.js +275 -0
- package/generators/lib/migration/audit-table-runner.js +213 -215
- package/generators/lib/payload/endpoint-schema-validator.js +171 -0
- package/generators/lib/payload/payload-runner.js +137 -220
- package/generators/lib/payload/schema-diff.js +277 -0
- 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/audit-columns.js +181 -0
- package/generators/lib/utils/cli-output.js +17 -0
- package/generators/lib/utils/database-introspector.js +16 -13
- 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
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Diff Reporter — format delta dari diff-engine menjadi output human-readable
|
|
5
|
+
* plain text atau JSON object. Reporter tidak melakukan I/O sendiri; caller
|
|
6
|
+
* yang memutuskan untuk write ke stdout atau file.
|
|
7
|
+
*
|
|
8
|
+
* Exit code semantic:
|
|
9
|
+
* 0 — no drift
|
|
10
|
+
* 1 — drift detected
|
|
11
|
+
* 2 — error (di-set oleh caller, bukan oleh reporter ini)
|
|
12
|
+
*
|
|
13
|
+
* @module lib/dbschema-kit/diff-reporter
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// ─────────────────────────────────────────────────────────────
|
|
17
|
+
// Format helpers
|
|
18
|
+
// ─────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
function formatFieldSignature(f) {
|
|
21
|
+
if (!f) return '(unknown)';
|
|
22
|
+
const parts = [];
|
|
23
|
+
if (f.type !== undefined) {
|
|
24
|
+
if (f.type === 'string' && f.length !== undefined) {
|
|
25
|
+
parts.push(`${f.type}(${f.length})`);
|
|
26
|
+
} else if (f.type === 'decimal' && f.precision !== undefined && f.scale !== undefined) {
|
|
27
|
+
parts.push(`${f.type}(${f.precision},${f.scale})`);
|
|
28
|
+
} else {
|
|
29
|
+
parts.push(String(f.type));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
parts.push(f.nullable === false ? 'NOT NULL' : 'NULL');
|
|
33
|
+
return parts.join(' ');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function formatFieldLine(f) {
|
|
37
|
+
return ` - ${f.name} (${formatFieldSignature(f)})`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function formatColumns(cols) {
|
|
41
|
+
if (!Array.isArray(cols) || cols.length === 0) return '(empty)';
|
|
42
|
+
return cols.join(', ');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function formatFkLine(fk) {
|
|
46
|
+
if (!fk) return ' - (invalid)';
|
|
47
|
+
const refCol = fk.references ? `.${fk.references}` : '';
|
|
48
|
+
const actions = [];
|
|
49
|
+
if (fk.onDelete && fk.onDelete !== 'restrict') {
|
|
50
|
+
actions.push(`ON DELETE ${String(fk.onDelete).toUpperCase()}`);
|
|
51
|
+
}
|
|
52
|
+
if (fk.onUpdate && fk.onUpdate !== 'restrict') {
|
|
53
|
+
actions.push(`ON UPDATE ${String(fk.onUpdate).toUpperCase()}`);
|
|
54
|
+
}
|
|
55
|
+
const actionStr = actions.length > 0 ? ` [${actions.join(', ')}]` : '';
|
|
56
|
+
return ` - ${fk.localKey} -> ${fk.target}${refCol}${actionStr}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function formatFkMismatchedLine(fk) {
|
|
60
|
+
if (!fk) return ' - (invalid)';
|
|
61
|
+
const refCol = fk.references ? `.${fk.references}` : '';
|
|
62
|
+
const lines = [` - ${fk.localKey} -> ${fk.target}${refCol}`];
|
|
63
|
+
if (Array.isArray(fk.reasons)) {
|
|
64
|
+
for (const r of fk.reasons) {
|
|
65
|
+
lines.push(` ${r}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return lines.join('\n');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function formatCheckValue(value) {
|
|
72
|
+
if (Array.isArray(value)) {
|
|
73
|
+
const items = value.map((v) => (typeof v === 'string' ? `'${v}'` : String(v)));
|
|
74
|
+
return `[${items.join(', ')}]`;
|
|
75
|
+
}
|
|
76
|
+
if (typeof value === 'string') return `'${value}'`;
|
|
77
|
+
if (value === null || value === undefined) return 'null';
|
|
78
|
+
return String(value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function formatCheckLine(c) {
|
|
82
|
+
if (!c) return ' - (invalid)';
|
|
83
|
+
if (c._unparsable) return ` - (unparsable) ${c.expression}`;
|
|
84
|
+
return ` - ${c.field}: ${c.op} ${formatCheckValue(c.value)}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ─────────────────────────────────────────────────────────────
|
|
88
|
+
// Section builders (human format)
|
|
89
|
+
// ─────────────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
function buildFieldsSection(fields) {
|
|
92
|
+
const lines = ['Fields:'];
|
|
93
|
+
|
|
94
|
+
lines.push(' + Only in SDF:');
|
|
95
|
+
if (fields.onlyInSdf.length === 0) {
|
|
96
|
+
lines.push(' (none)');
|
|
97
|
+
} else {
|
|
98
|
+
for (const f of fields.onlyInSdf) lines.push(formatFieldLine(f));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
lines.push(' - Only in DB:');
|
|
102
|
+
if (fields.onlyInDb.length === 0) {
|
|
103
|
+
lines.push(' (none)');
|
|
104
|
+
} else {
|
|
105
|
+
for (const f of fields.onlyInDb) lines.push(formatFieldLine(f));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
lines.push(' ~ Mismatched:');
|
|
109
|
+
if (fields.mismatched.length === 0) {
|
|
110
|
+
lines.push(' (none)');
|
|
111
|
+
} else {
|
|
112
|
+
for (const m of fields.mismatched) {
|
|
113
|
+
lines.push(` - ${m.name}`);
|
|
114
|
+
for (const r of m.reasons) {
|
|
115
|
+
lines.push(` ${r}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return lines;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function buildPrimaryKeySection(pk) {
|
|
124
|
+
const lines = ['Primary Key:'];
|
|
125
|
+
if (pk.match) {
|
|
126
|
+
const cols = pk.sdf.length === 0 ? '(none)' : pk.sdf.join(', ');
|
|
127
|
+
lines.push(` Match: ${cols}`);
|
|
128
|
+
} else {
|
|
129
|
+
lines.push(` Mismatch:`);
|
|
130
|
+
lines.push(` SDF: ${formatColumns(pk.sdf)}`);
|
|
131
|
+
lines.push(` DB: ${formatColumns(pk.db)}`);
|
|
132
|
+
}
|
|
133
|
+
return lines;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function buildCollectionSection(label, coll, formatter, mismatchedFormatter) {
|
|
137
|
+
const isEmpty = coll.onlyInSdf.length === 0 && coll.onlyInDb.length === 0 && coll.mismatched.length === 0;
|
|
138
|
+
if (isEmpty) {
|
|
139
|
+
return [`${label}: (no drift)`];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const lines = [`${label}:`];
|
|
143
|
+
lines.push(' + Only in SDF:');
|
|
144
|
+
if (coll.onlyInSdf.length === 0) {
|
|
145
|
+
lines.push(' (none)');
|
|
146
|
+
} else {
|
|
147
|
+
for (const it of coll.onlyInSdf) lines.push(formatter(it));
|
|
148
|
+
}
|
|
149
|
+
lines.push(' - Only in DB:');
|
|
150
|
+
if (coll.onlyInDb.length === 0) {
|
|
151
|
+
lines.push(' (none)');
|
|
152
|
+
} else {
|
|
153
|
+
for (const it of coll.onlyInDb) lines.push(formatter(it));
|
|
154
|
+
}
|
|
155
|
+
lines.push(' ~ Mismatched:');
|
|
156
|
+
if (coll.mismatched.length === 0) {
|
|
157
|
+
lines.push(' (none)');
|
|
158
|
+
} else {
|
|
159
|
+
const useMismatch = typeof mismatchedFormatter === 'function' ? mismatchedFormatter : formatter;
|
|
160
|
+
for (const it of coll.mismatched) lines.push(useMismatch(it));
|
|
161
|
+
}
|
|
162
|
+
return lines;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function formatColumnItem(item) {
|
|
166
|
+
const cols = Array.isArray(item.columns) ? item.columns.join(', ') : '(empty)';
|
|
167
|
+
return ` - ${cols}`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function buildTableReport(delta, idx, total) {
|
|
171
|
+
const lines = [];
|
|
172
|
+
const banner = `Drift Report: ${delta.tableName} (${idx}/${total} table compared)`;
|
|
173
|
+
lines.push(banner);
|
|
174
|
+
lines.push('='.repeat(Math.max(banner.length, 30)));
|
|
175
|
+
lines.push('');
|
|
176
|
+
|
|
177
|
+
if (!delta.hasDrift) {
|
|
178
|
+
lines.push('No drift detected. SDF and database are in sync.');
|
|
179
|
+
return lines;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
lines.push(...buildFieldsSection(delta.fields));
|
|
183
|
+
lines.push('');
|
|
184
|
+
lines.push(...buildPrimaryKeySection(delta.primaryKey));
|
|
185
|
+
lines.push('');
|
|
186
|
+
lines.push(...buildCollectionSection('Indexes', delta.indexes, formatColumnItem));
|
|
187
|
+
lines.push('');
|
|
188
|
+
lines.push(...buildCollectionSection('Uniques', delta.uniques, formatColumnItem));
|
|
189
|
+
lines.push('');
|
|
190
|
+
lines.push(...buildCollectionSection('Foreign Keys', delta.foreignKeys, formatFkLine, formatFkMismatchedLine));
|
|
191
|
+
if (delta.checks) {
|
|
192
|
+
lines.push('');
|
|
193
|
+
lines.push(...buildCollectionSection('Checks', delta.checks, formatCheckLine));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return lines;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ─────────────────────────────────────────────────────────────
|
|
200
|
+
// Public API: human / json / exit code
|
|
201
|
+
// ─────────────────────────────────────────────────────────────
|
|
202
|
+
|
|
203
|
+
function reportHuman(deltas) {
|
|
204
|
+
const arr = Array.isArray(deltas) ? deltas : [];
|
|
205
|
+
const total = arr.length;
|
|
206
|
+
const tablesWithDrift = arr.filter((d) => d && d.hasDrift).length;
|
|
207
|
+
const tablesClean = total - tablesWithDrift;
|
|
208
|
+
|
|
209
|
+
const lines = [];
|
|
210
|
+
if (total === 0) {
|
|
211
|
+
lines.push('No tables compared. Schema set is empty.');
|
|
212
|
+
lines.push('Exit code: 0');
|
|
213
|
+
return lines.join('\n');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
for (let i = 0; i < arr.length; i++) {
|
|
217
|
+
const delta = arr[i];
|
|
218
|
+
lines.push(...buildTableReport(delta, i + 1, total));
|
|
219
|
+
if (i < arr.length - 1) {
|
|
220
|
+
lines.push('');
|
|
221
|
+
lines.push('');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
lines.push('');
|
|
226
|
+
lines.push(`Summary: ${tablesWithDrift} table${tablesWithDrift === 1 ? '' : 's'} with drift, ${tablesClean} clean`);
|
|
227
|
+
const exitCode = tablesWithDrift > 0 ? 1 : 0;
|
|
228
|
+
lines.push(`Exit code: ${exitCode}`);
|
|
229
|
+
|
|
230
|
+
return lines.join('\n');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function reportJson(deltas) {
|
|
234
|
+
const arr = Array.isArray(deltas) ? deltas : [];
|
|
235
|
+
const tablesWithDrift = arr.filter((d) => d && d.hasDrift).length;
|
|
236
|
+
const tablesClean = arr.length - tablesWithDrift;
|
|
237
|
+
const exitCode = tablesWithDrift > 0 ? 1 : 0;
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
version: '1.0',
|
|
241
|
+
summary: {
|
|
242
|
+
totalTables: arr.length,
|
|
243
|
+
tablesWithDrift,
|
|
244
|
+
tablesClean,
|
|
245
|
+
exitCode
|
|
246
|
+
},
|
|
247
|
+
tables: arr.map((d) => {
|
|
248
|
+
const out = {
|
|
249
|
+
tableName: d.tableName,
|
|
250
|
+
hasDrift: d.hasDrift,
|
|
251
|
+
fields: d.fields,
|
|
252
|
+
primaryKey: d.primaryKey,
|
|
253
|
+
indexes: d.indexes,
|
|
254
|
+
uniques: d.uniques,
|
|
255
|
+
foreignKeys: d.foreignKeys
|
|
256
|
+
};
|
|
257
|
+
if (d.checks) out.checks = d.checks;
|
|
258
|
+
return out;
|
|
259
|
+
})
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function getExitCode(deltas) {
|
|
264
|
+
const arr = Array.isArray(deltas) ? deltas : [];
|
|
265
|
+
return arr.some((d) => d && d.hasDrift) ? 1 : 0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
module.exports = {
|
|
269
|
+
reportHuman,
|
|
270
|
+
reportJson,
|
|
271
|
+
getExitCode
|
|
272
|
+
};
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ALTER TABLE Emitters — generate dialect-aware DDL fragments untuk apply-engine.
|
|
5
|
+
*
|
|
6
|
+
* Lingkup:
|
|
7
|
+
* - ADD COLUMN <name> <type> [NULL|NOT NULL] [DEFAULT ...]
|
|
8
|
+
* - DROP COLUMN <name>
|
|
9
|
+
* - ALTER/MODIFY COLUMN <name> ... (length / nullable; type change defer)
|
|
10
|
+
* - CREATE INDEX
|
|
11
|
+
* - DROP INDEX (dialect-aware)
|
|
12
|
+
* - ADD CONSTRAINT UNIQUE
|
|
13
|
+
* - DROP CONSTRAINT
|
|
14
|
+
*
|
|
15
|
+
* Konvensi penamaan constraint/index reuse `naming.js` (generateConstraintName,
|
|
16
|
+
* deriveCompositeShortName) agar nama yang di-emit identik dengan create-table
|
|
17
|
+
* dan create-index. Output adalah string single-statement tanpa trailing
|
|
18
|
+
* semicolon (apply-executor / statement-splitter yang menangani separator).
|
|
19
|
+
*
|
|
20
|
+
* SQLite tidak mendukung ALTER COLUMN / DROP COLUMN (legacy mode). Modul ini
|
|
21
|
+
* tetap mendukung ADD COLUMN dan CREATE INDEX/DROP INDEX untuk sqlite; semua
|
|
22
|
+
* operasi MODIFY column dan DROP COLUMN harus dicegah di apply-engine sebelum
|
|
23
|
+
* sampai ke emitter.
|
|
24
|
+
*
|
|
25
|
+
* @module lib/dbschema-kit/emitters/alter-table
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const { generateConstraintName, deriveCompositeShortName } = require('../naming');
|
|
29
|
+
|
|
30
|
+
// ─────────────────────────────────────────────────────────────
|
|
31
|
+
// ADD COLUMN
|
|
32
|
+
// ─────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
function emitAddColumn(tableIR, fieldName, field, dialect) {
|
|
35
|
+
if (!tableIR || typeof tableIR.tableName !== 'string') {
|
|
36
|
+
throw new Error('emitAddColumn: tableIR with tableName is required');
|
|
37
|
+
}
|
|
38
|
+
if (typeof fieldName !== 'string' || fieldName === '') {
|
|
39
|
+
throw new Error('emitAddColumn: fieldName must be a non-empty string');
|
|
40
|
+
}
|
|
41
|
+
if (!field || typeof field !== 'object') {
|
|
42
|
+
throw new Error(`emitAddColumn: field definition required for '${fieldName}'`);
|
|
43
|
+
}
|
|
44
|
+
const tableIdentifier = dialect.formatTableIdentifier(tableIR);
|
|
45
|
+
const column = dialect.quoteIdentifier(fieldName);
|
|
46
|
+
const typeFrag = dialect.mapType(field);
|
|
47
|
+
const parts = [column, typeFrag];
|
|
48
|
+
if (field.notnull === true) {
|
|
49
|
+
parts.push('NOT NULL');
|
|
50
|
+
}
|
|
51
|
+
if (field.default !== undefined && field.autoUpdate !== true) {
|
|
52
|
+
parts.push(`DEFAULT ${dialect.formatDefault(field.default)}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (dialect.name === 'oracle') {
|
|
56
|
+
// Oracle membungkus column definition di dalam parentheses untuk ADD,
|
|
57
|
+
// konvensi yang juga mendukung multi-column add bila diperlukan nanti.
|
|
58
|
+
return `ALTER TABLE ${tableIdentifier} ADD (${parts.join(' ')})`;
|
|
59
|
+
}
|
|
60
|
+
return `ALTER TABLE ${tableIdentifier} ADD COLUMN ${parts.join(' ')}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ─────────────────────────────────────────────────────────────
|
|
64
|
+
// DROP COLUMN
|
|
65
|
+
// ─────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
function emitDropColumn(tableIR, fieldName, dialect) {
|
|
68
|
+
if (!tableIR || typeof tableIR.tableName !== 'string') {
|
|
69
|
+
throw new Error('emitDropColumn: tableIR with tableName is required');
|
|
70
|
+
}
|
|
71
|
+
if (typeof fieldName !== 'string' || fieldName === '') {
|
|
72
|
+
throw new Error('emitDropColumn: fieldName must be a non-empty string');
|
|
73
|
+
}
|
|
74
|
+
if (dialect.name === 'sqlite') {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`emitDropColumn: sqlite does not support DROP COLUMN reliably (requires table rebuild). ` +
|
|
77
|
+
`Filter DROP COLUMN operations in apply-engine before calling emitter.`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const tableIdentifier = dialect.formatTableIdentifier(tableIR);
|
|
81
|
+
const column = dialect.quoteIdentifier(fieldName);
|
|
82
|
+
if (dialect.name === 'oracle') {
|
|
83
|
+
return `ALTER TABLE ${tableIdentifier} DROP (${column})`;
|
|
84
|
+
}
|
|
85
|
+
return `ALTER TABLE ${tableIdentifier} DROP COLUMN ${column}`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ─────────────────────────────────────────────────────────────
|
|
89
|
+
// MODIFY COLUMN (length / nullable)
|
|
90
|
+
// ─────────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Generate ALTER COLUMN statement(s) untuk modifikasi length / nullable.
|
|
94
|
+
*
|
|
95
|
+
* Modify ini bersifat dialect-specific. Type change TIDAK di-handle (defer).
|
|
96
|
+
*
|
|
97
|
+
* @param {Object} tableIR - { tableName, schemaName? }
|
|
98
|
+
* @param {string} fieldName
|
|
99
|
+
* @param {Object} sdfField - target shape (type, length, notnull, dll.)
|
|
100
|
+
* @param {Object} options - { changeNullable: boolean, changeLength: boolean }
|
|
101
|
+
* @param {Object} dialect - dialect adapter
|
|
102
|
+
* @returns {string[]} array of ALTER statement (postgres bisa multiple,
|
|
103
|
+
* mysql/oracle satu statement MODIFY)
|
|
104
|
+
*/
|
|
105
|
+
function emitModifyColumn(tableIR, fieldName, sdfField, options, dialect) {
|
|
106
|
+
if (!tableIR || typeof tableIR.tableName !== 'string') {
|
|
107
|
+
throw new Error('emitModifyColumn: tableIR with tableName is required');
|
|
108
|
+
}
|
|
109
|
+
if (typeof fieldName !== 'string' || fieldName === '') {
|
|
110
|
+
throw new Error('emitModifyColumn: fieldName must be a non-empty string');
|
|
111
|
+
}
|
|
112
|
+
if (!sdfField || typeof sdfField !== 'object') {
|
|
113
|
+
throw new Error(`emitModifyColumn: sdfField required for '${fieldName}'`);
|
|
114
|
+
}
|
|
115
|
+
const changeNullable = options && options.changeNullable === true;
|
|
116
|
+
const changeLength = options && options.changeLength === true;
|
|
117
|
+
if (!changeNullable && !changeLength) {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (dialect.name === 'sqlite') {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`emitModifyColumn: sqlite does not support ALTER COLUMN. ` +
|
|
124
|
+
`Filter modify operations in apply-engine before calling emitter.`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const tableIdentifier = dialect.formatTableIdentifier(tableIR);
|
|
129
|
+
const column = dialect.quoteIdentifier(fieldName);
|
|
130
|
+
|
|
131
|
+
if (dialect.name === 'postgres') {
|
|
132
|
+
const out = [];
|
|
133
|
+
if (changeLength) {
|
|
134
|
+
const typeFrag = dialect.mapType(sdfField);
|
|
135
|
+
out.push(`ALTER TABLE ${tableIdentifier} ALTER COLUMN ${column} TYPE ${typeFrag}`);
|
|
136
|
+
}
|
|
137
|
+
if (changeNullable) {
|
|
138
|
+
if (sdfField.notnull === true) {
|
|
139
|
+
out.push(`ALTER TABLE ${tableIdentifier} ALTER COLUMN ${column} SET NOT NULL`);
|
|
140
|
+
} else {
|
|
141
|
+
out.push(`ALTER TABLE ${tableIdentifier} ALTER COLUMN ${column} DROP NOT NULL`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (dialect.name === 'mysql') {
|
|
148
|
+
const typeFrag = dialect.mapType(sdfField);
|
|
149
|
+
const parts = [column, typeFrag];
|
|
150
|
+
if (sdfField.notnull === true) parts.push('NOT NULL');
|
|
151
|
+
else parts.push('NULL');
|
|
152
|
+
return [`ALTER TABLE ${tableIdentifier} MODIFY COLUMN ${parts.join(' ')}`];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (dialect.name === 'oracle') {
|
|
156
|
+
const typeFrag = dialect.mapType(sdfField);
|
|
157
|
+
const parts = [column, typeFrag];
|
|
158
|
+
if (sdfField.notnull === true) parts.push('NOT NULL');
|
|
159
|
+
else parts.push('NULL');
|
|
160
|
+
return [`ALTER TABLE ${tableIdentifier} MODIFY (${parts.join(' ')})`];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
throw new Error(`emitModifyColumn: unsupported dialect '${dialect.name}'`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ─────────────────────────────────────────────────────────────
|
|
167
|
+
// CREATE / DROP INDEX
|
|
168
|
+
// ─────────────────────────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
function deriveIndexName(tableName, columns, dialect) {
|
|
171
|
+
const composite = Array.isArray(columns) && columns.length > 1;
|
|
172
|
+
const suffix = composite
|
|
173
|
+
? deriveCompositeShortName(columns, dialect.maxIdentifierLength)
|
|
174
|
+
: columns[0];
|
|
175
|
+
return generateConstraintName('idx', tableName, suffix, dialect.maxIdentifierLength);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function emitCreateIndex(tableIR, columns, dialect) {
|
|
179
|
+
if (!tableIR || typeof tableIR.tableName !== 'string') {
|
|
180
|
+
throw new Error('emitCreateIndex: tableIR with tableName is required');
|
|
181
|
+
}
|
|
182
|
+
if (!Array.isArray(columns) || columns.length === 0) {
|
|
183
|
+
throw new Error('emitCreateIndex: columns must be a non-empty array');
|
|
184
|
+
}
|
|
185
|
+
const tableIdentifier = dialect.formatTableIdentifier(tableIR);
|
|
186
|
+
const name = deriveIndexName(tableIR.tableName, columns, dialect);
|
|
187
|
+
const colList = columns.map((c) => dialect.quoteIdentifier(c)).join(', ');
|
|
188
|
+
return `CREATE INDEX ${dialect.quoteIdentifier(name)} ON ${tableIdentifier} (${colList})`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function emitDropIndex(tableIR, columns, dialect, options) {
|
|
192
|
+
if (!tableIR || typeof tableIR.tableName !== 'string') {
|
|
193
|
+
throw new Error('emitDropIndex: tableIR with tableName is required');
|
|
194
|
+
}
|
|
195
|
+
if (!Array.isArray(columns) || columns.length === 0) {
|
|
196
|
+
throw new Error('emitDropIndex: columns must be a non-empty array');
|
|
197
|
+
}
|
|
198
|
+
const explicitName = options && typeof options.name === 'string' && options.name.length > 0
|
|
199
|
+
? options.name
|
|
200
|
+
: null;
|
|
201
|
+
const name = explicitName || deriveIndexName(tableIR.tableName, columns, dialect);
|
|
202
|
+
const quotedName = dialect.quoteIdentifier(name);
|
|
203
|
+
const tableIdentifier = dialect.formatTableIdentifier(tableIR);
|
|
204
|
+
|
|
205
|
+
switch (dialect.name) {
|
|
206
|
+
case 'postgres':
|
|
207
|
+
case 'sqlite':
|
|
208
|
+
// PG/SQLite: DROP INDEX adalah top-level object, tidak butuh ON clause.
|
|
209
|
+
return `DROP INDEX ${quotedName}`;
|
|
210
|
+
case 'mysql':
|
|
211
|
+
// MySQL: DROP INDEX adalah operasi pada table, butuh ON.
|
|
212
|
+
return `DROP INDEX ${quotedName} ON ${tableIdentifier}`;
|
|
213
|
+
case 'oracle':
|
|
214
|
+
// Oracle: DROP INDEX adalah top-level object.
|
|
215
|
+
return `DROP INDEX ${quotedName}`;
|
|
216
|
+
default:
|
|
217
|
+
throw new Error(`emitDropIndex: unsupported dialect '${dialect.name}'`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ─────────────────────────────────────────────────────────────
|
|
222
|
+
// ADD / DROP UNIQUE CONSTRAINT
|
|
223
|
+
// ─────────────────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
function deriveUniqueConstraintName(tableName, columns, dialect) {
|
|
226
|
+
const suffix = columns.length > 1
|
|
227
|
+
? deriveCompositeShortName(columns, dialect.maxIdentifierLength)
|
|
228
|
+
: columns[0];
|
|
229
|
+
return generateConstraintName('uq', tableName, suffix, dialect.maxIdentifierLength);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function emitAddUnique(tableIR, columns, dialect) {
|
|
233
|
+
if (!tableIR || typeof tableIR.tableName !== 'string') {
|
|
234
|
+
throw new Error('emitAddUnique: tableIR with tableName is required');
|
|
235
|
+
}
|
|
236
|
+
if (!Array.isArray(columns) || columns.length === 0) {
|
|
237
|
+
throw new Error('emitAddUnique: columns must be a non-empty array');
|
|
238
|
+
}
|
|
239
|
+
const tableIdentifier = dialect.formatTableIdentifier(tableIR);
|
|
240
|
+
const name = deriveUniqueConstraintName(tableIR.tableName, columns, dialect);
|
|
241
|
+
const colList = columns.map((c) => dialect.quoteIdentifier(c)).join(', ');
|
|
242
|
+
return `ALTER TABLE ${tableIdentifier} ADD CONSTRAINT ${dialect.quoteIdentifier(name)} UNIQUE (${colList})`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function emitDropUnique(tableIR, columns, dialect, options) {
|
|
246
|
+
if (!tableIR || typeof tableIR.tableName !== 'string') {
|
|
247
|
+
throw new Error('emitDropUnique: tableIR with tableName is required');
|
|
248
|
+
}
|
|
249
|
+
if (!Array.isArray(columns) || columns.length === 0) {
|
|
250
|
+
throw new Error('emitDropUnique: columns must be a non-empty array');
|
|
251
|
+
}
|
|
252
|
+
const explicitName = options && typeof options.name === 'string' && options.name.length > 0
|
|
253
|
+
? options.name
|
|
254
|
+
: null;
|
|
255
|
+
const name = explicitName || deriveUniqueConstraintName(tableIR.tableName, columns, dialect);
|
|
256
|
+
const tableIdentifier = dialect.formatTableIdentifier(tableIR);
|
|
257
|
+
|
|
258
|
+
if (dialect.name === 'mysql') {
|
|
259
|
+
// MySQL menyimpan UNIQUE sebagai index, syntax DROP INDEX adalah idiomatic.
|
|
260
|
+
return `ALTER TABLE ${tableIdentifier} DROP INDEX ${dialect.quoteIdentifier(name)}`;
|
|
261
|
+
}
|
|
262
|
+
return `ALTER TABLE ${tableIdentifier} DROP CONSTRAINT ${dialect.quoteIdentifier(name)}`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
module.exports = {
|
|
266
|
+
emitAddColumn,
|
|
267
|
+
emitDropColumn,
|
|
268
|
+
emitModifyColumn,
|
|
269
|
+
emitCreateIndex,
|
|
270
|
+
emitDropIndex,
|
|
271
|
+
emitAddUnique,
|
|
272
|
+
emitDropUnique,
|
|
273
|
+
deriveIndexName,
|
|
274
|
+
deriveUniqueConstraintName
|
|
275
|
+
};
|