velocious 1.0.47 → 1.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/package.json +1 -1
  2. package/spec/cli/commands/db/migrate-spec.js +44 -6
  3. package/spec/dummy/src/database/migrations/20250916111330-rename_authentication_tokens_token_to_user_token.js +11 -0
  4. package/src/database/drivers/base-column.js +2 -3
  5. package/src/database/drivers/base-foreign-key.js +31 -0
  6. package/src/database/drivers/base-table.js +15 -1
  7. package/src/database/drivers/base.js +19 -1
  8. package/src/database/drivers/mssql/columns-index.js +1 -1
  9. package/src/database/drivers/mssql/foreign-key.js +2 -5
  10. package/src/database/drivers/mssql/index.js +7 -5
  11. package/src/database/drivers/mssql/table.js +36 -0
  12. package/src/database/drivers/mysql/column.js +4 -3
  13. package/src/database/drivers/mysql/foreign-key.js +2 -5
  14. package/src/database/drivers/mysql/table.js +41 -0
  15. package/src/database/drivers/pgsql/foreign-key.js +2 -5
  16. package/src/database/drivers/pgsql/table.js +32 -2
  17. package/src/database/drivers/sqlite/columns-index.js +2 -2
  18. package/src/database/drivers/sqlite/foreign-key.js +8 -7
  19. package/src/database/drivers/sqlite/index.web.js +3 -1
  20. package/src/database/drivers/sqlite/sql/alter-table.js +77 -6
  21. package/src/database/migration/index.js +21 -12
  22. package/src/database/query/alter-table-base.js +6 -1
  23. package/src/database/query/create-index-base.js +28 -4
  24. package/src/database/query/create-table-base.js +14 -2
  25. package/src/database/table-data/index.js +12 -150
  26. package/src/database/table-data/table-column.js +145 -0
  27. package/src/database/table-data/table-foreign-key.js +21 -0
  28. package/src/database/table-data/table-index.js +18 -0
  29. package/src/database/table-data/table-reference.js +6 -0
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.47",
6
+ "version": "1.0.48",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "test": "VELOCIOUS_TEST_DIR=../ cd spec/dummy && npx velocious test",
@@ -40,15 +40,43 @@ describe("Cli - Commands - db:migrate", () => {
40
40
  }
41
41
  }
42
42
 
43
- // It creates unique indexes
43
+ // It creates the correct index
44
44
  const authenticationTokensTable = await dbs.default.getTableByName("authentication_tokens")
45
- const tokenColumn = await authenticationTokensTable.getColumnByName("token")
46
- const tokenIndex = await tokenColumn.getIndexByName("index_on_authentication_tokens_token")
45
+ const indexes = await authenticationTokensTable.getIndexes()
46
+ const indexesNames = indexes
47
+ .map((index) => index.getName())
48
+ .filter((indexName) => indexName != "authentication_tokens_pkey" && indexName != "PRIMARY" && !indexName.startsWith("PK__"))
49
+ .sort()
50
+
51
+ if (defaultDatabaseType == "mysql") {
52
+ expect(indexesNames).toEqual(["index_on_token","user_id"])
53
+ } else if (defaultDatabaseType == "sqlite") {
54
+ expect(indexesNames).toEqual(["index_on_authentication_tokens_token", "index_on_authentication_tokens_user_id"])
55
+ } else {
56
+ expect(indexesNames).toEqual(["index_on_token", "index_on_user_id"])
57
+ }
47
58
 
48
- expect(tokenIndex.getName()).toEqual("index_on_authentication_tokens_token")
59
+ // It creates unique indexes
60
+ let tokenIndexName
61
+
62
+ if (defaultDatabaseType == "sqlite") {
63
+ tokenIndexName = "index_on_authentication_tokens_token"
64
+ } else {
65
+ tokenIndexName = "index_on_token"
66
+ }
67
+
68
+ const tokenColumn = await authenticationTokensTable.getColumnByName("user_token")
69
+ const tokenIndex = await tokenColumn.getIndexByName(tokenIndexName)
70
+
71
+ expect(tokenIndex.getName()).toEqual(tokenIndexName)
49
72
  expect(tokenIndex.isPrimaryKey()).toBeFalse()
50
73
  expect(tokenIndex.isUnique()).toBeTrue()
51
74
 
75
+ // It creates foreign keys
76
+ const authTokensTableForeignKeys = await authenticationTokensTable.getForeignKeys()
77
+
78
+ expect(authTokensTableForeignKeys.length).toEqual(1)
79
+
52
80
  for (const db of Object.values(dbs)) {
53
81
  const schemaMigrations = await db.query("SELECT * FROM schema_migrations ORDER BY version")
54
82
 
@@ -89,7 +117,8 @@ describe("Cli - Commands - db:migrate", () => {
89
117
  "20250903112845",
90
118
  "20250912183605",
91
119
  "20250912183606",
92
- "20250915085450"
120
+ "20250915085450",
121
+ "20250916111330"
93
122
  ])
94
123
  } else {
95
124
  expect(tablesResult.sort()).toEqual(
@@ -105,7 +134,16 @@ describe("Cli - Commands - db:migrate", () => {
105
134
  ]
106
135
  )
107
136
 
108
- expect(defaultSchemaMigrations.sort()).toEqual(["20230728075328", "20230728075329", "20250605133926", "20250903112845", "20250912183605", "20250912183606", "20250915085450"])
137
+ expect(defaultSchemaMigrations.sort()).toEqual([
138
+ "20230728075328",
139
+ "20230728075329",
140
+ "20250605133926",
141
+ "20250903112845",
142
+ "20250912183605",
143
+ "20250912183606",
144
+ "20250915085450",
145
+ "20250916111330"
146
+ ])
109
147
  }
110
148
  })
111
149
  })
@@ -0,0 +1,11 @@
1
+ import Migration from "../../../../../src/database/migration/index.js"
2
+
3
+ export default class RenameAuthenticationTokensTokenToUserToken extends Migration {
4
+ async up() {
5
+ await this.renameColumn("authentication_tokens", "token", "user_token")
6
+ }
7
+
8
+ async down() {
9
+ await this.renameColumn("authentication_tokens", "user_token", "token")
10
+ }
11
+ }
@@ -1,4 +1,5 @@
1
- import TableData, {TableColumn} from "../table-data/index.js"
1
+ import TableColumn from "../table-data/table-column.js"
2
+ import TableData from "../table-data/index.js"
2
3
 
