diff --git a/buildConstants.js b/buildConstants.js index c8061cf..ce81025 100644 --- a/buildConstants.js +++ b/buildConstants.js @@ -23,6 +23,7 @@ const EXCLUDED_FILES = [ 'node_modules', 'lint-staged.config.js', 'scripts', + 'test', ]; module.exports = { diff --git a/forward_engineering/ddlProvider/ddlHelpers/columnDefinition/getColumnConstraints.js b/forward_engineering/ddlProvider/ddlHelpers/columnDefinition/getColumnConstraints.js index ffafc2e..76dce71 100644 --- a/forward_engineering/ddlProvider/ddlHelpers/columnDefinition/getColumnConstraints.js +++ b/forward_engineering/ddlProvider/ddlHelpers/columnDefinition/getColumnConstraints.js @@ -46,23 +46,31 @@ const getConstraintName = ({ unique, primaryKey, primaryKeyOptions, uniqueKeyOpt return trim(options.constraintName) || getDefaultConstraintName({ entityName, postfix }); }; +/** + * Build the column nullability clause. + * + * @param {{ nullable?: boolean }} params Column nullability. + * @returns {string} Nullability DDL fragment. + */ +const getColumnNullability = ({ nullable }) => (nullable ? '' : ' NOT NULL'); + /** * Build column constraint clauses. * * @param {ColumnConstraintParams} params Column constraint flags. * @returns {string} Constraints DDL fragment. */ -const getColumnConstraints = ({ nullable, unique, primaryKey, primaryKeyOptions, uniqueKeyOptions, entityName }) => { +const getColumnConstraints = ({ unique, primaryKey, primaryKeyOptions, uniqueKeyOptions, entityName }) => { const { constraintString, statement } = getOptionsString({ ...getOptions({ primaryKey, unique, primaryKeyOptions, uniqueKeyOptions }), constraintName: getConstraintName({ unique, primaryKey, primaryKeyOptions, uniqueKeyOptions, entityName }), }); const primaryKeyString = primaryKey ? ` PRIMARY KEY` : ''; const uniqueKeyString = unique ? ` UNIQUE` : ''; - const nullableString = nullable ? '' : ' NOT NULL'; - return `${nullableString}${constraintString}${primaryKeyString}${uniqueKeyString}${statement}`; + return `${constraintString}${primaryKeyString}${uniqueKeyString}${statement}`; }; module.exports = { + getColumnNullability, getColumnConstraints, }; diff --git a/forward_engineering/ddlProvider/ddlProvider.js b/forward_engineering/ddlProvider/ddlProvider.js index 45455d0..e828925 100644 --- a/forward_engineering/ddlProvider/ddlProvider.js +++ b/forward_engineering/ddlProvider/ddlProvider.js @@ -44,7 +44,7 @@ const { assignTemplates } = require('../utils/assignTemplates'); const keyHelper = require('./ddlHelpers/key/keyHelper.js'); const { getColumnType } = require('./ddlHelpers/columnDefinition/getColumnType.js'); const { getColumnDefault } = require('./ddlHelpers/columnDefinition/getColumnDefault.js'); -const { getColumnConstraints } = require('./ddlHelpers/columnDefinition/getColumnConstraints.js'); +const { getColumnNullability, getColumnConstraints } = require('./ddlHelpers/columnDefinition/getColumnConstraints.js'); const { getTableCommentStatement, getColumnComments, @@ -282,6 +282,7 @@ const convertColumnDefinition = (columnDefinition, template = templates.columnDe templateData: { name: wrapInQuotes(columnDefinition.name), type: getColumnType(columnDefinition), + nullability: getColumnNullability(columnDefinition), default: getColumnDefault(columnDefinition), constraints: getColumnConstraints(columnDefinition), }, diff --git a/forward_engineering/ddlProvider/templates.js b/forward_engineering/ddlProvider/templates.js index e92a4f3..2719940 100644 --- a/forward_engineering/ddlProvider/templates.js +++ b/forward_engineering/ddlProvider/templates.js @@ -27,7 +27,7 @@ module.exports = { createTableProps: '${columns}${keyConstraints}${checkConstraints}${foreignKeyConstraints}', - columnDefinition: '${name}${type}${default}${constraints}', + columnDefinition: '${name}${type}${nullability}${default}${constraints}', createForeignKey: 'ALTER TABLE ${foreignTable} ADD CONSTRAINT ${name} FOREIGN KEY (${foreignKey}) REFERENCES ${primaryTable} (${primaryKey})${onDelete};', diff --git a/package.json b/package.json index 52e01b2..3e88de2 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,8 @@ "pre-push": "npm run check" }, "scripts": { - "check": "npm run format:check && npm run lint && npm run types:check && npm run bundle:check", + "check": "npm run format:check && npm run lint && npm run types:check && npm test && npm run bundle:check", + "test": "node --test test/*.test.js", "types:check": "tsc --noEmit", "lint": "oxlint --type-aware --deny-warnings .", "bundle:check": "node esbuild.package.js --write=false", diff --git a/test/columnDefinition.test.js b/test/columnDefinition.test.js new file mode 100644 index 0000000..5f8ec4e --- /dev/null +++ b/test/columnDefinition.test.js @@ -0,0 +1,54 @@ +const assert = require('node:assert/strict'); +const { test } = require('node:test'); +const createDdlProvider = require('../forward_engineering/ddlProvider/ddlProvider'); + +const ddlProvider = createDdlProvider(null, null, null); + +void test('places NOT NULL before the ROWID generated clause', () => { + const columnDefinition = ddlProvider.convertColumnDefinition({ + name: 'row_id', + type: 'ROWID', + primaryKey: false, + unique: false, + nullable: false, + generated: 'ALWAYS', + isActivated: true, + }); + + assert.equal(columnDefinition, '"row_id" ROWID NOT NULL GENERATED ALWAYS'); +}); + +void test('places NOT NULL before a column default', () => { + const columnDefinition = ddlProvider.convertColumnDefinition({ + name: 'count', + type: 'INTEGER', + primaryKey: false, + unique: false, + nullable: false, + default: 0, + isActivated: true, + }); + + assert.equal(columnDefinition, '"count" INTEGER NOT NULL WITH DEFAULT 0'); +}); + +void test('keeps inline key constraints after identity generation', () => { + const columnDefinition = ddlProvider.convertColumnDefinition({ + name: 'id', + entityName: 'sample', + type: 'INTEGER', + primaryKey: true, + unique: false, + nullable: false, + isActivated: true, + identity: { + generated: 'ALWAYS', + start: 1, + }, + }); + + assert.equal( + columnDefinition, + '"id" INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1) CONSTRAINT "sample_pk" PRIMARY KEY', + ); +});