velocious 1.0.46 → 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 (42) hide show
  1. package/package.json +1 -1
  2. package/spec/cli/commands/db/migrate-spec.js +52 -8
  3. package/spec/dummy/src/database/migrations/20250915085450-change-authentication-tokens-user-id-nullable.js +11 -0
  4. package/spec/dummy/src/database/migrations/20250916111330-rename_authentication_tokens_token_to_user_token.js +11 -0
  5. package/src/database/drivers/base-column.js +28 -0
  6. package/src/database/drivers/base-foreign-key.js +31 -0
  7. package/src/database/drivers/base-table.js +29 -0
  8. package/src/database/drivers/base.js +19 -1
  9. package/src/database/drivers/mssql/column.js +22 -0
  10. package/src/database/drivers/mssql/columns-index.js +1 -1
  11. package/src/database/drivers/mssql/foreign-key.js +2 -5
  12. package/src/database/drivers/mssql/index.js +16 -6
  13. package/src/database/drivers/mssql/sql/alter-table.js +4 -0
  14. package/src/database/drivers/mssql/table.js +37 -1
  15. package/src/database/drivers/mysql/column.js +38 -4
  16. package/src/database/drivers/mysql/foreign-key.js +2 -5
  17. package/src/database/drivers/mysql/index.js +9 -1
  18. package/src/database/drivers/mysql/sql/alter-table.js +4 -0
  19. package/src/database/drivers/mysql/table.js +41 -0
  20. package/src/database/drivers/pgsql/column.js +22 -0
  21. package/src/database/drivers/pgsql/foreign-key.js +2 -5
  22. package/src/database/drivers/pgsql/index.js +10 -2
  23. package/src/database/drivers/pgsql/sql/alter-table.js +4 -0
  24. package/src/database/drivers/pgsql/table.js +32 -2
  25. package/src/database/drivers/sqlite/base.js +5 -5
  26. package/src/database/drivers/sqlite/column.js +28 -36
  27. package/src/database/drivers/sqlite/columns-index.js +13 -1
  28. package/src/database/drivers/sqlite/foreign-key.js +8 -7
  29. package/src/database/drivers/sqlite/index.js +1 -1
  30. package/src/database/drivers/sqlite/index.web.js +3 -1
  31. package/src/database/drivers/sqlite/query.js +1 -2
  32. package/src/database/drivers/sqlite/sql/alter-table.js +143 -1
  33. package/src/database/drivers/sqlite/table.js +38 -0
  34. package/src/database/migration/index.js +31 -15
  35. package/src/database/query/alter-table-base.js +32 -7
  36. package/src/database/query/create-index-base.js +28 -4
  37. package/src/database/query/create-table-base.js +21 -82
  38. package/src/database/table-data/index.js +36 -70
  39. package/src/database/table-data/table-column.js +145 -0
  40. package/src/database/table-data/table-foreign-key.js +21 -0
  41. package/src/database/table-data/table-index.js +18 -0
  42. package/src/database/table-data/table-reference.js +6 -0
@@ -1,5 +1,6 @@
1
+ import AlterTable from "./sql/alter-table.js"
1
2
  import Base from "../base.js"
2
- import {Client, escapeLiteral} from "pg"
3
+ import {Client} from "pg"
3
4
  import CreateDatabase from "./sql/create-database.js"
4
5
  import CreateIndex from "./sql/create-index.js"
5
6
  import CreateTable from "./sql/create-table.js"
@@ -49,6 +50,13 @@ export default class VelociousDatabaseDriversPgsql extends Base{
49
50
  this.connection = undefined
50
51
  }
51
52
 
