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.
- package/package.json +1 -1
- package/spec/cli/commands/db/migrate-spec.js +44 -6
- package/spec/dummy/src/database/migrations/20250916111330-rename_authentication_tokens_token_to_user_token.js +11 -0
- package/src/database/drivers/base-column.js +2 -3
- package/src/database/drivers/base-foreign-key.js +31 -0
- package/src/database/drivers/base-table.js +15 -1
- package/src/database/drivers/base.js +19 -1
- package/src/database/drivers/mssql/columns-index.js +1 -1
- package/src/database/drivers/mssql/foreign-key.js +2 -5
- package/src/database/drivers/mssql/index.js +7 -5
- package/src/database/drivers/mssql/table.js +36 -0
- package/src/database/drivers/mysql/column.js +4 -3
- package/src/database/drivers/mysql/foreign-key.js +2 -5
- package/src/database/drivers/mysql/table.js +41 -0
- package/src/database/drivers/pgsql/foreign-key.js +2 -5
- package/src/database/drivers/pgsql/table.js +32 -2
- package/src/database/drivers/sqlite/columns-index.js +2 -2
- package/src/database/drivers/sqlite/foreign-key.js +8 -7
- package/src/database/drivers/sqlite/index.web.js +3 -1
- package/src/database/drivers/sqlite/sql/alter-table.js +77 -6
- package/src/database/migration/index.js +21 -12
- package/src/database/query/alter-table-base.js +6 -1
- package/src/database/query/create-index-base.js +28 -4
- package/src/database/query/create-table-base.js +14 -2
- package/src/database/table-data/index.js +12 -150
- package/src/database/table-data/table-column.js +145 -0
- package/src/database/table-data/table-foreign-key.js +21 -0
- package/src/database/table-data/table-index.js +18 -0
- package/src/database/table-data/table-reference.js +6 -0
package/package.json
CHANGED
|
@@ -40,15 +40,43 @@ describe("Cli - Commands - db:migrate", () => {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
// It creates
|
|
43
|
+
// It creates the correct index
|
|
44
44
|
const authenticationTokensTable = await dbs.default.getTableByName("authentication_tokens")
|
|
45
|
-
const
|
|
46
|
-
const
|
|
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
|
-
|
|
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([
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
151
|
-
quoteTable
|
|
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
|
|
25
|
-
|
|
26
|
-
|
|
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.
|
|
47
|
+
tc.table_name = ${this.getDriver().quote(this.getName())}
|
|
47
48
|
`
|
|
48
49
|
|
|
49
|
-
const foreignKeyRows = await this.
|
|
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
|
|
3
|
+
import TableIndex from "../../table-data/table-index.js"
|
|
4
4
|
|
|
5
|
-
export default class
|
|
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
|
-
|
|
6
|
+
super(data)
|
|
6
7
|
this.tableName = tableName
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
getColumnName
|
|
10
|
-
getName
|
|
11
|
-
getTableName
|
|
12
|
-
getReferencedColumnName
|
|
13
|
-
getReferencedTableName
|
|
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) =>
|
|
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 =
|
|
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)} (${
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
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.
|
|
39
|
+
const sqls = await this.getDriver().alterTableSql(tableData)
|
|
38
40
|
|
|
39
41
|
for (const sql of sqls) {
|
|
40
|
-
await this.
|
|
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.
|
|
54
|
+
const sql = this.getDriver().createIndexSql(createIndexArgs)
|
|
53
55
|
|
|
54
|
-
await this.
|
|
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.
|
|
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
|
-
|
|
76
|
-
|
|
78
|
+
restArgsError(restArgs)
|
|
79
|
+
|
|
80
|
+
await this.addColumn(tableName, columnName, type || "integer")
|
|
81
|
+
await this.addIndex(tableName, [columnName], {unique: unique})
|
|
77
82
|
|
|
78
|
-
if (
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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 = "
|
|
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(
|
|
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
|
-
|
|
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
|
|
2
|
-
import
|
|
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]
|
|
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
|
+
}
|