velocious 1.0.39 → 1.0.41

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 (71) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -1
  3. package/peak_flow.yml +14 -6
  4. package/spec/cli/commands/db/create-spec.js +1 -0
  5. package/spec/cli/commands/db/migrate-spec.js +28 -11
  6. package/spec/cli/commands/test/test-files-finder-spec.js +5 -4
  7. package/spec/database/record/create-spec.js +9 -0
  8. package/spec/database/record/destroy-spec.js +6 -3
  9. package/spec/database/record/find-spec.js +4 -1
  10. package/spec/database/record/query-spec.js +7 -3
  11. package/spec/database/record/translation-fallbacks-spec.js +1 -1
  12. package/spec/database/record/update-spec.js +2 -1
  13. package/spec/database/record/validations-spec.js +16 -4
  14. package/spec/database/transactions-spec.js +7 -5
  15. package/spec/dummy/index.js +18 -29
  16. package/spec/dummy/src/config/configuration.example.js +3 -2
  17. package/spec/dummy/src/config/configuration.peakflow.mariadb.js +3 -7
  18. package/spec/dummy/src/config/configuration.peakflow.mssql.js +3 -12
  19. package/spec/dummy/src/config/configuration.peakflow.pgsql.js +3 -7
  20. package/spec/dummy/src/config/configuration.peakflow.sqlite.js +3 -7
  21. package/spec/dummy/src/config/testing.js +62 -0
  22. package/spec/dummy/src/database/migrations/20250912183605-create-users.js +15 -0
  23. package/spec/dummy/src/database/migrations/20250912183606-create-authentication-tokens.js +15 -0
  24. package/spec/dummy/src/models/authentication-token.js +8 -0
  25. package/spec/dummy/src/models/task.js +2 -2
  26. package/spec/dummy/src/models/user.js +15 -0
  27. package/spec/dummy/src/routes/projects/controller.js +7 -1
  28. package/spec/http-server/client-spec.js +1 -1
  29. package/spec/http-server/get-spec.js +1 -1
  30. package/spec/http-server/post-spec.js +21 -8
  31. package/spec/http-server/root-get-spec.js +1 -1
  32. package/src/cli/commands/db/create.js +11 -8
  33. package/src/cli/commands/db/drop.js +19 -0
  34. package/src/cli/commands/db/migrate.js +1 -1
  35. package/src/cli/commands/db/reset.js +7 -1
  36. package/src/cli/commands/test.js +10 -4
  37. package/src/configuration.js +26 -3
  38. package/src/database/drivers/base-column.js +22 -0
  39. package/src/database/drivers/base-columns-index.js +34 -0
  40. package/src/database/drivers/base-table.js +43 -0
  41. package/src/database/drivers/base.js +12 -16
  42. package/src/database/drivers/mssql/column.js +43 -2
  43. package/src/database/drivers/mssql/columns-index.js +9 -0
  44. package/src/database/drivers/mssql/index.js +26 -14
  45. package/src/database/drivers/mssql/table.js +16 -1
  46. package/src/database/drivers/mysql/column.js +47 -2
  47. package/src/database/drivers/mysql/columns-index.js +10 -0
  48. package/src/database/drivers/mysql/index.js +5 -8
  49. package/src/database/drivers/mysql/table.js +3 -1
  50. package/src/database/drivers/pgsql/column.js +37 -2
  51. package/src/database/drivers/pgsql/columns-index.js +4 -0
  52. package/src/database/drivers/pgsql/index.js +6 -5
  53. package/src/database/drivers/pgsql/table.js +3 -1
  54. package/src/database/drivers/sqlite/base.js +6 -4
  55. package/src/database/drivers/sqlite/column.js +46 -2
  56. package/src/database/drivers/sqlite/columns-index.js +22 -0
  57. package/src/database/drivers/sqlite/connection-sql-js.js +1 -1
  58. package/src/database/drivers/sqlite/table.js +3 -1
  59. package/src/database/migrator.js +27 -7
  60. package/src/database/query/create-index-base.js +10 -1
  61. package/src/database/query/create-table-base.js +56 -2
  62. package/src/database/query/drop-table-base.js +8 -2
  63. package/src/database/record/index.js +16 -5
  64. package/src/database/record/validators/presence.js +1 -1
  65. package/src/database/table-data/index.js +2 -1
  66. package/src/database/use-database.js +1 -1
  67. package/src/routes/resolver.js +1 -1
  68. package/src/templates/configuration.js +1 -1
  69. package/src/testing/test-runner.js +86 -26
  70. package/src/testing/test.js +155 -7
  71. package/src/utils/with-tracked-stack.js +5 -3
