velocious 1.0.29 → 1.0.31

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 (63) hide show
  1. package/package.json +5 -2
  2. package/peak_flow.yml +21 -0
  3. package/spec/cli/commands/db/create-spec.js +14 -2
  4. package/spec/cli/commands/db/migrate-spec.js +56 -25
  5. package/spec/database/drivers/mysql/connection-spec.js +2 -2
  6. package/spec/dummy/index.js +8 -7
  7. package/spec/dummy/src/config/configuration.example.js +25 -3
  8. package/spec/dummy/src/config/configuration.mariadb.js +97 -0
  9. package/spec/dummy/src/config/configuration.peakflow.mariadb.js +26 -3
  10. package/spec/dummy/src/config/configuration.peakflow.mssql.js +75 -0
  11. package/spec/dummy/src/config/configuration.peakflow.sqlite.js +27 -3
  12. package/spec/dummy/src/config/configuration.sqlite.js +58 -4
  13. package/spec/dummy/src/database/migrations/20250903112845-create-accounts.js +18 -0
  14. package/src/cli/commands/db/create.js +25 -15
  15. package/src/cli/commands/db/migrate.js +4 -82
  16. package/src/cli/commands/db/reset.js +40 -0
  17. package/src/configuration.js +71 -18
  18. package/src/database/drivers/base.js +97 -13
  19. package/src/database/drivers/mssql/column.js +10 -0
  20. package/src/database/drivers/mssql/connect-connection.js +12 -0
  21. package/src/database/drivers/mssql/foreign-key.js +13 -0
  22. package/src/database/drivers/mssql/index.js +216 -0
  23. package/src/database/drivers/mssql/options.js +43 -0
  24. package/src/database/drivers/mssql/query-parser.js +4 -0
  25. package/src/database/drivers/mssql/sql/create-database.js +28 -0
  26. package/src/database/drivers/mssql/sql/create-index.js +4 -0
  27. package/src/database/drivers/mssql/sql/create-table.js +4 -0
  28. package/src/database/drivers/mssql/sql/delete.js +19 -0
  29. package/src/database/drivers/mssql/sql/drop-table.js +4 -0
  30. package/src/database/drivers/mssql/sql/insert.js +4 -0
  31. package/src/database/drivers/mssql/sql/update.js +31 -0
  32. package/src/database/drivers/mssql/table.js +65 -0
  33. package/src/database/drivers/mysql/index.js +29 -18
  34. package/src/database/drivers/mysql/query.js +1 -1
  35. package/src/database/drivers/mysql/sql/drop-table.js +4 -0
  36. package/src/database/drivers/sqlite/base.js +25 -23
  37. package/src/database/drivers/sqlite/index.native.js +10 -1
  38. package/src/database/drivers/sqlite/sql/drop-table.js +4 -0
  39. package/src/database/initializer-from-require-context.js +3 -1
  40. package/src/database/migration/index.js +32 -23
  41. package/src/database/migrator.js +177 -28
  42. package/src/database/pool/async-tracked-multi-connection.js +2 -3
  43. package/src/database/pool/base.js +15 -3
  44. package/src/database/query/base.js +24 -4
  45. package/src/database/query/create-database-base.js +1 -3
  46. package/src/database/query/create-index-base.js +13 -4
  47. package/src/database/query/create-table-base.js +27 -11
  48. package/src/database/query/drop-table-base.js +39 -0
  49. package/src/database/query/index.js +5 -1
  50. package/src/database/query/insert-base.js +31 -6
  51. package/src/database/query-parser/limit-parser.js +11 -2
  52. package/src/database/query-parser/options.js +20 -8
  53. package/src/database/record/index.js +19 -3
  54. package/src/database/use-database.js +5 -4
  55. package/src/routes/base-route.js +7 -0
  56. package/src/routes/post-route.js +24 -0
  57. package/src/routes/resolver.js +1 -1
  58. package/src/templates/configuration.js +36 -3
  59. package/src/testing/test-runner.js +1 -1
  60. package/src/utils/nest-callbacks.js +15 -0
  61. package/src/big-brother.js +0 -37
  62. package/src/database/migrate-from-require-context.js +0 -72
  63. package/src/spec/index.js +0 -5
@@ -3,26 +3,43 @@ import restArgsError from "../../utils/rest-args-error.js"
3
3
  import TableData, {TableColumn} from "../table-data/index.js"
4
4
 
