velocious 1.0.28 → 1.0.30
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 +5 -2
- package/peak_flow.yml +21 -0
- package/spec/cli/commands/db/create-spec.js +14 -2
- package/spec/cli/commands/db/migrate-spec.js +56 -25
- package/spec/database/drivers/mysql/connection-spec.js +2 -2
- package/spec/dummy/index.js +8 -7
- package/spec/dummy/src/config/configuration.example.js +25 -3
- package/spec/dummy/src/config/configuration.mariadb.js +97 -0
- package/spec/dummy/src/config/configuration.peakflow.mariadb.js +26 -3
- package/spec/dummy/src/config/configuration.peakflow.mssql.js +75 -0
- package/spec/dummy/src/config/configuration.peakflow.sqlite.js +27 -3
- package/spec/dummy/src/config/configuration.sqlite.js +58 -4
- package/spec/dummy/src/config/routes.js +2 -0
- package/spec/dummy/src/database/migrations/20250903112845-create-accounts.js +18 -0
- package/spec/dummy/src/routes/_root/controller.js +11 -0
- package/spec/dummy/src/routes/projects/controller.js +0 -1
- package/spec/http-server/root-get-spec.js +26 -0
- package/src/cli/commands/db/create.js +25 -15
- package/src/cli/commands/db/migrate.js +4 -82
- package/src/cli/commands/db/reset.js +40 -0
- package/src/configuration.js +71 -18
- package/src/database/drivers/base.js +97 -13
- package/src/database/drivers/mssql/column.js +10 -0
- package/src/database/drivers/mssql/connect-connection.js +12 -0
- package/src/database/drivers/mssql/foreign-key.js +13 -0
- package/src/database/drivers/mssql/index.js +216 -0
- package/src/database/drivers/mssql/options.js +43 -0
- package/src/database/drivers/mssql/query-parser.js +4 -0
- package/src/database/drivers/mssql/sql/create-database.js +28 -0
- package/src/database/drivers/mssql/sql/create-index.js +4 -0
- package/src/database/drivers/mssql/sql/create-table.js +4 -0
- package/src/database/drivers/mssql/sql/delete.js +19 -0
- package/src/database/drivers/mssql/sql/drop-table.js +4 -0
- package/src/database/drivers/mssql/sql/insert.js +4 -0
- package/src/database/drivers/mssql/sql/update.js +31 -0
- package/src/database/drivers/mssql/table.js +65 -0
- package/src/database/drivers/mysql/index.js +29 -18
- package/src/database/drivers/mysql/query.js +1 -1
- package/src/database/drivers/mysql/sql/drop-table.js +4 -0
- package/src/database/drivers/sqlite/base.js +25 -23
- package/src/database/drivers/sqlite/index.native.js +10 -1
- package/src/database/drivers/sqlite/sql/drop-table.js +4 -0
- package/src/database/initializer-from-require-context.js +3 -1
- package/src/database/migration/index.js +32 -23
- package/src/database/migrator.js +176 -27
- package/src/database/pool/async-tracked-multi-connection.js +2 -3
- package/src/database/pool/base.js +15 -3
- package/src/database/query/base.js +24 -4
- package/src/database/query/create-database-base.js +1 -3
- package/src/database/query/create-index-base.js +13 -4
- package/src/database/query/create-table-base.js +27 -11
- package/src/database/query/drop-table-base.js +39 -0
- package/src/database/query/index.js +5 -1
- package/src/database/query/insert-base.js +31 -6
- package/src/database/query-parser/limit-parser.js +11 -2
- package/src/database/query-parser/options.js +20 -8
- package/src/database/record/index.js +19 -3
- package/src/database/use-database.js +1 -1
- package/src/routes/get-route.js +6 -2
- package/src/routes/resolver.js +4 -2
- package/src/templates/configuration.js +36 -3
- package/src/testing/test-runner.js +1 -1
- package/src/utils/nest-callbacks.js +15 -0
- package/src/big-brother.js +0 -37
- package/src/database/migrate-from-require-context.js +0 -72
- package/src/spec/index.js +0 -5
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Migration from "../../../../../src/database/migration/index.js"
|
|
2
|
+
|
|
3
|
+
class CreateAccounts extends Migration {
|
|
4
|
+
async up() {
|
|
5
|
+
await this.createTable("accounts", (t) => {
|
|
6
|
+
t.string("name")
|
|
7
|
+
t.timestamps()
|
|
8
|
+
})
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async down() {
|
|
12
|
+
await this.dropTable("accounts")
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
CreateAccounts.onDatabases(["mssql"])
|
|
17
|
+
|
|
18
|
+
export default CreateAccounts
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import fetch from "node-fetch"
|
|
2
|
+
import Dummy from "../dummy/index.js"
|
|
3
|
+
|
|
4
|
+
describe("HttpServer", () => {
|
|
5
|
+
it("handles root get requests", async () => {
|
|
6
|
+
await Dummy.run(async () => {
|
|
7
|
+
const response = await fetch("http://localhost:3006/ping")
|
|
8
|
+
const text = await response.text()
|
|
9
|
+
|
|
10
|
+
expect(response.status).toEqual(200)
|
|
11
|
+
expect(response.statusText).toEqual("OK")
|
|
12
|
+
expect(text).toEqual("{\"message\":\"Pong\"}")
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it("returns a 404 error when a root get isn't found", async () => {
|
|
17
|
+
await Dummy.run(async () => {
|
|
18
|
+
const response = await fetch("http://localhost:3006/doesnt-exist")
|
|
19
|
+
const text = await response.text()
|
|
20
|
+
|
|
21
|
+
expect(response.status).toEqual(404)
|
|
22
|
+
expect(response.statusText).toEqual("Not Found")
|
|
23
|
+
expect(text).toEqual("Not found!\n")
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -1,32 +1,42 @@
|
|
|
1
1
|
import BaseCommand from "../../base-command.js"
|
|
2
2
|
import {digg} from "diggerize"
|
|
3
|
+
import {incorporate} from "incorporator"
|
|
3
4
|
import TableData from "../../../database/table-data/index.js"
|
|
4
5
|
|
|
5
6
|
export default class DbCreate extends BaseCommand{
|
|
6
7
|
async execute() {
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
for (const databaseIdentifier of this.configuration.getDatabaseIdentifiers()) {
|
|
9
|
+
const databaseType = this.configuration.getDatabaseType(databaseIdentifier)
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
this.databasePool = this.configuration.getDatabasePool(databaseIdentifier)
|
|
12
|
+
this.newConfiguration = incorporate({}, this.databasePool.getConfiguration())
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
this.newConfiguration.database = this.newConfiguration.useDatabase || "mysql"
|
|
14
|
+
if (this.args.testing) this.result = []
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
// Use a database known to exist. Since we are creating the database, it shouldn't actually exist which would make connecting fail.
|
|
17
|
+
this.newConfiguration.database = this.newConfiguration.useDatabase || "mysql"
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
// Login can fail because given db name doesn't exist, which it might not because we are trying to create it right now.
|
|
20
|
+
if (databaseType == "mssql" && this.newConfiguration.sqlConfig?.database) {
|
|
21
|
+
delete this.newConfiguration.sqlConfig.database
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this.databaseConnection = await this.databasePool.spawnConnectionWithConfiguration(this.newConfiguration)
|
|
25
|
+
await this.databaseConnection.connect()
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
if (databaseType != "sqlite") {
|
|
28
|
+
await this.createDatabase(databaseIdentifier)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await this.createSchemaMigrationsTable()
|
|
32
|
+
await this.databaseConnection.close()
|
|
24
33
|
|
|
25
|
-
|
|
34
|
+
if (this.args.testing) return this.result
|
|
35
|
+
}
|
|
26
36
|
}
|
|
27
37
|
|
|
28
|
-
async createDatabase() {
|
|
29
|
-
const databaseName = digg(this
|
|
38
|
+
async createDatabase(databaseIdentifier) {
|
|
39
|
+
const databaseName = digg(this.configuration.getDatabaseConfiguration(), databaseIdentifier, "database")
|
|
30
40
|
const sql = this.databaseConnection.createDatabaseSql(databaseName, {ifNotExists: true})
|
|
31
41
|
|
|
32
42
|
if (this.args.testing) {
|
|
@@ -9,10 +9,6 @@ export default class DbMigrate extends BaseCommand {
|
|
|
9
9
|
const migrationsPath = `${projectPath}/src/database/migrations`
|
|
10
10
|
let files = await fs.readdir(migrationsPath)
|
|
11
11
|
|
|
12
|
-
this.migrator = new Migrator({configuration: this.configuration})
|
|
13
|
-
|
|
14
|
-
await this.migrator.prepare()
|
|
15
|
-
|
|
16
12
|
files = files
|
|
17
13
|
.map((file) => {
|
|
18
14
|
const match = file.match(/^(\d{14})-(.+)\.js$/)
|
|
@@ -33,85 +29,11 @@ export default class DbMigrate extends BaseCommand {
|
|
|
33
29
|
.filter((migration) => Boolean(migration))
|
|
34
30
|
.sort((migration1, migration2) => migration1.date - migration2.date)
|
|
35
31
|
|
|
36
|
-
|
|
37
|
-
if (!this.migrator.hasRunMigrationVersion(migration.date)) {
|
|
38
|
-
await this.runMigrationFile(migration)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async executeRequireContext(requireContext) {
|
|
44
|
-
const migrationFiles = requireContext.keys()
|
|
45
|
-
|
|
46
|
-
files = migrationFiles
|
|
47
|
-
.map((file) => {
|
|
48
|
-
const match = file.match(/^(\d{14})-(.+)\.js$/)
|
|
49
|
-
|
|
50
|
-
if (!match) return null
|
|
51
|
-
|
|
52
|
-
const date = parseInt(match[1])
|
|
53
|
-
const migrationName = match[2]
|
|
54
|
-
const migrationClassName = inflection.camelize(migrationName)
|
|
55
|
-
|
|
56
|
-
return {
|
|
57
|
-
file,
|
|
58
|
-
fullPath: `${migrationsPath}/${file}`,
|
|
59
|
-
date,
|
|
60
|
-
migrationClassName
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
.filter((migration) => Boolean(migration))
|
|
64
|
-
.sort((migration1, migration2) => migration1.date - migration2.date)
|
|
65
|
-
|
|
66
|
-
for (const migration of files) {
|
|
67
|
-
if (!this.migrator.hasRunMigrationVersion(migration.date)) {
|
|
68
|
-
await this.runMigrationFileFromRequireContext(migration, requireContext)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async runMigrationFileFromRequireContext(migration, requireContext) {
|
|
74
|
-
if (!this.configuration) throw new Error("No configuration set")
|
|
75
|
-
if (!this.configuration.isDatabasePoolInitialized()) await this.configuration.initializeDatabasePool()
|
|
76
|
-
|
|
77
|
-
await this.configuration.getDatabasePool().withConnection(async (db) => {
|
|
78
|
-
const MigrationClass = requireContext(migration.file).default
|
|
79
|
-
const migrationInstance = new MigrationClass({
|
|
80
|
-
configuration: this.configuration
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
if (migrationInstance.change) {
|
|
84
|
-
await migrationInstance.change()
|
|
85
|
-
} else if (migrationInstance.up) {
|
|
86
|
-
await migrationInstance.up()
|
|
87
|
-
} else {
|
|
88
|
-
throw new Error(`'change' or 'up' didn't exist on migration: ${migration.file}`)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
await db.insert({tableName: "schema_migrations", data: {version: migration.date}})
|
|
92
|
-
})
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async runMigrationFile(migration) {
|
|
96
|
-
if (!this.configuration) throw new Error("No configuration set")
|
|
97
|
-
if (!this.configuration.isDatabasePoolInitialized()) await this.configuration.initializeDatabasePool()
|
|
98
|
-
|
|
99
|
-
await this.configuration.getDatabasePool().withConnection(async (db) => {
|
|
100
|
-
const migrationImport = await import(migration.fullPath)
|
|
101
|
-
const MigrationClass = migrationImport.default
|
|
102
|
-
const migrationInstance = new MigrationClass({
|
|
103
|
-
configuration: this.configuration
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
if (migrationInstance.change) {
|
|
107
|
-
await migrationInstance.change()
|
|
108
|
-
} else if (migrationInstance.up) {
|
|
109
|
-
await migrationInstance.up()
|
|
110
|
-
} else {
|
|
111
|
-
throw new Error(`'change' or 'up' didn't exist on migration: ${migration.file}`)
|
|
112
|
-
}
|
|
32
|
+
this.migrator = new Migrator({configuration: this.configuration})
|
|
113
33
|
|
|
114
|
-
|
|
34
|
+
await this.configuration.withConnections(async () => {
|
|
35
|
+
await this.migrator.prepare()
|
|
36
|
+
await this.migrator.migrateFiles(files)
|
|
115
37
|
})
|
|
116
38
|
}
|
|
117
39
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import BaseCommand from "../../base-command.js"
|
|
2
|
+
import fs from "node:fs/promises"
|
|
3
|
+
import * as inflection from "inflection"
|
|
4
|
+
import Migrator from "../../../database/migrator.js"
|
|
5
|
+
|
|
6
|
+
export default class DbReset extends BaseCommand {
|
|
7
|
+
async execute() {
|
|
8
|
+
const projectPath = this.configuration.getDirectory()
|
|
9
|
+
const migrationsPath = `${projectPath}/src/database/migrations`
|
|
10
|
+
let files = await fs.readdir(migrationsPath)
|
|
11
|
+
|
|
12
|
+
files = files
|
|
13
|
+
.map((file) => {
|
|
14
|
+
const match = file.match(/^(\d{14})-(.+)\.js$/)
|
|
15
|
+
|
|
16
|
+
if (!match) return null
|
|
17
|
+
|
|
18
|
+
const date = parseInt(match[1])
|
|
19
|
+
const migrationName = match[2]
|
|
20
|
+
const migrationClassName = inflection.camelize(migrationName.replaceAll("-", "_"))
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
file,
|
|
24
|
+
fullPath: `${migrationsPath}/${file}`,
|
|
25
|
+
date,
|
|
26
|
+
migrationClassName
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
.filter((migration) => Boolean(migration))
|
|
30
|
+
.sort((migration1, migration2) => migration1.date - migration2.date)
|
|
31
|
+
|
|
32
|
+
this.migrator = new Migrator({configuration: this.configuration})
|
|
33
|
+
|
|
34
|
+
await this.configuration.withConnections(async () => {
|
|
35
|
+
await this.migrator.reset()
|
|
36
|
+
await this.migrator.prepare()
|
|
37
|
+
await this.migrator.migrateFiles(files)
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/configuration.js
CHANGED
|
@@ -8,12 +8,14 @@ export default class VelociousConfiguration {
|
|
|
8
8
|
return this.velociousConfiguration
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
constructor({cors, database, debug, directory, initializeModels, locale, localeFallbacks, locales, ...restArgs}) {
|
|
11
|
+
constructor({cors, database, debug, directory, environment, initializeModels, locale, localeFallbacks, locales, ...restArgs}) {
|
|
12
12
|
restArgsError(restArgs)
|
|
13
13
|
|
|
14
14
|
this.cors = cors
|
|
15
15
|
this.database = database
|
|
16
|
+
this.databasePools = {}
|
|
16
17
|
this.debug = debug
|
|
18
|
+
this._environment = environment || process.env.VELOCIOUS_ENV || process.env.NODE_ENV || "development"
|
|
17
19
|
this._directory = directory
|
|
18
20
|
this._initializeModels = initializeModels
|
|
19
21
|
this._isInitialized = false
|
|
@@ -23,16 +25,30 @@ export default class VelociousConfiguration {
|
|
|
23
25
|
this.modelClasses = {}
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
getDatabaseConfiguration() {
|
|
29
|
+
return digg(this, "database", this.getEnvironment())
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getDatabaseIdentifiers() {
|
|
33
|
+
return Object.keys(this.getDatabaseConfiguration())
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getDatabasePool(identifier = "default") {
|
|
37
|
+
if (!this.isDatabasePoolInitialized(identifier)) {
|
|
38
|
+
this.initializeDatabasePool(identifier)
|
|
29
39
|
}
|
|
30
40
|
|
|
31
|
-
return this
|
|
41
|
+
return digg(this, "databasePools", identifier)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getDatabaseIdentifier(identifier) {
|
|
45
|
+
if (!this.getDatabaseConfiguration()[identifier]) throw new Error(`No such database identifier configured: ${identifier}`)
|
|
46
|
+
|
|
47
|
+
return this.getDatabaseConfiguration()[identifier]
|
|
32
48
|
}
|
|
33
49
|
|
|
34
|
-
getDatabasePoolType() {
|
|
35
|
-
const poolTypeClass = digg(this, "
|
|
50
|
+
getDatabasePoolType(identifier = "default") {
|
|
51
|
+
const poolTypeClass = digg(this.getDatabaseIdentifier(identifier), "poolType")
|
|
36
52
|
|
|
37
53
|
if (!poolTypeClass) {
|
|
38
54
|
throw new Error("No poolType given in database configuration")
|
|
@@ -41,12 +57,10 @@ export default class VelociousConfiguration {
|
|
|
41
57
|
return poolTypeClass
|
|
42
58
|
}
|
|
43
59
|
|
|
44
|
-
getDatabaseType() {
|
|
45
|
-
const databaseType = digg(this, "
|
|
60
|
+
getDatabaseType(identifier = "default") {
|
|
61
|
+
const databaseType = digg(this.getDatabaseIdentifier(identifier), "type")
|
|
46
62
|
|
|
47
|
-
if (!databaseType)
|
|
48
|
-
throw new Error("No database type given in database configuration")
|
|
49
|
-
}
|
|
63
|
+
if (!databaseType) throw new Error("No database type given in database configuration")
|
|
50
64
|
|
|
51
65
|
return databaseType
|
|
52
66
|
}
|
|
@@ -59,6 +73,10 @@ export default class VelociousConfiguration {
|
|
|
59
73
|
return this._directory
|
|
60
74
|
}
|
|
61
75
|
|
|
76
|
+
getEnvironment() {
|
|
77
|
+
return digg(this, "_environment")
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
getLocaleFallbacks = () => this.localeFallbacks
|
|
63
81
|
setLocaleFallbacks(newLocaleFallbacks) {
|
|
64
82
|
this.localeFallbacks = newLocaleFallbacks
|
|
@@ -84,17 +102,17 @@ export default class VelociousConfiguration {
|
|
|
84
102
|
return modelClass
|
|
85
103
|
}
|
|
86
104
|
|
|
87
|
-
initializeDatabasePool() {
|
|
105
|
+
initializeDatabasePool(identifier = "default") {
|
|
88
106
|
if (!this.database) throw new Error("No 'database' was given")
|
|
89
|
-
if (this.
|
|
107
|
+
if (this.databasePools[identifier]) throw new Error("DatabasePool has already been initialized")
|
|
90
108
|
|
|
91
|
-
const PoolType = this.getDatabasePoolType()
|
|
109
|
+
const PoolType = this.getDatabasePoolType(identifier)
|
|
92
110
|
|
|
93
|
-
this.
|
|
94
|
-
this.
|
|
111
|
+
this.databasePools[identifier] = new PoolType({configuration: this, identifier})
|
|
112
|
+
this.databasePools[identifier].setCurrent()
|
|
95
113
|
}
|
|
96
114
|
|
|
97
|
-
isDatabasePoolInitialized = () => Boolean(this.
|
|
115
|
+
isDatabasePoolInitialized = (identifier = "default") => Boolean(this.databasePools[identifier])
|
|
98
116
|
isInitialized = () => this._isInitialized
|
|
99
117
|
|
|
100
118
|
async initialize() {
|
|
@@ -118,4 +136,39 @@ export default class VelociousConfiguration {
|
|
|
118
136
|
setRoutes(newRoutes) {
|
|
119
137
|
this.routes = newRoutes
|
|
120
138
|
}
|
|
139
|
+
|
|
140
|
+
async withConnections(callback) {
|
|
141
|
+
const dbs = {}
|
|
142
|
+
const actualCallback = async () => {
|
|
143
|
+
return await callback(dbs)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let runRequest = actualCallback
|
|
147
|
+
|
|
148
|
+
for (const identifier of this.getDatabaseIdentifiers()) {
|
|
149
|
+
let actualRunRequest = runRequest
|
|
150
|
+
|
|
151
|
+
const nextRunRequest = async () => {
|
|
152
|
+
return await this.getDatabasePool(identifier).withConnection(async (db) => {
|
|
153
|
+
dbs[identifier] = db
|
|
154
|
+
|
|
155
|
+
await actualRunRequest()
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
runRequest = nextRunRequest
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
await runRequest()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async getCurrentConnections() {
|
|
166
|
+
const dbs = {}
|
|
167
|
+
|
|
168
|
+
for (const identifier of this.getDatabaseIdentifiers()) {
|
|
169
|
+
dbs[identifier] = this.getDatabasePool(identifier).getCurrentConnection()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return dbs
|
|
173
|
+
}
|
|
121
174
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {Logger} from "../../logger.js"
|
|
1
2
|
import Query from "../query/index.js"
|
|
2
3
|
import Handler from "../handler.js"
|
|
3
4
|
import {v4 as uuidv4} from "uuid"
|
|
@@ -6,6 +7,7 @@ export default class VelociousDatabaseDriversBase {
|
|
|
6
7
|
constructor(config, configuration) {
|
|
7
8
|
this._args = config
|
|
8
9
|
this.configuration = configuration
|
|
10
|
+
this.logger = new Logger(this)
|
|
9
11
|
this._transactionsCount = 0
|
|
10
12
|
}
|
|
11
13
|
|
|
@@ -23,6 +25,14 @@ export default class VelociousDatabaseDriversBase {
|
|
|
23
25
|
await this.query(sql)
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
async dropTable(...args) {
|
|
29
|
+
const sqls = this.dropTableSql(...args)
|
|
30
|
+
|
|
31
|
+
for (const sql of sqls) {
|
|
32
|
+
await this.query(sql)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
getArgs() {
|
|
27
37
|
return this._args
|
|
28
38
|
}
|
|
@@ -56,12 +66,38 @@ export default class VelociousDatabaseDriversBase {
|
|
|
56
66
|
throw new Error(`${this.constructor.name}#lastInsertID not implemented`)
|
|
57
67
|
}
|
|
58
68
|
|
|
59
|
-
|
|
69
|
+
quote(value) {
|
|
70
|
+
if (typeof value == "number") return value
|
|
71
|
+
|
|
72
|
+
const escapedValue = this.escape(value)
|
|
73
|
+
const result = `"${escapedValue}"`
|
|
74
|
+
|
|
75
|
+
return result
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
quoteColumn(columnName) {
|
|
79
|
+
return this.options().quoteColumnName(columnName)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
quoteIndex(columnName) {
|
|
83
|
+
return this.options().quoteIndexName(columnName)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
quoteTable(tableName) {
|
|
87
|
+
return this.options().quoteColumnName(tableName)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
newQuery() {
|
|
60
91
|
const handler = new Handler()
|
|
61
|
-
|
|
92
|
+
|
|
93
|
+
return new Query({
|
|
62
94
|
driver: this,
|
|
63
95
|
handler
|
|
64
96
|
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async select(tableName) {
|
|
100
|
+
const query = this.newQuery()
|
|
65
101
|
|
|
66
102
|
const sql = query
|
|
67
103
|
.from(tableName)
|
|
@@ -83,38 +119,48 @@ export default class VelociousDatabaseDriversBase {
|
|
|
83
119
|
return false
|
|
84
120
|
}
|
|
85
121
|
|
|
86
|
-
async startTransaction() {
|
|
87
|
-
return await this.query("BEGIN TRANSACTION")
|
|
88
|
-
}
|
|
89
|
-
|
|
90
122
|
async transaction(callback) {
|
|
91
|
-
const savePointName =
|
|
123
|
+
const savePointName = this.generateSavePointName()
|
|
92
124
|
let transactionStarted = false
|
|
125
|
+
let savePointStarted = false
|
|
93
126
|
|
|
94
127
|
if (this._transactionsCount == 0) {
|
|
128
|
+
this.logger.debug("Start transaction")
|
|
95
129
|
await this.startTransaction()
|
|
96
130
|
transactionStarted = true
|
|
97
131
|
this._transactionsCount++
|
|
132
|
+
} else {
|
|
133
|
+
this.logger.debug("Start savepoint", savePointName)
|
|
134
|
+
await this.startSavePoint(savePointName)
|
|
135
|
+
savePointStarted = true
|
|
98
136
|
}
|
|
99
137
|
|
|
100
|
-
await this.query(`SAVEPOINT ${savePointName}`)
|
|
101
|
-
|
|
102
138
|
let result
|
|
103
139
|
|
|
104
140
|
try {
|
|
105
141
|
result = await callback()
|
|
106
142
|
|
|
107
|
-
|
|
143
|
+
if (savePointStarted) {
|
|
144
|
+
this.logger.debug("Release savepoint", savePointName)
|
|
145
|
+
await this.releaseSavePoint(savePointName)
|
|
146
|
+
}
|
|
108
147
|
|
|
109
148
|
if (transactionStarted) {
|
|
110
|
-
|
|
149
|
+
this.logger.debug("Commit transaction")
|
|
150
|
+
await this.commitTransaction()
|
|
111
151
|
this._transactionsCount--
|
|
112
152
|
}
|
|
113
153
|
} catch (error) {
|
|
114
|
-
|
|
154
|
+
this.logger.debug("Transaction error", error.message)
|
|
155
|
+
|
|
156
|
+
if (savePointStarted) {
|
|
157
|
+
this.logger.debug("Rollback savepoint", savePointName)
|
|
158
|
+
await this.rollbackSavePoint(savePointName)
|
|
159
|
+
}
|
|
115
160
|
|
|
116
161
|
if (transactionStarted) {
|
|
117
|
-
|
|
162
|
+
this.logger.debug("Rollback transaction")
|
|
163
|
+
await this.rollbackTransaction()
|
|
118
164
|
this._transactionsCount--
|
|
119
165
|
}
|
|
120
166
|
|
|
@@ -124,9 +170,47 @@ export default class VelociousDatabaseDriversBase {
|
|
|
124
170
|
return result
|
|
125
171
|
}
|
|
126
172
|
|
|
173
|
+
async startTransaction() {
|
|
174
|
+
return await this.query("BEGIN TRANSACTION")
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async commitTransaction() {
|
|
178
|
+
await this.query("COMMIT")
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async rollbackTransaction() {
|
|
182
|
+
await this.query("ROLLBACK")
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
generateSavePointName() {
|
|
186
|
+
return `sp${uuidv4().replaceAll("-", "")}`
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async startSavePoint(savePointName) {
|
|
190
|
+
await this.query(`SAVEPOINT ${savePointName}`)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async releaseSavePoint(savePointName) {
|
|
194
|
+
await this.query(`RELEASE SAVEPOINT ${savePointName}`)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async rollbackSavePoint(savePointName) {
|
|
198
|
+
await this.query(`ROLLBACK TO SAVEPOINT ${savePointName}`)
|
|
199
|
+
}
|
|
200
|
+
|
|
127
201
|
async update(...args) {
|
|
128
202
|
const sql = this.updateSql(...args)
|
|
129
203
|
|
|
130
204
|
await this.query(sql)
|
|
131
205
|
}
|
|
206
|
+
|
|
207
|
+
async withDisabledForeignKeys(callback) {
|
|
208
|
+
await this.disableForeignKeys()
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
return await callback()
|
|
212
|
+
} finally {
|
|
213
|
+
await this.enableForeignKeys()
|
|
214
|
+
}
|
|
215
|
+
}
|
|
132
216
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Async function to connect a MS-SQL connection
|
|
2
|
+
export default function connectConnection(connection) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
connection.connect((error) => {
|
|
5
|
+
if (error) {
|
|
6
|
+
reject(error)
|
|
7
|
+
} else {
|
|
8
|
+
resolve()
|
|
9
|
+
}
|
|
10
|
+
})
|
|
11
|
+
})
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseDriversMssqlForeignKey {
|
|
4
|
+
constructor(data) {
|
|
5
|
+
this.data = data
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
getColumnName = () => digg(this, "data", "ParentColumn")
|
|
9
|
+
getName = () => digg(this, "data", "CONSTRAINT_NAME")
|
|
10
|
+
getTableName = () => digg(this, "data", "TableName")
|
|
11
|
+
getReferencedColumnName = () => digg(this, "data", "ReferencedColumn")
|
|
12
|
+
getReferencedTableName = () => digg(this, "data", "ReferencedTable")
|
|
13
|
+
}
|