@@ -0,0 +1,9 @@
1
+ import BaseColumnsIndex from "../base-columns-index.js"
2
+
3
+ export default class VelociousDatabaseDriversMssqlColumn extends BaseColumnsIndex {
4
+ constructor(table, data) {
5
+ super()
6
+ this.data = data
7
+ this.table = table
8
+ }
9
+ }
@@ -26,10 +26,6 @@ export default class VelociousDatabaseDriversMssql extends Base{
26
26
  }
27
27
  }
28
28
 
29
- disconnect() {
30
- this.connection.end()
31
- }
32
-
33
29
  async close() {
34
30
  await this.connection.close()
35
31
  this.connection = undefined
@@ -50,7 +46,7 @@ export default class VelociousDatabaseDriversMssql extends Base{
50
46
  }
51
47
 
52
48
  createTableSql(tableData) {
53
- const createArgs = Object.assign({tableData, driver: this})
49
+ const createArgs = Object.assign({tableData, driver: this, indexInCreateTable: false})
54
50
  const createTable = new CreateTable(createArgs)
55
51
 
56
52
  return createTable.toSql()
@@ -75,7 +71,7 @@ export default class VelociousDatabaseDriversMssql extends Base{
75
71
  primaryKeyType = () => "bigint"
76
72
 
77
73
  async query(sql) {
78
- let result, request
74
+ let result, request, tries = 0
79
75
 
80
76
  if (this._currentTransaction) {
81
77
  request = new mssql.Request(this._currentTransaction)
@@ -83,11 +79,22 @@ export default class VelociousDatabaseDriversMssql extends Base{
83
79
  request = mssql
84
80
  }
85
81
 
86
- try {
87
- result = await request.query(sql)
88
- } catch (error) {
89
- // Re-throw error because the stack-trace is broken and can't be used for app-development.
90
- throw new Error(`Query failed '${error.message})': ${sql}`)
82
+ while (true) {
83
+ tries++
84
+
85
+ try {
86
+ result = await request.query(sql)
87
+ break
88
+ } catch (error) {
89
+ if (error.message == "No connection is specified for that request." && tries <= 3) {
90
+ this.logger.log("Reconnecting to database")
91
+ await this.connect()
92
+ // Retry
93
+ } else {
94
+ // Re-throw error because the stack-trace is broken and can't be used for app-development.
95
+ throw new Error(`Query failed '${error.message}': ${sql}`)
96
+ }
97
+ }
91
98
  }
92
99
 
93
100
  return result.recordsets[0]
@@ -154,12 +161,14 @@ export default class VelociousDatabaseDriversMssql extends Base{
154
161
  return tables
155
162
  }
156
163
 
157
- async getTableByName(tableName) {
164
+ async getTableByName(tableName, args) {
158
165
  const result = await this.query(`SELECT [TABLE_NAME] FROM [INFORMATION_SCHEMA].[TABLES] WHERE [TABLE_CATALOG] = DB_NAME() AND [TABLE_SCHEMA] = 'dbo' AND [TABLE_NAME] = ${this.quote(tableName)}`)
159
166
 
160
- if (!result[0]) throw new Error(`Couldn't find a table by that name: ${tableName}`)
167
+ if (result[0]) {
168
+ return new Table(this, result[0])
169
+ }
161
170
 
162
- return new Table(this, result[0])
171
+ if (args?.throwError !== false) throw new Error(`Couldn't find a table by that name: ${tableName}`)
163
172
  }
164
173
 
165
174
  async lastInsertID() {
@@ -184,6 +193,7 @@ export default class VelociousDatabaseDriversMssql extends Base{
184
193
  this._currentTransaction = new mssql.Transaction(this.connection)
185
194
 
186
195
  await this._currentTransaction.begin()
196
+ this._transactionsCount++
187
197
  }
188
198
 
189
199
  async commitTransaction() {
@@ -191,6 +201,7 @@ export default class VelociousDatabaseDriversMssql extends Base{
191
201
 
192
202
  await this._currentTransaction.commit()
193
203
  this._currentTransaction = null
204
+ this._transactionsCount--
194
205
  }
195
206
 
196
207
  async rollbackTransaction() {
@@ -199,6 +210,7 @@ export default class VelociousDatabaseDriversMssql extends Base{
199
210
  await this._currentTransaction.rollback()
200
211
 
201
212
  this._currentTransaction = null
213
+ this._transactionsCount--
202
214
  }
203
215
 
204
216
  async startSavePoint(savePointName) {
@@ -1,9 +1,11 @@
1
+ import BaseTable from "../base-table.js"
1
2
  import Column from "./column.js"
2
3
  import {digg} from "diggerize"
3
4
  import ForeignKey from "./foreign-key.js"
4
5
 
5
- export default class VelociousDatabaseDriversMssqlTable {
6
+ export default class VelociousDatabaseDriversMssqlTable extends BaseTable {
6
7
  constructor(driver, data) {
8
+ super()
7
9
  this.data = data
8
10
  this.driver = driver
9
11
  }
@@ -62,4 +64,17 @@ export default class VelociousDatabaseDriversMssqlTable {
62
64
  getName() {
63
65
  return digg(this.data, "TABLE_NAME")
64
66
  }
67
+
68
+ async truncate() {
69
+ try {
70
+ await this.getDriver().query(`TRUNCATE TABLE ${this.getOptions().quoteTableName(this.getName())}`)
71
+ } catch (error) {
72
+ if (error.message.startsWith("Query failed 'Cannot truncate table")) {
73
+ // Truncate table is really buggy for some reason - fall back to delete all rows instead
74
+ await this.getDriver().query(`DELETE FROM ${this.getOptions().quoteTableName(this.getName())}`)
75
+ } else {
76
+ throw error
77
+ }
78
+ }
79
+ }
65
80
  }
@@ -1,8 +1,53 @@
1
- export default class VelociousDatabaseDriversMysqlColumn {
1
+ import BaseColumn from "../base-column.js"
2
+ import ColumnsIndex from "./columns-index.js"
3
+ import {digg} from "diggerize"
4
+
5
+ export default class VelociousDatabaseDriversMysqlColumn extends BaseColumn {
2
6
  constructor(table, data) {
7
+ super()
3
8
  this.data = data
4
9
  this.table = table
5
10
  }
6
11
 
7
- getName = () => this.data["Field"]
12
+ async getIndexes() {
13
+ const options = this.getOptions()
14
+ const sql = `
15
+ SELECT
16
+ TABLE_SCHEMA,
17
+ TABLE_NAME,
18
+ INDEX_NAME AS index_name,
19
+ COLUMN_NAME,
20
+ SEQ_IN_INDEX,
21
+ NON_UNIQUE,
22
+ INDEX_TYPE
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())}
27
+ `
28
+ const indexesRows = await this.getDriver().query(sql)
29
+ const indexes = []
30
+
31
+ for (const indexRow of indexesRows) {
32
+ if (indexRow.NON_UNIQUE == 1) {
33
+ indexRow.is_unique = false
34
+ } else {
35
+ indexRow.is_unique = true
36
+ }
37
+
38
+ if (indexRow.index_name == "PRIMARY") {
39
+ indexRow.is_primary_key = true
40
+ } else {
41
+ indexRow.is_primary_key = false
42
+ }
43
+
44
+ const index = new ColumnsIndex(this.getTable(), indexRow)
45
+
46
+ indexes.push(index)
47
+ }
48
+
49
+ return indexes
50
+ }
51
+
52
+ getName = () => digg(this, "data", "Field")
8
53
  }
@@ -0,0 +1,10 @@
1
+ import BaseColumnsIndex from "../base-columns-index.js"
2
+ import {digg} from "diggerize"
3
+
4
+ export default class VelociousDatabaseDriversMysqlColumn extends BaseColumnsIndex {
5
+ constructor(table, data) {
6
+ super()
7
+ this.data = data
8
+ this.table = table
9
+ }
10
+ }
@@ -22,8 +22,9 @@ export default class VelociousDatabaseDriversMysql extends Base{
22
22
  this.connection = connection
23
23
  }
24
24
 
25
- disconnect() {
26
- this.connection.end()
25
+ async close() {
26
+ await this.connection.end()
27
+ this.connection = undefined
27
28
  }
28
29
 
29
30
  connectArgs() {
@@ -40,11 +41,6 @@ export default class VelociousDatabaseDriversMysql extends Base{
40
41
  return connectArgs
41
42
  }
42
43
 
43
- async close() {
44
- await this.connection.end()
45
- this.connection = undefined
46
- }
47
-
48
44
  createDatabaseSql(databaseName, args) {
49
45
  const createArgs = Object.assign({databaseName, driver: this}, args)
50
46
  const createDatabase = new CreateDatabase(createArgs)
@@ -152,7 +148,8 @@ export default class VelociousDatabaseDriversMysql extends Base{
152
148
  }
153
149
 
154
150
  async startTransaction() {
155
- return await this.query("START TRANSACTION")
151
+ await this.query("START TRANSACTION")
152
+ this._transactionsCount++
156
153
  }
157
154
 
158
155
  updateSql({conditions, data, tableName}) {
@@ -1,8 +1,10 @@
1
+ import BaseTable from "../base-table.js"
1
2
  import Column from "./column.js"
2
3
  import ForeignKey from "./foreign-key.js"
3
4
 
4
- export default class VelociousDatabaseDriversMysqlTable {
5
+ export default class VelociousDatabaseDriversMysqlTable extends BaseTable {
5
6
  constructor(driver, data) {
7
+ super()
6
8
  this.data = data
7
9
  this.driver = driver
8
10
  }
@@ -1,10 +1,45 @@
1
- export default class VelociousDatabaseDriversPgsqlColumn {
1
+ import BaseColumn from "../base-column.js"
2
+ import ColumnsIndex from "./columns-index.js"
3
+ import {digg} from "diggerize"
4
+
5
+ export default class VelociousDatabaseDriversPgsqlColumn extends BaseColumn {
2
6
  constructor(table, data) {
7
+ super()
3
8
  this.data = data
4
9
  this.table = table
5
10
  }
6
11
 
12
+ async getIndexes() {
13
+ const options = this.getOptions()
14
+
15
+ const indexesRows = await this.table.getDriver().query(`
16
+ SELECT
17
+ pg_attribute.attname AS column_name,
18
+ pg_index.indexrelid::regclass as index_name,
19
+ pg_class.relnamespace::regnamespace as schema_name,
20
+ pg_class.relname as table_name,
21
+ pg_index.indisprimary as is_primary_key,
22
+ pg_index.indisunique as is_unique
23
+ FROM pg_index
24
+ JOIN pg_class ON pg_class.oid = pg_index.indrelid
25
+ JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid AND pg_attribute.attnum = ANY(pg_index.indkey)
26
+ WHERE
27
+ pg_attribute.attname = ${options.quote(this.getName())} AND
28
+ pg_class.relname = ${options.quote(this.getTable().getName())}
29
+ `)
30
+
31
+ const indexes = []
32
+
33
+ for (const indexRow of indexesRows) {
34
+ const columnsIndex = new ColumnsIndex(this.getTable(), indexRow)
35
+
36
+ indexes.push(columnsIndex)
37
+ }
38
+
39
+ return indexes
40
+ }
41
+
7
42
  getName() {
8
- return this.data.column_name
43
+ return digg(this, "data", "column_name")
9
44
  }
10
45
  }
@@ -0,0 +1,4 @@
1
+ import BaseColumnsIndex from "../base-columns-index.js"
2
+
3
+ export default class VelociousDatabaseDriversPgsqlColumn extends BaseColumnsIndex {
4
+ }
@@ -26,8 +26,8 @@ export default class VelociousDatabaseDriversPgsql extends Base{
26
26
  this.connection = client
27
27
  }
28
28
 
29
- disconnect() {
30
- this.connection.end()
29
+ async disconnect() {
30
+ await this.connection.end()
31
31
  }
32
32
 
33
33
  connectArgs() {
@@ -71,11 +71,11 @@ export default class VelociousDatabaseDriversPgsql extends Base{
71
71
  }
72
72
 
73
73
  async disableForeignKeys() {
74
- await this.query("SET FOREIGN_KEY_CHECKS = 0")
74
+ await this.query("SET session_replication_role = 'replica'")
75
75
  }
76
76
 
77
77
  async enableForeignKeys() {
78
- await this.query("SET FOREIGN_KEY_CHECKS = 1")
78
+ await this.query("SET session_replication_role = 'origin'")
79
79
  }
80
80
 
81
81
  dropTableSql(tableName, args = {}) {
@@ -161,7 +161,8 @@ export default class VelociousDatabaseDriversPgsql extends Base{
161
161
  }
162
162
 
163
163
  async startTransaction() {
164
- return await this.query("START TRANSACTION")
164
+ await this.query("START TRANSACTION")
165
+ this._transactionsCount++
165
166
  }
166
167
 
167
168
  updateSql({conditions, data, tableName}) {
@@ -1,8 +1,10 @@
1
+ import BaseTable from "../base-table.js"
1
2
  import Column from "./column.js"
2
3
  import ForeignKey from "./foreign-key.js"
3
4
 
4
- export default class VelociousDatabaseDriversPgsqlTable {
5
+ export default class VelociousDatabaseDriversPgsqlTable extends BaseTable {
5
6
  constructor(driver, data) {
7
+ super()
6
8
  this.data = data
7
9
  this.driver = driver
8
10
  }
@@ -54,18 +54,20 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
54
54
  getType = () => "sqlite"
55
55
  insertSql = (args) => new Insert(Object.assign({driver: this}, args)).toSql()
56
56
 
57
- async getTableByName(tableName) {
57
+ async getTableByName(tableName, args) {
58
58
  const result = await this.query(`SELECT name FROM sqlite_master WHERE type = 'table' AND name = ${this.quote(tableName)} LIMIT 1`)
59
59
  const row = result[0]
60
60
 
61
- if (!row) {
61
+ if (row) {
62
+ return new Table({driver: this, row})
63
+ }
64
+
65
+ if (args?.throwError !== false) {
62
66
  const tables = await this.getTables()
63
67
  const tableNames = tables.map((table) => table.getName())
64
68
 
65
69
  throw new Error(`No table by that name: ${tableName} in ${tableNames.join(", ")}`)
66
70
  }
67
-
68
- return new Table({driver: this, row})
69
71
  }
70
72
 
71
73
  async getTables() {
@@ -1,7 +1,51 @@
1
- export default class VelociousDatabaseDriversSqliteColumn {
2
- constructor({column, driver}) {
1
+ import BaseColumn from "../base-column.js"
2
+ import ColumnsIndex from "./columns-index.js"
3
+
4
+ export default class VelociousDatabaseDriversSqliteColumn extends BaseColumn {
5
+ constructor({column, driver, table}) {
6
+ super()
3
7
  this.column = column
4
8
  this.driver = driver
9
+ this.table = table
10
+ }
11
+
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 = []
16
+
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
+ }
25
+
26
+ return indexes
27
+ }
28
+
29
+
30
+ _parseColumnsFromSQL(sql) {
31
+ const columnsSQLMatch = sql.match(/\((.+?)\)/)
32
+ const columnsSQL = columnsSQLMatch[1].split(",")
33
+ const columnNames = []
34
+
35
+ for (const column of columnsSQL) {
36
+ const matchTicks = column.match(/`(.+)`/)
37
+ const matchQuotes = column.match(/"(.+)"/)
38
+
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
+ }
46
+ }
47
+
48
+ return columnNames
5
49
  }
6
50
 
7
51
  getName() {
@@ -0,0 +1,22 @@
1
+ import BaseColumnsIndex from "../base-columns-index.js"
2
+ import {digg} from "diggerize"
3
+
4
+ export default class VelociousDatabaseDriversSqliteColumn extends BaseColumnsIndex {
5
+ constructor(table, data) {
6
+ super()
7
+ this.data = data
8
+ this.table = table
9
+ }
10
+
11
+ getName() {
12
+ return digg(this, "data", "name")
13
+ }
14
+
15
+ isPrimaryKey() {
16
+ return false
17
+ }
18
+
19
+ isUnique() {
20
+ return digg(this, "data", "unique") == 1
21
+ }
22
+ }
@@ -13,7 +13,7 @@ export default class VelociousDatabaseDriversSqliteConnectionSqlJs {
13
13
  this.connection = undefined
14
14
  }
15
15
 
16
- disconnect = () => this.saveDatabase()
16
+ disconnect = async () => await this.saveDatabase()
17
17
 
18
18
  async query(sql) {
19
19
  const result = await query(this.connection, sql)
@@ -1,8 +1,10 @@
1
+ import BaseTable from "../base-table.js"
1
2
  import Column from "./column.js"
2
3
  import ForeignKey from "./foreign-key.js"
3
4
 
4
- export default class VelociousDatabaseDriversSqliteTable {
5
+ export default class VelociousDatabaseDriversSqliteTable extends BaseTable {
5
6
  constructor({driver, row}) {
7
+ super()
6
8
  this.driver = driver
7
9
  this.row = row
8
10
  }
@@ -44,7 +44,7 @@ export default class VelociousDatabaseMigrator {
44
44
  }
45
45
 
46
46
  async migrateFiles(files, importCallback) {
47
- await this.configuration.withConnections(async () => {
47
+ await this.configuration.ensureConnections(async () => {
48
48
  for (const migration of files) {
49
49
  await this.runMigrationFile({
50
50
  migration,
@@ -90,7 +90,7 @@ export default class VelociousDatabaseMigrator {
90
90
  .filter((migration) => Boolean(migration))
91
91
  .sort((migration1, migration2) => migration1.date - migration2.date)
92
92
 
93
- await this.configuration.withConnections(async () => {
93
+ await this.configuration.ensureConnections(async () => {
94
94
  for (const migration of files) {
95
95
  await this.runMigrationFile({
96
96
  migration,
@@ -120,8 +120,7 @@ export default class VelociousDatabaseMigrator {
120
120
  }
121
121
 
122
122
  async migrationsTableExist(db) {
123
- const tables = await db.getTables()
124
- const schemaTable = tables.find((table) => table.getName() == "schema_migrations")
123
+ const schemaTable = await db.getTableByName("schema_migrations", {throwError: false})
125
124
 
126
125
  if (!schemaTable) return false
127
126
 
@@ -166,9 +165,30 @@ export default class VelociousDatabaseMigrator {
166
165
  const db = dbs[dbIdentifier]
167
166
 
168
167
  await db.withDisabledForeignKeys(async () => {
169
- for (const table of await db.getTables()) {
170
- this.logger.log(`Dropping table ${table.getName()}`)
171
- await db.dropTable(table.getName())
168
+ while (true) {
169
+ const errors = []
170
+ let anyTableDropped = false
171
+
172
+ try {
173
+ for (const table of await db.getTables()) {
174
+ this.logger.log(`Dropping table ${table.getName()}`)
175
+
176
+ try {
177
+ await db.dropTable(table.getName(), {cascade: true})
178
+ anyTableDropped = true
179
+ } catch (error) {
180
+ errors.push(error)
181
+ }
182
+ }
183
+
184
+ break
185
+ } catch (error) {
186
+ if (errors.length > 0 && anyTableDropped) {
187
+ // Retry
188
+ } else {
189
+ throw errors[0]
190
+ }
191
+ }
172
192
  }
173
193
  })
174
194
  }
@@ -17,7 +17,16 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
17
17
  for (const columnIndex in this.columns) {
18
18
  if (columnIndex > 0) indexName += "_and_"
19
19
 
20
- indexName += this.columns[columnIndex]
20
+ const column = this.columns[columnIndex]
21
+ let columnName
22
+
23
+ if (typeof column == "string") {
24
+ columnName = column
25
+ } else {
26
+ columnName = column.getName()
27
+ }
28
+
29
+ indexName += columnName
21
30
  }
22
31
 
23
32
  return indexName
@@ -1,6 +1,7 @@
1
1
  import CreateIndexBase from "./create-index-base.js"
2
2
  import * as inflection from "inflection"
3
3
  import QueryBase from "./base.js"
4
+ import restArgsError from "../../utils/rest-args-error.js"
4
5
 
5
6
  export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
6
7
  constructor({driver, ifNotExists, indexInCreateTable = true, tableData}) {
@@ -48,6 +49,9 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
48
49
 
49
50
  if (databaseType == "mssql" && type == "BOOLEAN") {
50
51
  type = "BIT"
52
+ } else if (databaseType == "mssql" && type == "UUID") {
53
+ type = "VARCHAR"
54
+ maxlength ||= 36
51
55
  }
52
56
 
53
57
  if (databaseType == "sqlite" && column.getAutoIncrement() && column.getPrimaryKey()) {
@@ -79,7 +83,19 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
79
83
  }
80
84
 
81
85
  if (typeof column.getDefault() == "function") {
82
- sql += ` DEFAULT (${column.getDefault()()})`
86
+ const defaultValue = column.getDefault()()
87
+
88
+ sql += ` DEFAULT (`
89
+
90
+ if (databaseType == "pgsql" && defaultValue == "UUID()") {
91
+ sql += "gen_random_uuid()"
92
+ } else if (databaseType == "mssql" && defaultValue == "UUID()") {
93
+ sql += "NEWID()"
94
+ } else {
95
+ sql += defaultValue
96
+ }
97
+
98
+ sql += ")"
83
99
  } else if (column.getDefault()) {
84
100
  sql += ` DEFAULT ${options.quote(column.getDefault())}`
85
101
  }
@@ -125,6 +141,24 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
125
141
 
126
142
  sql += ")"
127
143
  }
144
+
145
+ for (const column of tableData.getColumns()) {
146
+ if (!column.getIndex()) continue
147
+
148
+ const indexName = `index_on_${column.getName()}`
149
+
150
+ sql += ","
151
+
152
+ const {unique, ...restIndexArgs} = column.getIndex()
153
+
154
+ restArgsError(restIndexArgs)
155
+
156
+ if (unique) {
157
+ sql += " UNIQUE"
158
+ }
159
+
160
+ sql += ` INDEX ${options.quoteIndexName(indexName)} (${options.quoteColumnName(column.getName())})`
161
+ }
128
162
  }
129
163
 
130
164
  sql += ")"
@@ -147,8 +181,28 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
147
181
 
148
182
  sqls.push(sql)
149
183
  }
184
+
185
+ for (const column of tableData.getColumns()) {
186
+ if (!column.getIndex()) continue
187
+
188
+ const indexName = `index_on_${column.getName()}`
189
+ const {unique, ...restIndexArgs} = column.getIndex()
190
+
191
+ restArgsError(restIndexArgs)
192
+
193
+ const createIndexArgs = {
194
+ columns: [column.getName()],
195
+ driver: this.getDriver(),
196
+ name: indexName,
197
+ tableName: tableData.getName(),
198
+ unique
199
+ }
200
+ const sql = new CreateIndexBase(createIndexArgs).toSql()
201
+
202
+ sqls.push(sql)
203
+ }
150
204
  }
151
205
 
152
- return [sql]
206
+ return sqls
153
207
  }
154
208
  }