3
4
  export default class VelociousDatabaseDriversBaseColumn {
4
5
  async getIndexByName(indexName) {
@@ -18,8 +19,6 @@ export default class VelociousDatabaseDriversBaseColumn {
18
19
 
19
20
  const sqls = await this.getDriver().alterTableSql(tableData)
20
21
 
21
- console.log({sqls})
22
-
23
22
  for (const sql of sqls) {
24
23
  await this.getDriver().query(sql)
25
24
  }
@@ -0,0 +1,31 @@
1
+ import TableForeignKey from "../table-data/table-foreign-key.js"
2
+
3
+ export default class VelociousDatabaseDriversBaseForeignKey {
4
+ constructor(data) {
5
+ this.data = data
6
+ }
7
+
8
+ getDriver() {
9
+ return this.getTable().getDriver()
10
+ }
11
+
12
+ getOptions() {
13
+ return this.getDriver().options()
14
+ }
15
+
16
+ getTable() {
17
+ if (!this.table) throw new Error("No table set on column")
18
+
19
+ return this.table
20
+ }
21
+
22
+ getTableDataForeignKey() {
23
+ return new TableForeignKey({
24
+ columnName: this.getColumnName(),
25
+ name: this.getName(),
26
+ tableName: this.getTableName(),
27
+ referencedColumnName: this.getReferencedColumnName(),
28
+ referencedTableName: this.getReferencedTableName()
29
+ })
30
+ }
31
+ }
@@ -21,9 +21,23 @@ export default class VelociousDatabaseDriversBaseTable {
21
21
 
22
22
  async getTableData() {
23
23
  const tableData = new TableData(this.getName())
24
+ const tableDataColumns = []
24
25
 
25
26
  for (const column of await this.getColumns()) {
26
- tableData.addColumn(column.getTableDataColumn())
27
+ const tableDataColumn = column.getTableDataColumn()
28
+
29
+ tableData.addColumn(tableDataColumn)
30
+ tableDataColumns.push(tableDataColumn)
31
+ }
32
+
33
+ for (const foreignKey of await this.getForeignKeys()) {
34
+ tableData.addForeignKey(foreignKey.getTableDataForeignKey())
35
+
36
+ const tableDataColumn = tableDataColumns.find((tableDataColumn) => tableDataColumn.getName() == foreignKey.getColumnName())
37
+
38
+ if (!tableDataColumn) throw new Error(`Couldn't find table data column for foreign key: ${foreignKey.getColumnName()}`)
39
+
40
+ tableDataColumn.setForeignKey(foreignKey)
27
41
  }
28
42
 
29
43
  for (const index of await this.getIndexes()) {
@@ -3,6 +3,8 @@ import Query from "../query/index.js"
3
3
  import Handler from "../handler.js"
4
4
  import strftime from "strftime"
5
5
  import UUID from "pure-uuid"
6
+ import TableData from "../table-data/index.js"
7
+ import TableColumn from "../table-data/table-column.js"
6
8
 
7
9
  export default class VelociousDatabaseDriversBase {
8
10
  constructor(config, configuration) {
@@ -42,7 +44,7 @@ export default class VelociousDatabaseDriversBase {
42
44
  if (!this.configuration) throw new Error("No configuration set")
43
45
 
44
46
  return this.configuration
45
- }
47
+ }
46
48
 
47
49
  getIdSeq() {
48
50
  return this.idSeq
@@ -203,6 +205,22 @@ export default class VelociousDatabaseDriversBase {
203
205
  await this.query(`SAVEPOINT ${savePointName}`)
204
206
  }
205
207
 
208
+ async renameColumn(tableName, oldColumnName, newColumnName) {
209
+ const tableColumn = new TableColumn(oldColumnName)
210
+
211
+ tableColumn.setNewName(newColumnName)
212
+
213
+ const tableData = new TableData(tableName)
214
+
215
+ tableData.addColumn(tableColumn)
216
+
217
+ const alterTableSQLs = await this.alterTableSql(tableData)
218
+
219
+ for (const alterTableSQL of alterTableSQLs) {
220
+ await this.query(alterTableSQL)
221
+ }
222
+ }
223
+
206
224
  async releaseSavePoint(savePointName) {
207
225
  await this.query(`RELEASE SAVEPOINT ${savePointName}`)
208
226
  }
@@ -1,6 +1,6 @@
1
1
  import BaseColumnsIndex from "../base-columns-index.js"
2
2
 
3
- export default class VelociousDatabaseDriversMssqlColumn extends BaseColumnsIndex {
3
+ export default class VelociousDatabaseDriversMssqlColumnsIndex extends BaseColumnsIndex {
4
4
  constructor(table, data) {
5
5
  super()
6
6
  this.data = data
@@ -1,10 +1,7 @@
1
+ import BaseForeignKey from "../base-foreign-key.js"
1
2
  import {digg} from "diggerize"
2
3
 
3
- export default class VelociousDatabaseDriversMssqlForeignKey {
4
- constructor(data) {
5
- this.data = data
6
- }
7
-
4
+ export default class VelociousDatabaseDriversMssqlForeignKey extends BaseForeignKey {
8
5
  getColumnName = () => digg(this, "data", "ParentColumn")
9
6
  getName = () => digg(this, "data", "CONSTRAINT_NAME")
10
7
  getTableName = () => digg(this, "data", "TableName")
@@ -119,9 +119,7 @@ export default class VelociousDatabaseDriversMssql extends Base{
119
119
  return new QueryParser({query}).toSql()
120
120
  }
121
121
 
122
- shouldSetAutoIncrementWhenPrimaryKey = () => true
123
-
124
-
122
+ shouldSetAutoIncrementWhenPrimaryKey() { return true }
125
123
 
126
124
  escape(value) {
127
125
  value = this._convertValue(value)
@@ -147,8 +145,12 @@ export default class VelociousDatabaseDriversMssql extends Base{
147
145
  return escapeString(value)
148
146
  }
149
147
 
150
- quoteColumn = (string) => this.options().quoteColumnName(string)
151
- quoteTable = (string) => this.options().quoteTableName(string)
148
+ quoteColumn(string) { return this.options().quoteColumnName(string) }
149
+ quoteTable(string) { return this.options().quoteTableName(string) }
150
+
151
+ async renameColumn(tableName, oldColumnName, newColumnName) {
152
+ await this.query(`EXEC sp_rename ${this.quote(`${tableName}.${oldColumnName}`)}, ${this.quote(newColumnName)}, 'COLUMN'`)
153
+ }
152
154
 
153
155
  deleteSql({tableName, conditions}) {
154
156
  const deleteInstruction = new Delete({conditions, driver: this, tableName})
@@ -1,5 +1,6 @@
1
1
  import BaseTable from "../base-table.js"
2
2
  import Column from "./column.js"
3
+ import ColumnsIndex from "./columns-index.js"
3
4
  import {digg} from "diggerize"
4
5
  import ForeignKey from "./foreign-key.js"
5
6
 
@@ -61,6 +62,41 @@ export default class VelociousDatabaseDriversMssqlTable extends BaseTable {
61
62
  return foreignKeys
62
63
  }
63
64
 
65
+ async getIndexes() {
66
+ const options = this.getOptions()
67
+ const sql = `
68
+ SELECT
69
+ sys.tables.name AS TableName,
70
+ sys.columns.name AS ColumnName,
71
+ sys.indexes.name AS index_name,
72
+ sys.indexes.type_desc AS IndexType,
73
+ sys.index_columns.is_included_column AS IsIncludedColumn,
74
+ sys.indexes.is_unique,
75
+ sys.indexes.is_primary_key,
76
+ sys.indexes.is_unique_constraint
77
+ FROM sys.indexes
78
+ INNER JOIN sys.index_columns ON sys.indexes.object_id = sys.index_columns.object_id AND sys.indexes.index_id = sys.index_columns.index_id
79
+ INNER JOIN sys.columns ON sys.index_columns.object_id = sys.columns.object_id AND sys.index_columns.column_id = sys.columns.column_id
80
+ INNER JOIN sys.tables ON sys.indexes.object_id = sys.tables.object_id
81
+ WHERE
82
+ sys.tables.name = ${options.quote(this.getName())}
83
+ ORDER BY
84
+ sys.indexes.name,
85
+ sys.index_columns.key_ordinal
86
+ `
87
+
88
+ const rows = await this.getDriver().query(sql)
89
+ const indexes = []
90
+
91
+ for (const row of rows) {
92
+ const index = new ColumnsIndex(this, row)
93
+
94
+ indexes.push(index)
95
+ }
96
+
97
+ return indexes
98
+ }
99
+
64
100
  getName() {
65
101
  return digg(this.data, "TABLE_NAME")
66
102
  }
@@ -21,9 +21,10 @@ export default class VelociousDatabaseDriversMysqlColumn extends BaseColumn {
21
21
  NON_UNIQUE,
22
22
  INDEX_TYPE
23
23
  FROM INFORMATION_SCHEMA.STATISTICS
24
- WHERE TABLE_SCHEMA = DATABASE()
25
- AND TABLE_NAME = ${options.quote(this.table.getName())}
26
- AND COLUMN_NAME = ${options.quote(this.getName())}
24
+ WHERE
25
+ TABLE_SCHEMA = DATABASE() AND
26
+ TABLE_NAME = ${options.quote(this.table.getName())} AND
27
+ COLUMN_NAME = ${options.quote(this.getName())}
27
28
  `
28
29
  const indexesRows = await this.getDriver().query(sql)
29
30
  const indexes = []
@@ -1,10 +1,7 @@
1
+ import BaseForeignKey from "../base-foreign-key.js"
1
2
  import {digg} from "diggerize"
2
3
 
3
- export default class VelociousDatabaseDriversMysqlForeignKey {
4
- constructor(data) {
5
- this.data = data
6
- }
7
-
4
+ export default class VelociousDatabaseDriversMysqlForeignKey extends BaseForeignKey {
8
5
  getColumnName = () => digg(this, "data", "COLUMN_NAME")
9
6
  getName = () => digg(this, "data", "CONSTRAINT_NAME")
10
7
  getTableName = () => digg(this, "data", "TABLE_NAME")
@@ -1,5 +1,6 @@
1
1
  import BaseTable from "../base-table.js"
2
2
  import Column from "./column.js"
3
+ import ColumnsIndex from "./columns-index.js"
3
4
  import ForeignKey from "./foreign-key.js"
4
5
 
5
6
  export default class VelociousDatabaseDriversMysqlTable extends BaseTable {
@@ -43,6 +44,46 @@ export default class VelociousDatabaseDriversMysqlTable extends BaseTable {
43
44
  return foreignKeys
44
45
  }
45
46
 
47
+ async getIndexes() {
48
+ const options = this.getOptions()
49
+ const sql = `
50
+ SELECT
51
+ TABLE_SCHEMA,
52
+ TABLE_NAME,
53
+ INDEX_NAME AS index_name,
54
+ COLUMN_NAME,
55
+ SEQ_IN_INDEX,
56
+ NON_UNIQUE,
57
+ INDEX_TYPE
58
+ FROM INFORMATION_SCHEMA.STATISTICS
59
+ WHERE
60
+ TABLE_SCHEMA = DATABASE() AND
61
+ TABLE_NAME = ${options.quote(this.getName())}
62
+ `
63
+ const indexesRows = await this.getDriver().query(sql)
64
+ const indexes = []
65
+
66
+ for (const indexRow of indexesRows) {
67
+ if (indexRow.NON_UNIQUE == 1) {
68
+ indexRow.is_unique = false
69
+ } else {
70
+ indexRow.is_unique = true
71
+ }
72
+
73
+ if (indexRow.index_name == "PRIMARY") {
74
+ indexRow.is_primary_key = true
75
+ } else {
76
+ indexRow.is_primary_key = false
77
+ }
78
+
79
+ const index = new ColumnsIndex(this, indexRow)
80
+
81
+ indexes.push(index)
82
+ }
83
+
84
+ return indexes
85
+ }
86
+
46
87
  getName() {
47
88
  return Object.values(this.data)[0]
48
89
  }
@@ -1,10 +1,7 @@
1
+ import BaseForeignKey from "../base-foreign-key.js"
1
2
  import {digg} from "diggerize"
2
3
 
3
- export default class VelociousDatabaseDriversPgsqlForeignKey {
4
- constructor(data) {
5
- this.data = data
6
- }
7
-
4
+ export default class VelociousDatabaseDriversPgsqlForeignKey extends BaseForeignKey {
8
5
  getColumnName = () => digg(this, "data", "column_name")
9
6
  getName = () => digg(this, "data", "constraint_name")
10
7
  getTableName = () => digg(this, "data", "table_name")
@@ -1,5 +1,6 @@
1
1
  import BaseTable from "../base-table.js"
2
2
  import Column from "./column.js"
3
+ import ColumnsIndex from "./columns-index.js"
3
4
  import ForeignKey from "./foreign-key.js"
4
5
 
5
6
  export default class VelociousDatabaseDriversPgsqlTable extends BaseTable {
@@ -43,10 +44,10 @@ export default class VelociousDatabaseDriversPgsqlTable extends BaseTable {
43
44
  WHERE
44
45
  constraint_type = 'FOREIGN KEY' AND
45
46
  tc.table_catalog = CURRENT_DATABASE() AND
46
- tc.table_name = ${this.driver.quote(this.getName())}
47
+ tc.table_name = ${this.getDriver().quote(this.getName())}
47
48
  `
48
49
 
49
- const foreignKeyRows = await this.driver.query(sql)
50
+ const foreignKeyRows = await this.getDriver().query(sql)
50
51
  const foreignKeys = []
51
52
 
52
53
  for (const foreignKeyRow of foreignKeyRows) {
@@ -58,6 +59,35 @@ export default class VelociousDatabaseDriversPgsqlTable extends BaseTable {
58
59
  return foreignKeys
59
60
  }
60
61
 
62
+ async getIndexes() {
63
+ const options = this.getOptions()
64
+
65
+ const indexesRows = await this.getDriver().query(`
66
+ SELECT
67
+ pg_attribute.attname AS column_name,
68
+ pg_index.indexrelid::regclass as index_name,
69
+ pg_class.relnamespace::regnamespace as schema_name,
70
+ pg_class.relname as table_name,
71
+ pg_index.indisprimary as is_primary_key,
72
+ pg_index.indisunique as is_unique
73
+ FROM pg_index
74
+ JOIN pg_class ON pg_class.oid = pg_index.indrelid
75
+ JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid AND pg_attribute.attnum = ANY(pg_index.indkey)
76
+ WHERE
77
+ pg_class.relname = ${options.quote(this.getName())}
78
+ `)
79
+
80
+ const indexes = []
81
+
82
+ for (const indexRow of indexesRows) {
83
+ const columnsIndex = new ColumnsIndex(this, indexRow)
84
+
85
+ indexes.push(columnsIndex)
86
+ }
87
+
88
+ return indexes
89
+ }
90
+
61
91
  getName() {
62
92
  return this.data.table_name
63
93
  }
@@ -1,8 +1,8 @@
1
1
  import BaseColumnsIndex from "../base-columns-index.js"
2
2
  import {digg} from "diggerize"
3
- import {TableIndex} from "../../table-data/index.js"
3
+ import TableIndex from "../../table-data/table-index.js"
4
4
 
5
- export default class VelociousDatabaseDriversSqliteColumn extends BaseColumnsIndex {
5
+ export default class VelociousDatabaseDriversSqliteColumnsIndex extends BaseColumnsIndex {
6
6
  constructor(table, data) {
7
7
  super()
8
8
  this.data = data
@@ -1,14 +1,15 @@
1
+ import BaseForeignKey from "../base-foreign-key.js"
1
2
  import {digg} from "diggerize"
2
3
 
3
- export default class VelociousDatabaseDriversSqliteForeignKey {
4
+ export default class VelociousDatabaseDriversSqliteForeignKey extends BaseForeignKey {
4
5
  constructor(data, {tableName}) {
5
- this.data = data
6
+ super(data)
6
7
  this.tableName = tableName
7
8
  }
8
9
 
9
- getColumnName = () => digg(this, "data", "from")
10
- getName = () => `${this.getTableName()}_${this.getColumnName()}_${this.data.id}`
11
- getTableName = () => digg(this, "tableName")
12
- getReferencedColumnName = () => digg(this, "data", "to")
13
- getReferencedTableName = () => digg(this, "data", "table")
10
+ getColumnName() { return digg(this, "data", "from") }
11
+ getName() { return `${this.getTableName()}_${this.getColumnName()}_${this.data.id}` }
12
+ getTableName() { return digg(this, "tableName") }
13
+ getReferencedColumnName() { return digg(this, "data", "to") }
14
+ getReferencedTableName() { return digg(this, "data", "table") }
14
15
  }
@@ -45,5 +45,7 @@ export default class VelociousDatabaseDriversSqliteWeb extends Base {
45
45
  return `VelociousDatabaseDriversSqliteWeb---${this.args.name}`
46
46
  }
47
47
 
48
- query = async (sql) => await this.getConnection().query(sql)
48
+ query = async (sql) => {
49
+ return await this.getConnection().query(sql)
50
+ }
49
51
  }
@@ -1,6 +1,8 @@
1
1
  import AlterTableBase from "../../../query/alter-table-base.js"
2
2
  import CreateIndexBase from "../../../query/create-index-base.js"
3
3
  import {digs} from "diggerize"
4
+ import * as inflection from "inflection"
5
+ import {Logger} from "../../../../logger.js"
4
6
  import restArgsError from "../../../../utils/rest-args-error.js"
5
7
  import TableData from "../../../table-data/index.js"
6
8
 
@@ -11,6 +13,7 @@ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable exten
11
13
  if (!(tableData instanceof TableData)) throw new Error("Invalid table data was given")
12
14
 
13
15
  super({driver, tableData})
16
+ this.logger = new Logger(this)
14
17
  this.tableData = tableData
15
18
  }
16
19
 
@@ -21,7 +24,15 @@ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable exten
21
24
  const options = this.getOptions()
22
25
  const tableName = tableData.getName()
23
26
  const tempTableName = `${tableData.getName()}AlterTableTemp`
27
+ const newColumnNames = currentTableData.getColumns()
28
+ .filter((column) => !column.isNewColumn())
29
+ .map((column) => {
30
+ const newTableColumn = tableData.getColumns().find((tableColumn) => tableColumn.getName() == column.getName())
31
+
32
+ return newTableColumn?.getNewName() || newTableColumn?.getName() || column.getNewName() || column.getName()
33
+ })
24
34
  const oldColumnNames = currentTableData.getColumns().filter((column) => !column.isNewColumn()).map((column) => column.getName())
35
+ const newColumnsSQL = newColumnNames.map((name) => options.quoteColumnName(name)).join(", ")
25
36
  const oldColumnsSQL = oldColumnNames.map((name) => options.quoteColumnName(name)).join(", ")
26
37
 
27
38
  tableData.setName(tempTableName)
@@ -29,13 +40,71 @@ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable exten
29
40
  const newTableData = new TableData(tempTableName)
30
41
 
31
42
  for (const tableDataColumn of currentTableData.getColumns()) {
32
- const newTableDataColumn = newTableData.getColumns().find((newTableDataColumn) => newTableDataColumn.getName() == tableDataColumn.getName())
43
+ const newTableDataColumn = tableData.getColumns().find((newTableDataColumn) => newTableDataColumn.getName() == tableDataColumn.getName())
44
+
45
+ if (newTableDataColumn) {
46
+ const settingsToClone = ["autoIncrement", "default", "index", "foreignKey", "maxLength", "primaryKey", "type"]
47
+
48
+ for (const settingToClone of settingsToClone) {
49
+ const camelizedSettingToClone = inflection.camelize(settingToClone)
50
+
51
+ if (!newTableDataColumn[`get${camelizedSettingToClone}`]) {
52
+ throw new Error(`No such method on column: get${camelizedSettingToClone}`)
53
+ }
54
+
55
+ if (!newTableDataColumn[`get${camelizedSettingToClone}`]()) {
56
+ newTableDataColumn[`set${camelizedSettingToClone}`](tableDataColumn[`get${camelizedSettingToClone}`]())
57
+ }
58
+ }
59
+ }
33
60
 
34
61
  newTableData.addColumn(newTableDataColumn || tableDataColumn)
35
62
  }
36
63
 
64
+ for (const tableDataColumn of tableData.getColumns()) {
65
+ if (!tableDataColumn.isNewColumn()) continue
66
+
67
+ newTableData.addColumn(tableDataColumn)
68
+ }
69
+
70
+ const foundForeignKeys = []
71
+
72
+ for (const tableDataForeignKey of currentTableData.getForeignKeys()) {
73
+ const newTableDataForeignKey = newTableData.getForeignKeys().find((newTableDataForeignKey) => newTableDataForeignKey.getName() == tableDataForeignKey.getName())
74
+
75
+ if (newTableDataForeignKey) foundForeignKeys.push(newTableDataForeignKey.getName())
76
+
77
+ const actualTableDataForeignKey = newTableDataForeignKey || tableDataForeignKey
78
+
79
+ // Register foreign key on the table
80
+ newTableData.addForeignKey(actualTableDataForeignKey)
81
+
82
+ // Register foreign key on the column
83
+ const tableDataColumn = newTableData.getColumns().find((newTableDataColumn) => newTableDataColumn.getName() == actualTableDataForeignKey.getColumnName())
84
+
85
+ if (!tableDataColumn) throw new Error(`Couldn't find column for foreign key: ${actualTableDataForeignKey.getName()}`)
86
+
87
+ this.logger.debug(() => [`Setting foreign key on column ${tableDataColumn.getName()}`])
88
+ tableDataColumn.setForeignKey(actualTableDataForeignKey)
89
+ }
90
+
91
+ for (const foreignKey of tableData.getForeignKeys()) {
92
+ if (foundForeignKeys.includes(foreignKey.getName())) continue
93
+
94
+ // Register foreign key on the table
95
+ newTableData.addForeignKey(foreignKey)
96
+
97
+ // Register foreign key on the column
98
+ const tableDataColumn = newTableData.getColumns().find((newTableDataColumn) => newTableDataColumn.getName() == foreignKey.getColumnName())
99
+
100
+ if (!tableDataColumn) throw new Error(`Couldn't find column for foreign key: ${actualTableDataForeignKey.getName()}`)
101
+
102
+ this.logger.debug(() => [`Setting foreign key on column ${tableDataColumn.getName()}`])
103
+ tableDataColumn.setForeignKey(actualTableDataForeignKey)
104
+ }
105
+
37
106
  const createNewTableSQL = this.getDriver().createTableSql(newTableData)
38
- const insertSQL = `INSERT INTO ${options.quoteTableName(tempTableName)} (${oldColumnsSQL}) SELECT ${oldColumnsSQL} FROM ${options.quoteTableName(tableName)}`
107
+ const insertSQL = `INSERT INTO ${options.quoteTableName(tempTableName)} (${newColumnsSQL}) SELECT ${oldColumnsSQL} FROM ${options.quoteTableName(tableName)}`
39
108
  const dropTableSQL = `DROP TABLE ${options.quoteTableName(tableName)}`
40
109
  const renameTableSQL = `ALTER TABLE ${options.quoteTableName(tempTableName)} RENAME TO ${options.quoteTableName(tableName)}`
41
110
  const sqls = []
@@ -54,10 +123,14 @@ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable exten
54
123
 
55
124
  newTableData.addIndex(actualTableIndex)
56
125
 
57
- console.log({actualTableIndex})
126
+ const columnNames = actualTableIndex.getColumns().map((columnName) => {
127
+ const newTableColumn = tableData.getColumns().find((tableColumn) => tableColumn.getName() == columnName)
128
+
129
+ return newTableColumn?.getNewName() || newTableColumn?.getName() || columnName
130
+ })
58
131
 
59
132
  const createIndexArgs = {
60
- columns: actualTableIndex.getColumns(),
133
+ columns: columnNames,
61
134
  driver: this.getDriver(),
62
135
  name: actualTableIndex.getName(),
63
136
  tableName,
@@ -68,8 +141,6 @@ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable exten
68
141
  sqls.push(sql)
69
142
  }
70
143
 
71
- console.log({sqls})
72
-
73
144
  return sqls
74
145
  }
75
146
  }
@@ -1,6 +1,6 @@
1
1
  import * as inflection from "inflection"
2
2
  import restArgsError from "../../utils/rest-args-error.js"
3
- import TableData, {TableColumn} from "../table-data/index.js"
3
+ import TableData from "../table-data/index.js"
4
4
 
5
5
  export default class VelociousDatabaseMigration {
6
6
  static onDatabases(databaseIdentifiers) {
@@ -29,15 +29,17 @@ export default class VelociousDatabaseMigration {
29
29
  getDriver() { return this._db }
30
30
 
31
31
  async addColumn(tableName, columnName, columnType, args) {
32
- const tableColumnArgs = Object.assign({type: columnType}, args)
32
+ if (!columnType) throw new Error("No column type given")
33
+
34
+ const tableColumnArgs = Object.assign({isNewColumn: true, type: columnType}, args)
33
35
  const tableData = new TableData(tableName)
34
36
 
35
37
  tableData.addColumn(columnName, tableColumnArgs)
36
38
 
37
- const sqls = await this._db.alterTableSql(tableData)
39
+ const sqls = await this.getDriver().alterTableSql(tableData)
38
40
 
39
41
  for (const sql of sqls) {
40
- await this._db.query(sql)
42
+ await this.getDriver().query(sql)
41
43
  }
42
44
  }
43
45
 
@@ -49,9 +51,9 @@ export default class VelociousDatabaseMigration {
49
51
  },
50
52
  args
51
53
  )
52
- const sql = this._db.createIndexSql(createIndexArgs)
54
+ const sql = this.getDriver().createIndexSql(createIndexArgs)
53
55
 
54
- await this._db.query(sql)
56
+ await this.getDriver().query(sql)
55
57
  }
56
58
 
57
59
  async addForeignKey(tableName, referenceName) {
@@ -66,16 +68,19 @@ export default class VelociousDatabaseMigration {
66
68
  sql += ` FOREIGN KEY (${this._db.quoteColumn(columnName)})`
67
69
  sql += ` REFERENCES ${tableNameUnderscore}(id)`
68
70
 
69
- await this._db.query(sql)
71
+ await this.getDriver().query(sql)
70
72
  }
71
73
 
72
74
  async addReference(tableName, referenceName, args) {
75
+ const {foreignKey, type, unique, ...restArgs} = args
73
76
  const columnName = `${inflection.underscore(referenceName)}_id`
74
77
 
75
- await this.addColumn(tableName, columnName, {type: args?.type})
76
- await this.addIndex(tableName, [columnName], {unique: args?.unique})
78
+ restArgsError(restArgs)
79
+
80
+ await this.addColumn(tableName, columnName, type || "integer")
81
+ await this.addIndex(tableName, [columnName], {unique: unique})
77
82
 
78
- if (args?.foreignKey) {
83
+ if (foreignKey) {
79
84
  await this.addForeignKey(tableName, referenceName)
80
85
  }
81
86
  }
@@ -118,15 +123,19 @@ export default class VelociousDatabaseMigration {
118
123
  callback(tableData)
119
124
  }
120
125
 
121
- const sqls = this._db.createTableSql(tableData)
126
+ const sqls = this.getDriver().createTableSql(tableData)
122
127
 
123
128
  for (const sql of sqls) {
124
129
  await this._db.query(sql)
125
130
  }
126
131
  }
127
132
 
133
+ async renameColumn(tableName, oldColumnName, newColumnName) {
134
+ await this.getDriver().renameColumn(tableName, oldColumnName, newColumnName)
135
+ }
136
+
128
137
  async tableExists(tableName) {
129
- const exists = await this._db.tableExists(tableName)
138
+ const exists = await this.getDriver().tableExists(tableName)
130
139
 
131
140
  return exists
132
141
  }
@@ -27,15 +27,20 @@ export default class VelociousDatabaseQueryAlterTableBase extends QueryBase {
27
27
 
28
28
  if (column.isNewColumn()) {
29
29
  sql += "ADD "
30
+ sql += column.getSQL({driver: this.getDriver(), forAlterTable: true})
31
+ } else if (column.getNewName()) {
32
+ sql += `RENAME COLUMN ${options.quoteColumnName(column.getName())} TO ${options.quoteColumnName(column.getNewName())}`
30
33
  } else {
31
34
  if (databaseType == "mssql" || databaseType == "pgsql") {
32
35
  sql += "ALTER COLUMN "
33
36
  } else {
34
37
  sql += "MODIFY "
35
38
  }
39
+
40
+ sql += column.getSQL({driver: this.getDriver(), forAlterTable: true})
36
41
  }
37
42
 
38
- sql += column.getSQL({driver: this.getDriver(), forAlterTable: true})
43
+
39
44
  columnsCount++
40
45
  }
41
46
 
@@ -12,7 +12,10 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
12
12
  }
13
13
 
14
14
  generateIndexName() {
15
- let indexName = `index_on_${this.tableName}_`
15
+ const databaseType = this.getDriver().getType()
16
+ let indexName = `index_on_`
17
+
18
+ if (databaseType == "sqlite") indexName += `${this.tableName}_`
16
19
 
17
20
  for (const columnIndex in this.columns) {
18
21
  if (columnIndex > 0) indexName += "_and_"
@@ -33,17 +36,34 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
33
36
  }
34
37
 
35
38
  toSql() {
39
+ const databaseType = this.getDriver().getType()
40
+ const indexName = this.name || this.generateIndexName()
36
41
  const options = this.getOptions()
37
42
  const {tableName} = this
38
- let sql = "CREATE"
43
+ let sql = ""
44
+
45
+ if (this.ifNotExists && databaseType == "mssql") {
46
+ sql += `
47
+ IF NOT EXISTS (
48
+ SELECT 1
49
+ FROM sys.indexes
50
+ WHERE
51
+ name = ${options.quote(indexName)} AND
52
+ object_id = OBJECT_ID(${options.quote(`dbo.${tableName}`)})
53
+ )
54
+ BEGIN
55
+ `
56
+ }
57
+
58
+ sql += "CREATE"
39
59
 
40
60
  if (this.unique) sql += " UNIQUE"
41
61
 
42
62
  sql += " INDEX"
43
63
 
44
- if (this.ifNotExists) sql += " IF NOT EXISTS"
64
+ if (this.ifNotExists && databaseType != "mssql") sql += " IF NOT EXISTS"
45
65
 
46
- sql += ` ${options.quoteIndexName(this.name || this.generateIndexName())}`
66
+ sql += ` ${options.quoteIndexName(indexName)}`
47
67
  sql += ` ON ${options.quoteTableName(tableName)} (`
48
68
 
49
69
  for (const columnIndex in this.columns) {
@@ -63,6 +83,10 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
63
83
 
64
84
  sql += ")"
65
85
 
86
+ if (this.ifNotExists && databaseType == "mssql") {
87
+ sql += " END"
88
+ }
89
+
66
90
  return sql
67
91
  }
68
92
  }
@@ -68,10 +68,15 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
68
68
  sql += ")"
69
69
  }
70
70
 
71
+ // Create indexes for all columns with the index argument
71
72
  for (const column of tableData.getColumns()) {
72
73
  if (!column.getIndex()) continue
73
74
 
74
- const indexName = `index_on_${tableData.getName()}_${column.getName()}`
75
+ let indexName = `index_on_`
76
+
77
+ if (databaseType == "sqlite") sql += `${tableData.getName()}_`
78
+
79
+ indexName += column.getName()
75
80
 
76
81
  sql += ","
77
82
 
@@ -100,6 +105,7 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
100
105
  const createIndexArgs = {
101
106
  columns: index.getColumns(),
102
107
  driver: this.getDriver(),
108
+ ifNotExists: true,
103
109
  name: index.getName(),
104
110
  tableName: tableData.getName(),
105
111
  unique: index.getUnique()
@@ -109,14 +115,20 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
109
115
  sqls.push(sql)
110
116
  }
111
117
 
118
+ // Create indexes for all columns with the index argument
112
119
  for (const column of tableData.getColumns()) {
113
120
  if (!column.getIndex()) continue
114
121
 
115
- const indexName = `index_on_${tableData.getName()}_${column.getName()}`
116
122
  const {unique, ...restIndexArgs} = column.getIndex()
117
123
 
118
124
  restArgsError(restIndexArgs)
119
125
 
126
+ let indexName = `index_on_`
127
+
128
+ if (databaseType == "sqlite") indexName += `${tableData.getName()}_`
129
+
130
+ indexName += column.getName()
131
+
120
132
  const createIndexArgs = {
121
133
  columns: [column.getName()],
122
134
  driver: this.getDriver(),
@@ -1,152 +1,10 @@
1
- import * as inflection from "inflection"
2
- import restArgsError from "../../utils/rest-args-error.js"
3
-
4
- class TableColumn {
5
- constructor(name, args) {
6
- if (args) {
7
- const {autoIncrement, default: columnDefault, foreignKey, index, isNewColumn, maxLength, name, null: argsNull, primaryKey, type, ...restArgs} = args
8
-
9
- if (Object.keys(args).length == 0) {
10
- throw new Error("Empty args given")
11
- }
12
-
13
- restArgsError(restArgs)
14
- }
15
-
16
- this.args = args
17
- this.name = name
18
- }
19
-
20
- getAutoIncrement() { return this.args?.autoIncrement }
21
- getDefault() { return this.args?.default }
22
- getForeignKey() { return this.args?.foreignKey }
23
- getIndex() { return this.args?.index }
24
- getMaxLength() { return this.args?.maxLength }
25
- getName() { return this.name }
26
- getNull() { return this.args?.null }
27
- setNull(nullable) { this.args.null = nullable }
28
- getPrimaryKey() { return this.args?.primaryKey }
29
- getType() { return this.args?.type }
30
- isNewColumn() { return this.args?.isNewColumn }
31
-
32
- getSQL({forAlterTable, driver}) {
33
- const databaseType = driver.getType()
34
- const options = driver.options()
35
- let maxlength = this.getMaxLength()
36
- let type = this.getType().toUpperCase()
37
-
38
- if (type == "DATETIME" && databaseType == "pgsql") {
39
- type = "TIMESTAMP"
40
- }
41
-
42
- if (type == "STRING") {
43
- type = "VARCHAR"
44
- maxlength ||= 255
45
- }
46
-
47
- if (databaseType == "mssql" && type == "BOOLEAN") {
48
- type = "BIT"
49
- } else if (databaseType == "mssql" && type == "UUID") {
50
- type = "VARCHAR"
51
- maxlength ||= 36
52
- }
53
-
54
- if (databaseType == "sqlite" && this.getAutoIncrement() && this.getPrimaryKey()) {
55
- type = "INTEGER"
56
- }
57
-
58
- if (databaseType == "pgsql" && this.getAutoIncrement() && this.getPrimaryKey()) {
59
- type = "SERIAL"
60
- }
61
-
62
- let sql = `${options.quoteColumnName(this.getName())} `
63
-
64
- if (databaseType == "pgsql" && forAlterTable) sql += "TYPE "
65
-
66
- sql += type
67
-
68
- if (maxlength !== undefined && maxlength !== null) sql += `(${maxlength})`
69
-
70
- if (this.getAutoIncrement() && driver.shouldSetAutoIncrementWhenPrimaryKey()) {
71
- if (databaseType == "mssql") {
72
- sql += " IDENTITY"
73
- } else if (databaseType == "pgsql") {
74
- if (this.getAutoIncrement() && this.getPrimaryKey()) {
75
- // Do nothing
76
- } else {
77
- throw new Error("pgsql auto increment must be primary key")
78
- }
79
- } else {
80
- sql += " AUTO_INCREMENT"
81
- }
82
- }
83
-
84
- if (typeof this.getDefault() == "function") {
85
- const defaultValue = this.getDefault()()
86
-
87
- sql += ` DEFAULT (`
88
-
89
- if (databaseType == "pgsql" && defaultValue == "UUID()") {
90
- sql += "gen_random_uuid()"
91
- } else if (databaseType == "mssql" && defaultValue == "UUID()") {
92
- sql += "NEWID()"
93
- } else {
94
- sql += defaultValue
95
- }
96
-
97
- sql += ")"
98
- } else if (this.getDefault()) {
99
- sql += ` DEFAULT ${options.quote(this.getDefault())}`
100
- }
101
-
102
- if (this.getPrimaryKey()) sql += " PRIMARY KEY"
103
- if (this.getNull() === false) sql += " NOT NULL"
104
-
105
- if (this.getForeignKey()) {
106
- let foreignKeyTable, foreignKeyColumn
107
-
108
- if (this.getForeignKey() === true) {
109
- foreignKeyColumn = "id"
110
- foreignKeyTable = inflection.pluralize(this.getName().replace(/_id$/, ""))
111
- } else {
112
- throw new Error(`Unknown foreign key type given: ${this.getForeignKey()} (${typeof this.getForeignKey()})`)
113
- }
114
-
115
- sql += ` REFERENCES ${options.quoteTableName(foreignKeyTable)}(${options.quoteColumnName(foreignKeyColumn)})`
116
- }
117
-
118
- return sql
119
- }
120
- }
121
-
122
- class TableIndex {
123
- constructor(columns, args) {
124
- if (args) {
125
- const {name, unique, ...restArgs} = args
126
-
127
- restArgsError(restArgs)
128
- }
129
-
130
- this.args = args
131
- this.columns = columns
132
- }
133
-
134
- getColumns() { return this.columns }
135
- getName() { return this.args.name }
136
- getUnique() { return Boolean(this.args.unique) }
137
- }
138
-
139
- class TableReference {
140
- constructor(name, args) {
141
- this.args = args
142
- this.name = name
143
- }
144
- }
145
-
146
- export {TableColumn, TableIndex}
1
+ import TableColumn from "./table-column.js"
2
+ import TableIndex from "./table-index.js"
3
+ import TableReference from "./table-reference.js"
147
4
 
148
5
  export default class TableData {
149
6
  _columns = []
7
+ _foreignKeys = []
150
8
  _indexes = []
151
9
  _references = []
152
10
 
@@ -167,12 +25,17 @@ export default class TableData {
167
25
  }
168
26
  }
169
27
 
170
- addIndex(index) { this._indexes.push(index) }
171
28
  getColumns() { return this._columns }
29
+
30
+ addForeignKey(foreignKey) { this._foreignKeys.push(foreignKey) }
31
+ getForeignKeys() { return this._foreignKeys }
32
+
33
+ addIndex(index) { this._indexes.push(index) }
34
+ getIndexes() { return this._indexes }
35
+
172
36
  getName() { return this._name }
173
37
  setName(newName) { this._name = newName }
174
38
  getIfNotExists() { return this.args.ifNotExists }
175
- getIndexes() { return this._indexes }
176
39
  getReferences() { return this._references }
177
40
 
178
41
  bigint(name, args = {}) { this.addColumn(name, Object.assign({isNewColumn: true, type: "bigint"}, args)) }
@@ -184,11 +47,10 @@ export default class TableData {
184
47
 
185
48
  references(name, args = {}) {
186
49
  const columnName = `${name}_id`
187
- const indexName = `index_on_${this.getName()}_${columnName}`
188
50
  const reference = new TableReference(name, args)
189
51
  const columnArgs = Object.assign({isNewColumn: true, type: "bigint"}, args)
190
52
  const column = new TableColumn(columnName, columnArgs)
191
- const index = new TableIndex([column], {name: indexName})
53
+ const index = new TableIndex([column])
192
54
 
193
55
  this._columns.push(column)
194
56
  this._indexes.push(index)
@@ -0,0 +1,145 @@
1
+ import * as inflection from "inflection"
2
+ import restArgsError from "../../utils/rest-args-error.js"
3
+ import TableForeignKey from "./table-foreign-key.js"
4
+
5
+ export default class TableColumn {
6
+ constructor(name, args) {
7
+ if (args) {
8
+ const {autoIncrement, default: columnDefault, foreignKey, index, isNewColumn, maxLength, name, null: argsNull, primaryKey, type, ...restArgs} = args
9
+
10
+ if (Object.keys(args).length == 0) {
11
+ throw new Error("Empty args given")
12
+ }
13
+
14
+ restArgsError(restArgs)
15
+ }
16
+
17
+ this.args = args || {}
18
+ this.name = name
19
+ }
20
+
21
+ getName() { return this.name }
22
+
23
+ getNewName() { return this._newName }
24
+ setNewName(newName) { this._newName = newName }
25
+
26
+ getActualName() { return this.getNewName() || this.getName() }
27
+
28
+ getAutoIncrement() { return this.args?.autoIncrement }
29
+ setAutoIncrement(newAutoIncrement) { this.args.autoIncrement = newAutoIncrement }
30
+
31
+ getDefault() { return this.args?.default }
32
+ setDefault(newDefault) { this.args.default = newDefault }
33
+
34
+ getForeignKey() { return this.args?.foreignKey }
35
+ setForeignKey(newForeignKey) { this.args.foreignKey = newForeignKey }
36
+
37
+ getIndex() { return this.args?.index }
38
+ setIndex(newIndex) { this.args.index = newIndex }
39
+
40
+ getMaxLength() { return this.args?.maxLength }
41
+ setMaxLength(newMaxLength) { this.args.maxLength = newMaxLength }
42
+
43
+ getNull() { return this.args?.null }
44
+ setNull(nullable) { this.args.null = nullable }
45
+
46
+ getPrimaryKey() { return this.args?.primaryKey }
47
+ setPrimaryKey(newPrimaryKey) { this.args.primaryKey = newPrimaryKey }
48
+
49
+ getType() { return this.args?.type }
50
+ setType(newType) { this.args.type = newType }
51
+
52
+ isNewColumn() { return this.args?.isNewColumn }
53
+
54
+ getSQL({forAlterTable, driver}) {
55
+ const databaseType = driver.getType()
56
+ const options = driver.options()
57
+ let maxlength = this.getMaxLength()
58
+ let type = this.getType()?.toUpperCase()
59
+
60
+ if (type == "DATETIME" && databaseType == "pgsql") {
61
+ type = "TIMESTAMP"
62
+ }
63
+
64
+ if (type == "STRING") {
65
+ type = "VARCHAR"
66
+ maxlength ||= 255
67
+ }
68
+
69
+ if (databaseType == "mssql" && type == "BOOLEAN") {
70
+ type = "BIT"
71
+ } else if (databaseType == "mssql" && type == "UUID") {
72
+ type = "VARCHAR"
73
+ maxlength ||= 36
74
+ }
75
+
76
+ if (databaseType == "sqlite" && this.getAutoIncrement() && this.getPrimaryKey()) {
77
+ type = "INTEGER"
78
+ }
79
+
80
+ if (databaseType == "pgsql" && this.getAutoIncrement() && this.getPrimaryKey()) {
81
+ type = "SERIAL"
82
+ }
83
+
84
+ let sql = `${options.quoteColumnName(this.getActualName())} `
85
+
86
+ if (databaseType == "pgsql" && forAlterTable) sql += "TYPE "
87
+ if (type) sql += type
88
+ if (type && maxlength !== undefined && maxlength !== null) sql += `(${maxlength})`
89
+
90
+ if (this.getAutoIncrement() && driver.shouldSetAutoIncrementWhenPrimaryKey()) {
91
+ if (databaseType == "mssql") {
92
+ sql += " IDENTITY"
93
+ } else if (databaseType == "pgsql") {
94
+ if (this.getAutoIncrement() && this.getPrimaryKey()) {
95
+ // Do nothing
96
+ } else {
97
+ throw new Error("pgsql auto increment must be primary key")
98
+ }
99
+ } else {
100
+ sql += " AUTO_INCREMENT"
101
+ }
102
+ }
103
+
104
+ if (typeof this.getDefault() == "function") {
105
+ const defaultValue = this.getDefault()()
106
+
107
+ sql += ` DEFAULT (`
108
+
109
+ if (databaseType == "pgsql" && defaultValue == "UUID()") {
110
+ sql += "gen_random_uuid()"
111
+ } else if (databaseType == "mssql" && defaultValue == "UUID()") {
112
+ sql += "NEWID()"
113
+ } else {
114
+ sql += defaultValue
115
+ }
116
+
117
+ sql += ")"
118
+ } else if (this.getDefault()) {
119
+ sql += ` DEFAULT ${options.quote(this.getDefault())}`
120
+ }
121
+
122
+ if (this.getPrimaryKey()) sql += " PRIMARY KEY"
123
+ if (this.getNull() === false) sql += " NOT NULL"
124
+
125
+ const foreignKey = this.getForeignKey()
126
+
127
+ if (foreignKey) {
128
+ let foreignKeyTable, foreignKeyColumn
129
+
130
+ if (foreignKey === true) {
131
+ foreignKeyColumn = "id"
132
+ foreignKeyTable = inflection.pluralize(this.getActualName().replace(/_id$/, ""))
133
+ } else if (foreignKey instanceof TableForeignKey) {
134
+ foreignKeyColumn = foreignKey.getReferencedColumnName()
135
+ foreignKeyTable = foreignKey.getReferencedTableName()
136
+ } else {
137
+ throw new Error(`Unknown foreign key type given: ${this.getForeignKey()} (${typeof this.getForeignKey()})`)
138
+ }
139
+
140
+ sql += ` REFERENCES ${options.quoteTableName(foreignKeyTable)}(${options.quoteColumnName(foreignKeyColumn)})`
141
+ }
142
+
143
+ return sql
144
+ }
145
+ }
@@ -0,0 +1,21 @@
1
+ import restArgsError from "../../utils/rest-args-error.js"
2
+
3
+ export default class TableForeignKey {
4
+ constructor({columnName, name, tableName, referencedColumnName, referencedTableName, ...restArgs}) {
5
+ restArgsError(restArgs)
6
+
7
+ this._columnName = columnName
8
+ this._name = name
9
+ this._tableName = tableName
10
+ this._referencedColumnName = referencedColumnName
11
+ this._referencedTableName = referencedTableName
12
+ }
13
+
14
+ getColumnName() { return this._columnName }
15
+ getTableName() { return this._tableName }
16
+ getReferencedColumnName() { return this._referencedColumnName }
17
+ getReferencedTableName() { return this._referencedTableName }
18
+
19
+ getName() { return this._name }
20
+ setName(newName) { this._name = newName }
21
+ }
@@ -0,0 +1,18 @@
1
+ import restArgsError from "../../utils/rest-args-error.js"
2
+
3
+ export default class TableIndex {
4
+ constructor(columns, args) {
5
+ if (args) {
6
+ const {name, unique, ...restArgs} = args
7
+
8
+ restArgsError(restArgs)
9
+ }
10
+
11
+ this.args = args
12
+ this.columns = columns
13
+ }
14
+
15
+ getColumns() { return this.columns }
16
+ getName() { return this.args?.name }
17
+ getUnique() { return Boolean(this.args?.unique) }
18
+ }
@@ -0,0 +1,6 @@
1
+ export default class TableReference {
2
+ constructor(name, args) {
3
+ this.args = args
4
+ this.name = name
5
+ }
6
+ }