5
5
  export default class VelociousDatabaseMigration {
6
- constructor({configuration}) {
6
+ static onDatabases(databaseIdentifiers) {
7
+ this._databaseIdentifiers = databaseIdentifiers
8
+ }
9
+
10
+ static getDatabaseIdentifiers() {
11
+ return this._databaseIdentifiers
12
+ }
13
+
14
+ constructor({configuration, databaseIdentifier = "default", db}) {
15
+ if (!databaseIdentifier) throw new Error("No database identifier given")
16
+ if (!db) throw new Error("No 'db' given")
17
+
7
18
  this.configuration = configuration
19
+ this._databaseIdentifier = databaseIdentifier
20
+ this._db = db
21
+ }
22
+
23
+ _getDatabaseIdentifier() {
24
+ if (!this._databaseIdentifier) throw new Error("No database identifier set")
25
+
26
+ return this._databaseIdentifier
8
27
  }
9
28
 
10
29
  async addColumn(tableName, columnName, columnType, args) {
11
- const databasePool = this.configuration.getDatabasePool()
12
30
  const tableColumnArgs = Object.assign({type: columnType}, args)
13
31
 
14
- const sqls = databasePool.alterTableSql({
32
+ const sqls = this._db.alterTableSql({
15
33
  columns: [new TableColumn(columnName, tableColumnArgs)],
16
34
  tableName
17
35
  })
18
36
 
19
37
  for (const sql of sqls) {
20
- await databasePool.query(sql)
38
+ await this._db.query(sql)
21
39
  }
22
40
  }
23
41
 
24
42
  async addIndex(tableName, columns, args) {
25
- const databasePool = this.configuration.getDatabasePool()
26
43
  const createIndexArgs = Object.assign(
27
44
  {
28
45
  columns,
@@ -30,25 +47,24 @@ export default class VelociousDatabaseMigration {
30
47
  },
31
48
  args
32
49
  )
33
- const sql = databasePool.createIndexSql(createIndexArgs)
50
+ const sql = this._db.createIndexSql(createIndexArgs)
34
51
 
35
- await databasePool.query(sql)
52
+ await this._db.query(sql)
36
53
  }
37
54
 
38
55
  async addForeignKey(tableName, referenceName) {
39
56
  const referenceNameUnderscore = inflection.underscore(referenceName)
40
57
  const tableNameUnderscore = inflection.underscore(tableName)
41
58
  const columnName = `${referenceNameUnderscore}_id`
42
- const databasePool = this.configuration.getDatabasePool()
43
59
  const foreignKeyName = `fk_${tableName}_${referenceName}`
44
60
  let sql = ""
45
61
 
46
- sql += `ALTER TABLE ${databasePool.quoteTable(tableName)}`
62
+ sql += `ALTER TABLE ${this._db.quoteTable(tableName)}`
47
63
  sql += ` ADD CONSTRAINT ${foreignKeyName} `
48
- sql += ` FOREIGN KEY (${databasePool.quoteColumn(columnName)})`
64
+ sql += ` FOREIGN KEY (${this._db.quoteColumn(columnName)})`
49
65
  sql += ` REFERENCES ${tableNameUnderscore}(id)`
50
66
 
51
- await databasePool.query(sql)
67
+ await this._db.query(sql)
52
68
  }
53
69
 
54
70
  async addReference(tableName, referenceName, args) {
@@ -74,8 +90,9 @@ export default class VelociousDatabaseMigration {
74
90
  callback = arg2
75
91
  }
76
92
 
77
- const databasePool = this.configuration.getDatabasePool()
78
93
  const {id = {}, ...restArgs} = args
94
+ const databaseIdentifier = this._getDatabaseIdentifier()
95
+ const databasePool = this.configuration.getDatabasePool(databaseIdentifier)
79
96
  const {default: idDefault, type: idType = databasePool.primaryKeyType(), ...restArgsId} = id
80
97
  const tableData = new TableData(tableName)
81
98
 
@@ -90,23 +107,15 @@ export default class VelociousDatabaseMigration {
90
107
  callback(tableData)
91
108
  }
92
109
 
93
- const sqls = databasePool.createTableSql(tableData)
110
+ const sqls = this._db.createTableSql(tableData)
94
111
 
95
112
  for (const sql of sqls) {
96
- await databasePool.query(sql)
113
+ await this._db.query(sql)
97
114
  }
98
115
  }
99
116
 
100
- getConnection() {
101
- const connection = this.configuration.getDatabasePool().getCurrentConnection()
102
-
103
- if (!connection) throw new Error("Couldn't get current connection")
104
-
105
- return connection
106
- }
107
-
108
117
  async tableExists(tableName) {
109
- const exists = await this.getConnection().tableExists(tableName)
118
+ const exists = await this._db.tableExists(tableName)
110
119
 
111
120
  return exists
112
121
  }
@@ -1,75 +1,224 @@
1
1
  import {digg} from "diggerize"
2
+ import * as inflection from "inflection"
3
+ import {Logger} from "../logger.js"
2
4
  import TableData from "./table-data/index.js"
3
5
 
4
6
  export default class VelociousDatabaseMigrator {
5
7
  constructor({configuration}) {
6
8
  this.configuration = configuration
9
+ this.logger = new Logger(this)
7
10
  }
8
11
 
9
12
  async prepare() {
10
- const exists = await this.migrationsTableExist()
11
-
12
- if (!exists) await this.createMigrationsTable()
13
-
13
+ await this.createMigrationsTable()
14
14
  await this.loadMigrationsVersions()
15
15
  }
16
16
 
17
17
  async createMigrationsTable() {
18
- const schemaMigrationsTable = new TableData("schema_migrations", {ifNotExists: true})
18
+ const dbs = await this.configuration.getCurrentConnections()
19
+
20
+ for (const db of Object.values(dbs)) {
21
+ if (await this.migrationsTableExist(db)) continue
22
+
23
+ const schemaMigrationsTable = new TableData("schema_migrations", {ifNotExists: true})
19
24
 
20
- schemaMigrationsTable.string("version", {null: false, primaryKey: true})
25
+ schemaMigrationsTable.string("version", {null: false, primaryKey: true})
21
26
 
22
- await this.configuration.getDatabasePool().withConnection(async (db) => {
23
27
  const createSchemaMigrationsTableSqls = db.createTableSql(schemaMigrationsTable)
24
28
 
25
29
  for (const createSchemaMigrationsTableSql of createSchemaMigrationsTableSqls) {
26
30
  await db.query(createSchemaMigrationsTableSql)
27
31
  }
28
- })
32
+ }
29
33
  }
30
34
 
31
- hasRunMigrationVersion(version) {
32
- if (!this.migrationsVersions) {
33
- throw new Error("Migrations versions hasn't been loaded yet")
34
- }
35
+ hasRunMigrationVersion(dbIdentifier, version) {
36
+ if (!this.migrationsVersions) throw new Error("Migrations versions hasn't been loaded yet")
37
+ if (!this.migrationsVersions[dbIdentifier]) throw new Error(`Migrations versions hasn't been loaded yet for db: ${dbIdentifier}`)
35
38
 
36
- if (version in this.migrationsVersions) {
39
+ if (version in this.migrationsVersions[dbIdentifier]) {
37
40
  return true
38
41
  }
39
42
 
40
43
  return false
41
44
  }
42
45
 
43
- async loadMigrationsVersions() {
44
- const db = this.configuration.getDatabasePool()
46
+ async migrateFiles(files, importCallback) {
47
+ await this.configuration.withConnections(async () => {
48
+ for (const migration of files) {
49
+ await this.runMigrationFile({
50
+ migration,
51
+ requireMigration: async () => {
52
+ const migrationImport = await importCallback(migration.fullPath)
53
+
54
+ return migrationImport.default
55
+ }
56
+ })
57
+ }
58
+ })
59
+ }
60
+
61
+ async migrateFilesFromRequireContext(requireContext) {
62
+ const files = requireContext
63
+ .keys()
64
+ .map((file) => {
65
+ // "13,14" because somes "require-context"-npm-module deletes first character!?
66
+ const match = file.match(/(\d{13,14})-(.+)\.js$/)
67
+
68
+ if (!match) return null
45
69
 
70
+ // Fix require-context-npm-module deletes first character
71
+ let fileName = file
72
+ let dateNumber = match[1]
73
+
74
+ if (dateNumber.length == 13) {
75
+ dateNumber = `2${dateNumber}`
76
+ fileName = `2${fileName}`
77
+ }
78
+
79
+ // Parse regex
80
+ const date = parseInt(dateNumber)
81
+ const migrationName = match[2]
82
+ const migrationClassName = inflection.camelize(migrationName.replaceAll("-", "_"))
83
+
84
+ return {
85
+ file: fileName,
86
+ date,
87
+ migrationClassName
88
+ }
89
+ })
90
+ .filter((migration) => Boolean(migration))
91
+ .sort((migration1, migration2) => migration1.date - migration2.date)
92
+
93
+ await this.configuration.withConnections(async () => {
94
+ for (const migration of files) {
95
+ await this.runMigrationFile({
96
+ migration,
97
+ requireMigration: () => requireContext(migration.file).default
98
+ })
99
+ }
100
+ })
101
+ }
102
+
103
+ async loadMigrationsVersions() {
46
104
  this.migrationsVersions = {}
47
105
 
48
- await db.withConnection(async () => {
106
+ const dbs = await this.configuration.getCurrentConnections()
107
+
108
+ for (const dbIdentifier in dbs) {
109
+ const db = dbs[dbIdentifier]
49
110
  const rows = await db.select("schema_migrations")
50
111
 
112
+ this.migrationsVersions[dbIdentifier] = {}
113
+
51
114
  for (const row of rows) {
52
115
  const version = digg(row, "version")
53
116
 
54
- this.migrationsVersions[version] = true
117
+ this.migrationsVersions[dbIdentifier][version] = true
55
118
  }
56
- })
119
+ }
120
+ }
121
+
122
+ async migrationsTableExist(db) {
123
+ const tables = await db.getTables()
124
+ const schemaTable = tables.find((table) => table.getName() == "schema_migrations")
125
+
126
+ if (!schemaTable) return false
127
+
128
+ return true
129
+ }
130
+
131
+ async executeRequireContext(requireContext) {
132
+ const migrationFiles = requireContext.keys()
133
+
134
+ files = migrationFiles
135
+ .map((file) => {
136
+ const match = file.match(/^(\d{14})-(.+)\.js$/)
137
+
138
+ if (!match) return null
139
+
140
+ const date = parseInt(match[1])
141
+ const migrationName = match[2]
142
+ const migrationClassName = inflection.camelize(migrationName)
143
+
144
+ return {
145
+ file,
146
+ fullPath: `${migrationsPath}/${file}`,
147
+ date,
148
+ migrationClassName
149
+ }
150
+ })
151
+ .filter((migration) => Boolean(migration))
152
+ .sort((migration1, migration2) => migration1.date - migration2.date)
153
+
154
+ for (const migration of files) {
155
+ await this.runMigrationFile({
156
+ migration,
157
+ require: requireContext(migration.file).default
158
+ })
159
+ }
57
160
  }
58
161
 
59
- async migrationsTableExist() {
60
- let exists = false
162
+ async reset() {
163
+ const dbs = await this.configuration.getCurrentConnections()
61
164
 
62
- await this.configuration.getDatabasePool().withConnection(async (db) => {
63
- const tables = await db.getTables()
165
+ for (const dbIdentifier in dbs) {
166
+ const db = dbs[dbIdentifier]
64
167
 
65
- for (const table of tables) {
66
- if (table.getName() == "schema_migrations") {
67
- exists = true
68
- break
168
+ 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())
69
172
  }
173
+ })
174
+ }
175
+ }
176
+
177
+ async runMigrationFile({migration, requireMigration}) {
178
+ if (!this.configuration) throw new Error("No configuration set")
179
+ if (!this.configuration.isDatabasePoolInitialized()) await this.configuration.initializeDatabasePool()
180
+
181
+ const dbs = await this.configuration.getCurrentConnections()
182
+ const migrationClass = await requireMigration()
183
+ const migrationDatabaseIdentifiers = migrationClass.getDatabaseIdentifiers() || ["default"]
184
+
185
+ for (const dbIdentifier in dbs) {
186
+ if (!migrationDatabaseIdentifiers.includes(dbIdentifier)) {
187
+ this.logger.debug(`${dbIdentifier} shouldn't run migration ${migration.file}`, {migrationDatabaseIdentifiers})
188
+ continue
70
189
  }
71
- })
72
190
 
73
- return exists
191
+ if (this.hasRunMigrationVersion(dbIdentifier, migration.date)) {
192
+ this.logger.debug(`${dbIdentifier} has already run migration ${migration.file}`)
193
+ continue
194
+ }
195
+
196
+ this.logger.debug(`Running migration on ${dbIdentifier}: ${migration.file}`, {migrationDatabaseIdentifiers})
197
+
198
+ const db = dbs[dbIdentifier]
199
+ const MigrationClass = migrationClass
200
+ const migrationInstance = new MigrationClass({
201
+ configuration: this.configuration,
202
+ db
203
+ })
204
+
205
+ if (migrationInstance.change) {
206
+ await migrationInstance.change()
207
+ } else if (migrationInstance.up) {
208
+ await migrationInstance.up()
209
+ } else {
210
+ throw new Error(`'change' or 'up' didn't exist on migration: ${migration.file}`)
211
+ }
212
+
213
+ const dateString = digg(migration, "date")
214
+ const existingSchemaMigrations = await db.newQuery()
215
+ .from("schema_migrations")
216
+ .where({version: dateString})
217
+ .results()
218
+
219
+ if (existingSchemaMigrations.length == 0) {
220
+ await db.insert({tableName: "schema_migrations", data: {version: dateString}})
221
+ }
222
+ }
74
223
  }
75
224
  }
@@ -1,14 +1,13 @@
1
1
  import {AsyncLocalStorage} from "async_hooks"
2
2
  import BasePool from "./base.js"
3
3
 
4
- let idSeq = 0
5
-
6
4
  export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends BasePool {
7
5
  constructor(args = {}) {
8
6
  super(args)
9
7
  this.connections = []
10
8
  this.connectionsInUse = {}
11
9
  this.asyncLocalStorage = new AsyncLocalStorage()
10
+ this.idSeq = 0
12
11
  }
13
12
 
14
13
  checkin = (connection) => {
@@ -32,7 +31,7 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
32
31
 
33
32
  if (connection.getIdSeq() !== undefined) throw new Error(`Connection already has an ID-seq - is it in use? ${connection.getIdSeq()}`)
34
33
 
35
- const id = idSeq++
34
+ const id = this.idSeq++
36
35
 
37
36
  connection.setIdSeq(id)
38
37
  this.connectionsInUse[id] = connection
@@ -1,5 +1,6 @@
1
1
  import Configuration from "../../configuration.js"
2
2
  import {digg} from "diggerize"
3
+ import {Logger} from "../../logger.js"
3
4
 
4
5
  if (!globalThis.velociousDatabasePoolBase) {
5
6
  globalThis.velociousDatabasePoolBase = {
@@ -18,11 +19,19 @@ class VelociousDatabasePoolBase {
18
19
 
19
20
  constructor(args = {}) {
20
21
  this.configuration = args.configuration || Configuration.current()
22
+
23
+ if (!this.configuration) throw new Error("No configuration given")
24
+ if (!args.identifier) throw new Error("No identifier was given")
25
+
21
26
  this.connections = []
22
27
  this.connectionsInUse = {}
28
+ this.identifier = args.identifier
29
+ this.logger = new Logger(this)
23
30
  }
24
31
 
25
- getConfiguration = () => digg(this, "configuration", "database", "default", "master")
32
+ getConfiguration() {
33
+ return digg(this.configuration.getDatabaseConfiguration(), this.identifier)
34
+ }
26
35
 
27
36
  setCurrent() {
28
37
  globalThis.velociousDatabasePoolBase.current = this
@@ -33,8 +42,11 @@ class VelociousDatabasePoolBase {
33
42
  }
34
43
 
35
44
  async spawnConnection() {
36
- const defaultConfig = this.getConfiguration()
37
- const connection = await this.spawnConnectionWithConfiguration(defaultConfig)
45
+ const databaseConfig = this.getConfiguration()
46
+
47
+ this.logger.debug("spawnConnection", {identifier: this.identifier, databaseConfig})
48
+
49
+ const connection = await this.spawnConnectionWithConfiguration(databaseConfig)
38
50
 
39
51
  return connection
40
52
  }
@@ -1,10 +1,30 @@
1
+ import restArgsError from "../../utils/rest-args-error.js"
2
+
1
3
  export default class VelociousDatabaseQueryBase {
2
- constructor({driver}) {
3
- this.driver = driver
4
+ constructor({driver, options, ...restArgs}) {
5
+ restArgsError(restArgs)
6
+
7
+ this._driver = driver
8
+ this._options = options || driver.options()
9
+
10
+ if (!this._options) throw new Error("No database options was given or could be gotten from driver")
11
+ }
12
+
13
+ getConfiguration() {
14
+ return this.getDriver().getConfiguration()
4
15
  }
5
16
 
6
- getDriver = () => this.driver
7
- getOptions = () => this.getDriver()?.options()
17
+ getDriver() {
18
+ return this._driver
19
+ }
20
+
21
+ getOptions() {
22
+ return this._options
23
+ }
24
+
25
+ getDatabaseType() {
26
+ return this.getDriver().getType()
27
+ }
8
28
 
9
29
  toSql() {
10
30
  throw new Error("'toSql' wasn't implemented")
@@ -1,4 +1,3 @@
1
- import {digs} from "diggerize"
2
1
  import QueryBase from "./base.js"
3
2
 
4
3
  export default class VelociousDatabaseQueryCreateDatabaseBase extends QueryBase {
@@ -10,12 +9,11 @@ export default class VelociousDatabaseQueryCreateDatabaseBase extends QueryBase
10
9
 
11
10
  toSql() {
12
11
  const {databaseName} = this
13
- const {tableQuote} = digs(this.getOptions(), "tableQuote")
14
12
  let sql = "CREATE DATABASE"
15
13
 
16
14
  if (this.ifNotExists) sql += " IF NOT EXISTS"
17
15
 
18
- sql += ` ${tableQuote}${databaseName}${tableQuote}`
16
+ sql += ` ${this.getOptions().quoteDatabaseName(databaseName)}`
19
17
 
20
18
  return sql
21
19
  }
@@ -24,8 +24,8 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
24
24
  }
25
25
 
26
26
  toSql() {
27
+ const options = this.getOptions()
27
28
  const {tableName} = this
28
- const {columnQuote, indexQuote, tableQuote} = digs(this.getOptions(), "columnQuote", "indexQuote", "tableQuote")
29
29
  let sql = "CREATE"
30
30
 
31
31
  if (this.unique) sql += " UNIQUE"
@@ -34,13 +34,22 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
34
34
 
35
35
  if (this.ifNotExists) sql += " IF NOT EXISTS"
36
36
 
37
- sql += ` ${indexQuote}${this.name || this.generateIndexName()}${indexQuote}`
38
- sql += ` ON ${tableQuote}${tableName}${tableQuote} (`
37
+ sql += ` ${options.quoteIndexName(this.name || this.generateIndexName())}`
38
+ sql += ` ON ${options.quoteTableName(tableName)} (`
39
39
 
40
40
  for (const columnIndex in this.columns) {
41
41
  if (columnIndex > 0) sql += ", "
42
42
 
43
- sql += `${columnQuote}${this.columns[columnIndex]}${columnQuote}`
43
+ const column = this.columns[columnIndex]
44
+ let columnName
45
+
46
+ if (typeof column == "string") {
47
+ columnName = column
48
+ } else {
49
+ columnName = column.getName()
50
+ }
51
+
52
+ sql += `${options.quoteColumnName(columnName)}`
44
53
  }
45
54
 
46
55
  sql += ")"
@@ -10,18 +10,24 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
10
10
  this.tableData = tableData
11
11
  }
12
12
 
13
- getConfiguration = () => this.driver.getConfiguration()
14
-
15
13
  toSql() {
16
- const databaseType = this.getConfiguration().getDatabaseType()
14
+ const databaseType = this.getDatabaseType()
15
+ const driver = this.getDriver()
16
+ const options = this.getOptions()
17
17
  const {tableData} = this
18
18
  const sqls = []
19
+ const ifNotExists = this.ifNotExists || tableData.getIfNotExists()
20
+ let sql = ""
21
+
22
+ if (databaseType == "mssql" && ifNotExists) {
23
+ sql += `IF NOT EXISTS(SELECT * FROM [sysobjects] WHERE [name] = ${options.quote(tableData.getName())} AND [xtype] = 'U') BEGIN `
24
+ }
19
25
 
20
- let sql = "CREATE TABLE"
26
+ sql += "CREATE TABLE"
21
27
 
22
- if (this.ifNotExists || tableData.getIfNotExists()) sql += " IF NOT EXISTS"
28
+ if (databaseType != "mssql" && ifNotExists) sql += " IF NOT EXISTS"
23
29
 
24
- sql += ` ${tableData.getName()} (`
30
+ sql += ` ${options.quoteTableName(tableData.getName())} (`
25
31
 
26
32
  let columnCount = 0
27
33
 
@@ -42,16 +48,22 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
42
48
 
43
49
  if (columnCount > 1) sql += ", "
44
50
 
45
- sql += `${this.driver.quoteColumn(column.getName())} ${type}`
51
+ sql += `${options.quoteColumnName(column.getName())} ${type}`
46
52
 
47
53
  if (maxlength !== undefined) sql += `(${maxlength})`
48
54
 
49
- if (column.getAutoIncrement() && this.driver.shouldSetAutoIncrementWhenPrimaryKey()) sql += " AUTO_INCREMENT"
55
+ if (column.getAutoIncrement() && driver.shouldSetAutoIncrementWhenPrimaryKey()) {
56
+ if (databaseType == "mssql") {
57
+ sql += " IDENTITY"
58
+ } else {
59
+ sql += " AUTO_INCREMENT"
60
+ }
61
+ }
50
62
 
51
63
  if (typeof column.getDefault() == "function") {
52
64
  sql += ` DEFAULT (${column.getDefault()()})`
53
65
  } else if (column.getDefault()) {
54
- sql += ` DEFAULT ${this.driver.quote(column.getDefault())}`
66
+ sql += ` DEFAULT ${options.quote(column.getDefault())}`
55
67
  }
56
68
 
57
69
  if (column.getPrimaryKey()) sql += " PRIMARY KEY"
@@ -67,7 +79,7 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
67
79
  throw new Error(`Unknown foreign key type given: ${column.getForeignKey()} (${typeof column.getForeignKey()})`)
68
80
  }
69
81
 
70
- sql += ` REFERENCES ${this.driver.quoteTable(foreignKeyTable)}(${this.driver.quoteColumn(foreignKeyColumn)})`
82
+ sql += ` REFERENCES ${driver.quoteTable(foreignKeyTable)}(${driver.quoteColumn(foreignKeyColumn)})`
71
83
  }
72
84
  }
73
85
 
@@ -90,7 +102,7 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
90
102
  index.getColumns().forEach((column, columnIndex) => {
91
103
  if (columnIndex > 0) sql += ", "
92
104
 
93
- sql += this.driver.quoteColumn(column.name)
105
+ sql += driver.quoteColumn(column.name)
94
106
  })
95
107
 
96
108
  sql += ")"
@@ -99,6 +111,10 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
99
111
 
100
112
  sql += ")"
101
113
 
114
+ if (databaseType == "mssql" && ifNotExists) {
115
+ sql += " END"
116
+ }
117
+
102
118
  sqls.push(sql)
103
119
 
104
120
  if (!this.indexInCreateTable) {
@@ -0,0 +1,39 @@
1
+ import QueryBase from "./base.js"
2
+ import restArgsError from "../../utils/rest-args-error.js"
3
+
4
+ export default class VelociousDatabaseQueryDropTableBase extends QueryBase {
5
+ constructor({driver, ifExists, options, tableName, ...restArgs}) {
6
+ super({driver, options})
7
+
8
+ restArgsError(restArgs)
9
+
10
+ this.ifExists = ifExists
11
+ this.tableName = tableName
12
+ }
13
+
14
+ toSql() {
15
+ const databaseType = this.getDatabaseType()
16
+ const options = this.getOptions()
17
+ const {ifExists, tableName} = this
18
+ const sqls = []
19
+ let sql = ""
20
+
21
+ if (databaseType == "mssql" && ifExists) {
22
+ sql += `IF EXISTS(SELECT * FROM [sysobjects] WHERE [name] = ${options.quote(tableName)} AND [xtype] = 'U') BEGIN `
23
+ }
24
+
25
+ sql += "DROP TABLE"
26
+
27
+ if (databaseType != "mssql" && ifExists) sql += " IF EXISTS"
28
+
29
+ sql += ` ${options.quoteTableName(tableName)}`
30
+
31
+ if (databaseType == "mssql" && ifExists) {
32
+ sql += " END"
33
+ }
34
+
35
+ sqls.push(sql)
36
+
37
+ return [sql]
38
+ }
39
+ }
@@ -218,9 +218,13 @@ export default class VelociousDatabaseQuery {
218
218
  return results
219
219
  }
220
220
 
221
+ async results() {
222
+ return await this._executeQuery()
223
+ }
224
+
221
225
  async toArray() {
222
226
  const models = []
223
- const results = await this._executeQuery()
227
+ const results = await this.results()
224
228
 
225
229
  for (const result of results) {
226
230
  const model = new this.modelClass()