53
+ async alterTableSql(tableData) {
54
+ const alterArgs = {tableData, driver: this}
55
+ const alterTable = new AlterTable(alterArgs)
56
+
57
+ return await alterTable.toSqls()
58
+ }
59
+
52
60
  createDatabaseSql(databaseName, args) {
53
61
  const createArgs = Object.assign({databaseName, driver: this}, args)
54
62
  const createDatabase = new CreateDatabase(createArgs)
@@ -64,7 +72,7 @@ export default class VelociousDatabaseDriversPgsql extends Base{
64
72
  }
65
73
 
66
74
  createTableSql(tableData) {
67
- const createArgs = Object.assign({tableData, driver: this, indexInCreateTable: false})
75
+ const createArgs = {tableData, driver: this, indexInCreateTable: false}
68
76
  const createTable = new CreateTable(createArgs)
69
77
 
70
78
  return createTable.toSql()
@@ -0,0 +1,4 @@
1
+ import AlterTableBase from "../../../query/alter-table-base.js"
2
+
3
+ export default class VelociousDatabaseConnectionDriversPgsqlSqlAlterTable extends AlterTableBase {
4
+ }
@@ -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
  }
@@ -14,11 +14,11 @@ import Table from "./table.js"
14
14
  import Update from "./sql/update.js"
15
15
 
16
16
  export default class VelociousDatabaseDriversSqliteBase extends Base {
17
- alterTableSql(columnData) {
18
- const createArgs = Object.assign({driver: this}, columnData)
19
- const alterTable = new AlterTable(createArgs)
17
+ async alterTableSql(tableData) {
18
+ const alterArgs = {driver: this, tableData}
19
+ const alterTable = new AlterTable(alterArgs)
20
20
 
21
- return alterTable.toSqls()
21
+ return await alterTable.toSqls()
22
22
  }
23
23
 
24
24
  createIndexSql(indexData) {
@@ -29,7 +29,7 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
29
29
  }
30
30
 
31
31
  createTableSql(tableData) {
32
- const createArgs = Object.assign({tableData, driver: this, indexInCreateTable: false})
32
+ const createArgs = {tableData, driver: this, indexInCreateTable: false}
33
33
  const createTable = new CreateTable(createArgs)
34
34
 
35
35
  return createTable.toSql()
@@ -1,5 +1,5 @@
1
+ import {digg} from "diggerize"
1
2
  import BaseColumn from "../base-column.js"
2
- import ColumnsIndex from "./columns-index.js"
3
3
 
4
4
  export default class VelociousDatabaseDriversSqliteColumn extends BaseColumn {
5
5
  constructor({column, driver, table}) {
@@ -10,59 +10,51 @@ export default class VelociousDatabaseDriversSqliteColumn extends BaseColumn {
10
10
  }
11
11
 
12
12
  async getIndexes() {
13
- const table = this.getTable()
14
- const rows = await this.getDriver().query(`PRAGMA index_list(${this.getOptions().quoteTableName(table.getName())})`)
15
- const indexes = []
13
+ const indexes = await this.getTable().getIndexes()
14
+ const indexesForColumn = indexes.filter((index) => index.getColumnNames().includes(this.getName()))
16
15
 
17
- for (const row of rows) {
18
- const columnsIndex = new ColumnsIndex(table, row)
19
- const indexMasterData = await this.getDriver().query(`SELECT * FROM sqlite_master WHERE type = 'index' AND name = ${this.getOptions().quote(columnsIndex.getName())}`)
20
-
21
- columnsIndex.columnNames = this._parseColumnsFromSQL(indexMasterData[0].sql)
22
-
23
- indexes.push(columnsIndex)
24
- }
16
+ return indexesForColumn
17
+ }
25
18
 
26
- return indexes
19
+ getDefault() {
20
+ return digg(this, "column", "dflt_value")
27
21
  }
28
22
 
23
+ getName() {
24
+ const name = digg(this, "column", "name")
25
+
26
+ if (!name) throw new Error("No name given for SQLite column")
29
27
 
30
- _parseColumnsFromSQL(sql) {
31
- const columnsSQLMatch = sql.match(/\((.+?)\)/)
32
- const columnsSQL = columnsSQLMatch[1].split(",")
33
- const columnNames = []
28
+ return name
29
+ }
34
30
 
35
- for (const column of columnsSQL) {
36
- const matchTicks = column.match(/`(.+)`/)
37
- const matchQuotes = column.match(/"(.+)"/)
31
+ getMaxLength() {
32
+ const columnType = digg(this, "column", "type")
33
+ const match = columnType.match(/(.*)\((\d+)\)$/)
38
34
 
39
- if (matchTicks) {
40
- columnNames.push(matchTicks[1])
41
- } else if (matchQuotes) {
42
- columnNames.push(matchQuotes[1])
43
- } else{
44
- throw new Error(`Couldn't parse column part: ${column}`)
45
- }
35
+ if (match) {
36
+ return parseInt(match[2])
46
37
  }
47
-
48
- return columnNames
49
38
  }
50
39
 
51
- getName() {
52
- if (!this.column.name) {
53
- throw new Error("No name given for SQLite column")
54
- }
40
+ getNull() {
41
+ const notNullValue = digg(this, "column", "notnull")
55
42
 
56
- return this.column.name
43
+ if (notNullValue === 1) {
44
+ return false
45
+ } else {
46
+ return true
47
+ }
57
48
  }
58
49
 
59
50
  getType() {
60
- const match = this.column.type.match(/(.*)\((\d+)\)$/)
51
+ const columnType = digg(this, "column", "type")
52
+ const match = columnType.match(/(.*)\((\d+)\)$/)
61
53
 
62
54
  if (match) {
63
55
  return match[1].toLowerCase()
64
56
  }
65
57
 
66
- return this.column.type.toLowerCase()
58
+ return columnType.toLowerCase()
67
59
  }
68
60
  }
@@ -1,17 +1,29 @@
1
1
  import BaseColumnsIndex from "../base-columns-index.js"
2
2
  import {digg} from "diggerize"
3
+ import TableIndex from "../../table-data/table-index.js"
3
4
 
4
- export default class VelociousDatabaseDriversSqliteColumn extends BaseColumnsIndex {
5
+ export default class VelociousDatabaseDriversSqliteColumnsIndex extends BaseColumnsIndex {
5
6
  constructor(table, data) {
6
7
  super()
7
8
  this.data = data
8
9
  this.table = table
9
10
  }
10
11
 
12
+ getColumnNames() {
13
+ return digg(this, "data", "columnNames")
14
+ }
15
+
11
16
  getName() {
12
17
  return digg(this, "data", "name")
13
18
  }
14
19
 
20
+ getTableDataIndex() {
21
+ return new TableIndex(this.getColumnNames(), {
22
+ name: this.getName(),
23
+ unique: this.isUnique()
24
+ })
25
+ }
26
+
15
27
  isPrimaryKey() {
16
28
  return false
17
29
  }
@@ -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
  }
@@ -34,7 +34,7 @@ export default class VelociousDatabaseDriversSqliteNode extends Base {
34
34
  this.connection = undefined
35
35
  }
36
36
 
37
- query = async (sql) => {
37
+ async query(sql) {
38
38
  return await query(this.connection, sql)
39
39
  }
40
40
  }
@@ -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,5 +1,4 @@
1
1
  export default async function query(connection, sql) {
2
- const rows = []
3
2
  let result
4
3
 
5
4
  try {
@@ -13,7 +12,7 @@ export default async function query(connection, sql) {
13
12
 
14
13
  error.message += `\n\n${sqlInErrorMessage}`
15
14
 
16
- throw error
15
+ throw new Error(error.message)
17
16
  }
18
17
 
19
18
  return result
@@ -1,4 +1,146 @@
1
1
  import AlterTableBase from "../../../query/alter-table-base.js"
2
+ import CreateIndexBase from "../../../query/create-index-base.js"
3
+ import {digs} from "diggerize"
4
+ import * as inflection from "inflection"
5
+ import {Logger} from "../../../../logger.js"
6
+ import restArgsError from "../../../../utils/rest-args-error.js"
7
+ import TableData from "../../../table-data/index.js"
2
8
 
3
- export default class VelociousDatabaseConnectionDriversMysqlSqlAlterTable extends AlterTableBase {
9
+ export default class VelociousDatabaseConnectionDriversSqliteSqlAlterTable extends AlterTableBase {
10
+ constructor({driver, tableData, ...restArgs}) {
11
+ restArgsError(restArgs)
12
+
13
+ if (!(tableData instanceof TableData)) throw new Error("Invalid table data was given")
14
+
15
+ super({driver, tableData})
16
+ this.logger = new Logger(this)
17
+ this.tableData = tableData
18
+ }
19
+
20
+ async toSqls() {
21
+ const {tableData} = digs(this, "tableData")
22
+ const table = await this.getDriver().getTableByName(tableData.getName())
23
+ const currentTableData = await table.getTableData()
24
+ const options = this.getOptions()
25
+ const tableName = tableData.getName()
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
+ })
34
+ const oldColumnNames = currentTableData.getColumns().filter((column) => !column.isNewColumn()).map((column) => column.getName())
35
+ const newColumnsSQL = newColumnNames.map((name) => options.quoteColumnName(name)).join(", ")
36
+ const oldColumnsSQL = oldColumnNames.map((name) => options.quoteColumnName(name)).join(", ")
37
+
38
+ tableData.setName(tempTableName)
39
+
40
+ const newTableData = new TableData(tempTableName)
41
+
42
+ for (const tableDataColumn of currentTableData.getColumns()) {
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
+ }
60
+
61
+ newTableData.addColumn(newTableDataColumn || tableDataColumn)
62
+ }
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
+
106
+ const createNewTableSQL = this.getDriver().createTableSql(newTableData)
107
+ const insertSQL = `INSERT INTO ${options.quoteTableName(tempTableName)} (${newColumnsSQL}) SELECT ${oldColumnsSQL} FROM ${options.quoteTableName(tableName)}`
108
+ const dropTableSQL = `DROP TABLE ${options.quoteTableName(tableName)}`
109
+ const renameTableSQL = `ALTER TABLE ${options.quoteTableName(tempTableName)} RENAME TO ${options.quoteTableName(tableName)}`
110
+ const sqls = []
111
+
112
+ for (const sql of createNewTableSQL) {
113
+ sqls.push(sql)
114
+ }
115
+
116
+ sqls.push(insertSQL)
117
+ sqls.push(dropTableSQL)
118
+ sqls.push(renameTableSQL)
119
+
120
+ for (const tableDataIndex of currentTableData.getIndexes()) {
121
+ const newTableDataIndex = newTableData.getIndexes().find((newTableDataIndex) => newTableDataIndex.getName() == tableDataIndex.getName())
122
+ const actualTableIndex = newTableDataIndex || tableDataIndex
123
+
124
+ newTableData.addIndex(actualTableIndex)
125
+
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
+ })
131
+
132
+ const createIndexArgs = {
133
+ columns: columnNames,
134
+ driver: this.getDriver(),
135
+ name: actualTableIndex.getName(),
136
+ tableName,
137
+ unique: actualTableIndex.getUnique()
138
+ }
139
+ const sql = new CreateIndexBase(createIndexArgs).toSql()
140
+
141
+ sqls.push(sql)
142
+ }
143
+
144
+ return sqls
145
+ }
4
146
  }
@@ -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 VelociousDatabaseDriversSqliteTable extends BaseTable {
@@ -35,6 +36,43 @@ export default class VelociousDatabaseDriversSqliteTable extends BaseTable {
35
36
  return foreignKeys
36
37
  }
37
38
 
39
+ async getIndexes() {
40
+ const rows = await this.getDriver().query(`PRAGMA index_list(${this.getOptions().quoteTableName(this.getName())})`)
41
+ const indexes = []
42
+
43
+ for (const row of rows) {
44
+ const columnsIndex = new ColumnsIndex(this, row)
45
+ const indexMasterData = await this.getDriver().query(`SELECT * FROM sqlite_master WHERE type = 'index' AND name = ${this.getOptions().quote(columnsIndex.getName())}`)
46
+
47
+ columnsIndex.data.columnNames = this._parseColumnsFromSQL(indexMasterData[0].sql)
48
+
49
+ indexes.push(columnsIndex)
50
+ }
51
+
52
+ return indexes
53
+ }
54
+
55
+ _parseColumnsFromSQL(sql) {
56
+ const columnsSQLMatch = sql.match(/\((.+?)\)/)
57
+ const columnsSQL = columnsSQLMatch[1].split(",")
58
+ const columnNames = []
59
+
60
+ for (const column of columnsSQL) {
61
+ const matchTicks = column.match(/`(.+)`/)
62
+ const matchQuotes = column.match(/"(.+)"/)
63
+
64
+ if (matchTicks) {
65
+ columnNames.push(matchTicks[1])
66
+ } else if (matchQuotes) {
67
+ columnNames.push(matchQuotes[1])
68
+ } else{
69
+ throw new Error(`Couldn't parse column part: ${column}`)
70
+ }
71
+ }
72
+
73
+ return columnNames
74
+ }
75
+
38
76
  getName() {
39
77
  if (!this.row.name) {
40
78
  throw new Error("No name given for SQLite table")
@@ -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
33
 
34
- const sqls = this._db.alterTableSql({
35
- columns: [new TableColumn(columnName, tableColumnArgs)],
36
- tableName
37
- })
34
+ const tableColumnArgs = Object.assign({isNewColumn: true, type: columnType}, args)
35
+ const tableData = new TableData(tableName)
36
+
37
+ tableData.addColumn(columnName, tableColumnArgs)
38
+
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,20 +68,30 @@ 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
  }
82
87
 
88
+ async changeColumnNull(tableName, columnName, nullable) {
89
+ const table = await this.getDriver().getTableByName(tableName)
90
+ const column = await table.getColumnByName(columnName)
91
+
92
+ await column.changeNullable(nullable)
93
+ }
94
+
83
95
  async createTable(tableName, arg1, arg2) {
84
96
  let args
85
97
  let callback
@@ -111,15 +123,19 @@ export default class VelociousDatabaseMigration {
111
123
  callback(tableData)
112
124
  }
113
125
 
114
- const sqls = this._db.createTableSql(tableData)
126
+ const sqls = this.getDriver().createTableSql(tableData)
115
127
 
116
128
  for (const sql of sqls) {
117
129
  await this._db.query(sql)
118
130
  }
119
131
  }
120
132
 
133
+ async renameColumn(tableName, oldColumnName, newColumnName) {
134
+ await this.getDriver().renameColumn(tableName, oldColumnName, newColumnName)
135
+ }
136
+
121
137
  async tableExists(tableName) {
122
- const exists = await this._db.tableExists(tableName)
138
+ const exists = await this.getDriver().tableExists(tableName)
123
139
 
124
140
  return exists
125
141
  }
@@ -1,26 +1,51 @@
1
+ import {digs} from "diggerize"
1
2
  import QueryBase from "./base.js"
2
3
  import restArgsError from "../../utils/rest-args-error.js"
4
+ import TableData from "../table-data/index.js"
3
5
 
4
6
  export default class VelociousDatabaseQueryAlterTableBase extends QueryBase {
5
- constructor({columns, driver, tableName, ...restArgs}) {
7
+ constructor({driver, tableData, ...restArgs}) {
6
8
  restArgsError(restArgs)
7
9
 
10
+ if (!(tableData instanceof TableData)) throw new Error("Invalid table data was given")
11
+
8
12
  super({driver})
9
- this.columns = columns
10
- this.tableName = tableName
13
+ this.tableData = tableData
11
14
  }
12
15
 
13
16
  toSqls() {
17
+ const databaseType = this.getDriver().getType()
14
18
  const sqls = []
19
+ const {tableData} = digs(this, "tableData")
20
+ const options = this.getOptions()
21
+
22
+ let sql = `ALTER TABLE ${options.quoteTableName(tableData.getName())} `
23
+ let columnsCount = 0
24
+
25
+ for (const column of tableData.getColumns()) {
26
+ if (columnsCount > 0) sql += ", "
15
27
 
16
- for (const column of this.columns) {
17
- let sql = `ALTER TABLE ${this.getOptions().quoteTableName(this.tableName)} ADD `
28
+ if (column.isNewColumn()) {
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())}`
33
+ } else {
34
+ if (databaseType == "mssql" || databaseType == "pgsql") {
35
+ sql += "ALTER COLUMN "
36
+ } else {
37
+ sql += "MODIFY "
38
+ }
18
39
 
19
- sql += this.getOptions().quoteColumnName(column.getName())
40
+ sql += column.getSQL({driver: this.getDriver(), forAlterTable: true})
41
+ }
20
42
 
21
- sqls.push(sql)
43
+
44
+ columnsCount++
22
45
  }
23
46
 
47
+ sqls.push(sql)
48
+
24
49
  return sqls
25
50
  }
26
51
  }