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.
- package/README.md +1 -1
- package/package.json +2 -1
- package/peak_flow.yml +14 -6
- package/spec/cli/commands/db/create-spec.js +1 -0
- package/spec/cli/commands/db/migrate-spec.js +28 -11
- package/spec/cli/commands/test/test-files-finder-spec.js +5 -4
- package/spec/database/record/create-spec.js +9 -0
- package/spec/database/record/destroy-spec.js +6 -3
- package/spec/database/record/find-spec.js +4 -1
- package/spec/database/record/query-spec.js +7 -3
- package/spec/database/record/translation-fallbacks-spec.js +1 -1
- package/spec/database/record/update-spec.js +2 -1
- package/spec/database/record/validations-spec.js +16 -4
- package/spec/database/transactions-spec.js +7 -5
- package/spec/dummy/index.js +18 -29
- package/spec/dummy/src/config/configuration.example.js +3 -2
- package/spec/dummy/src/config/configuration.peakflow.mariadb.js +3 -7
- package/spec/dummy/src/config/configuration.peakflow.mssql.js +3 -12
- package/spec/dummy/src/config/configuration.peakflow.pgsql.js +3 -7
- package/spec/dummy/src/config/configuration.peakflow.sqlite.js +3 -7
- package/spec/dummy/src/config/testing.js +62 -0
- package/spec/dummy/src/database/migrations/20250912183605-create-users.js +15 -0
- package/spec/dummy/src/database/migrations/20250912183606-create-authentication-tokens.js +15 -0
- package/spec/dummy/src/models/authentication-token.js +8 -0
- package/spec/dummy/src/models/task.js +2 -2
- package/spec/dummy/src/models/user.js +15 -0
- package/spec/dummy/src/routes/projects/controller.js +7 -1
- package/spec/http-server/client-spec.js +1 -1
- package/spec/http-server/get-spec.js +1 -1
- package/spec/http-server/post-spec.js +21 -8
- package/spec/http-server/root-get-spec.js +1 -1
- package/src/cli/commands/db/create.js +11 -8
- package/src/cli/commands/db/drop.js +19 -0
- package/src/cli/commands/db/migrate.js +1 -1
- package/src/cli/commands/db/reset.js +7 -1
- package/src/cli/commands/test.js +10 -4
- package/src/configuration.js +26 -3
- package/src/database/drivers/base-column.js +22 -0
- package/src/database/drivers/base-columns-index.js +34 -0
- package/src/database/drivers/base-table.js +43 -0
- package/src/database/drivers/base.js +12 -16
- package/src/database/drivers/mssql/column.js +43 -2
- package/src/database/drivers/mssql/columns-index.js +9 -0
- package/src/database/drivers/mssql/index.js +26 -14
- package/src/database/drivers/mssql/table.js +16 -1
- package/src/database/drivers/mysql/column.js +47 -2
- package/src/database/drivers/mysql/columns-index.js +10 -0
- package/src/database/drivers/mysql/index.js +5 -8
- package/src/database/drivers/mysql/table.js +3 -1
- package/src/database/drivers/pgsql/column.js +37 -2
- package/src/database/drivers/pgsql/columns-index.js +4 -0
- package/src/database/drivers/pgsql/index.js +6 -5
- package/src/database/drivers/pgsql/table.js +3 -1
- package/src/database/drivers/sqlite/base.js +6 -4
- package/src/database/drivers/sqlite/column.js +46 -2
- package/src/database/drivers/sqlite/columns-index.js +22 -0
- package/src/database/drivers/sqlite/connection-sql-js.js +1 -1
- package/src/database/drivers/sqlite/table.js +3 -1
- package/src/database/migrator.js +27 -7
- package/src/database/query/create-index-base.js +10 -1
- package/src/database/query/create-table-base.js +56 -2
- package/src/database/query/drop-table-base.js +8 -2
- package/src/database/record/index.js +16 -5
- package/src/database/record/validators/presence.js +1 -1
- package/src/database/table-data/index.js +2 -1
- package/src/database/use-database.js +1 -1
- package/src/routes/resolver.js +1 -1
- package/src/templates/configuration.js +1 -1
- package/src/testing/test-runner.js +86 -26
- package/src/testing/test.js +155 -7
- package/src/utils/with-tracked-stack.js +5 -3
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import dummyConfiguration from "./configuration.js"
|
|
2
|
+
|
|
3
|
+
beforeEach(async ({testArgs}) => {
|
|
4
|
+
const transaction = testArgs.databaseCleaning?.transaction
|
|
5
|
+
|
|
6
|
+
if (transaction === undefined) {
|
|
7
|
+
const dbs = dummyConfiguration.getCurrentConnections()
|
|
8
|
+
|
|
9
|
+
for (const dbIdentifier in dbs) {
|
|
10
|
+
const db = dbs[dbIdentifier]
|
|
11
|
+
|
|
12
|
+
await db.startTransaction()
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
afterEach(async ({testArgs}) => {
|
|
18
|
+
const transaction = testArgs.databaseCleaning?.transaction
|
|
19
|
+
const truncate = testArgs.databaseCleaning?.truncate
|
|
20
|
+
|
|
21
|
+
const dbs = dummyConfiguration.getCurrentConnections()
|
|
22
|
+
|
|
23
|
+
for (const dbIdentifier in dbs) {
|
|
24
|
+
const db = dbs[dbIdentifier]
|
|
25
|
+
|
|
26
|
+
if (transaction === undefined || transaction) {
|
|
27
|
+
await db.rollbackTransaction()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (truncate) {
|
|
31
|
+
await db.withDisabledForeignKeys(async () => {
|
|
32
|
+
let tries = 0
|
|
33
|
+
|
|
34
|
+
while(true) {
|
|
35
|
+
tries++
|
|
36
|
+
|
|
37
|
+
const tables = await db.getTables()
|
|
38
|
+
const truncateErrors = []
|
|
39
|
+
|
|
40
|
+
for (const table of tables) {
|
|
41
|
+
if (table.getName() != "schema_migrations") {
|
|
42
|
+
try {
|
|
43
|
+
await table.truncate({cascade: true})
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(error)
|
|
46
|
+
truncateErrors.push(error)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (truncateErrors.length == 0) {
|
|
52
|
+
break
|
|
53
|
+
} else if (tries <= 5) {
|
|
54
|
+
// Retry
|
|
55
|
+
} else {
|
|
56
|
+
throw truncateErrors[0]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Migration from "../../../../../src/database/migration/index.js"
|
|
2
|
+
|
|
3
|
+
export default class CreateUsers extends Migration {
|
|
4
|
+
async up() {
|
|
5
|
+
await this.createTable("users", (t) => {
|
|
6
|
+
t.string("email", {index: {unique: true}, null: false})
|
|
7
|
+
t.string("encrypted_password", {null: false})
|
|
8
|
+
t.timestamps()
|
|
9
|
+
})
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async down() {
|
|
13
|
+
await this.dropTable("users")
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Migration from "../../../../../src/database/migration/index.js"
|
|
2
|
+
|
|
3
|
+
export default class CreateAuthenticationTokens extends Migration {
|
|
4
|
+
async up() {
|
|
5
|
+
await this.createTable("authentication_tokens", (t) => {
|
|
6
|
+
t.string("token", {default: () => "UUID()", index: {unique: true}})
|
|
7
|
+
t.references("user", {foreignKey: true, null: false})
|
|
8
|
+
t.timestamps()
|
|
9
|
+
})
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async down() {
|
|
13
|
+
await this.dropTable("authentication_tokens")
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Record from "../../../../src/database/record/index.js"
|
|
2
|
+
import UserModule from "../../../../src/database/record/user-module.js"
|
|
3
|
+
|
|
4
|
+
class User extends Record {
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
User.hasMany("authenticationTokens" , {dependent: "destroy"})
|
|
8
|
+
|
|
9
|
+
const userModule = new UserModule({
|
|
10
|
+
secretKey: "02e383b7-aad1-437c-b1e1-17c0240ad851"
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
userModule.attachTo(User)
|
|
14
|
+
|
|
15
|
+
export default User
|
|
@@ -22,6 +22,12 @@ export default class ProjectsController extends Controller {
|
|
|
22
22
|
|
|
23
23
|
await project.save()
|
|
24
24
|
|
|
25
|
-
this.render({json: {
|
|
25
|
+
this.render({json: {
|
|
26
|
+
project: {
|
|
27
|
+
id: project.id(),
|
|
28
|
+
name: project.name()
|
|
29
|
+
},
|
|
30
|
+
status: "success"
|
|
31
|
+
}})
|
|
26
32
|
}
|
|
27
33
|
}
|
|
@@ -3,7 +3,7 @@ import Client from "../../src/http-server/client/index.js"
|
|
|
3
3
|
import {digg} from "diggerize"
|
|
4
4
|
import dummyConfiguration from "../dummy/src/config/configuration.js"
|
|
5
5
|
|
|
6
|
-
describe("http server - client", () => {
|
|
6
|
+
describe("http server - client", {databaseCleaning: {transaction: false, truncate: true}}, () => {
|
|
7
7
|
it("spawns a request for each that it is fed", async () => {
|
|
8
8
|
await dummyConfiguration.initialize()
|
|
9
9
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fetch from "node-fetch"
|
|
2
2
|
import Dummy from "../dummy/index.js"
|
|
3
3
|
|
|
4
|
-
describe("HttpServer", () => {
|
|
4
|
+
describe("HttpServer - get", {databaseCleaning: {transaction: false, truncate: true}}, () => {
|
|
5
5
|
it("handles get requests", async () => {
|
|
6
6
|
await Dummy.run(async () => {
|
|
7
7
|
for (let i = 0; i <= 5; i++) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
1
2
|
import fetch from "node-fetch"
|
|
2
3
|
import querystring from "querystring"
|
|
4
|
+
import wait from "awaitery/src/wait.js"
|
|
3
5
|
|
|
4
6
|
import Dummy from "../dummy/index.js"
|
|
5
7
|
import Project from "../dummy/src/models/project.js"
|
|
6
8
|
|
|
7
|
-
describe("HttpServer", () => {
|
|
9
|
+
describe("HttpServer - post", {databaseCleaning: {transaction: false, truncate: true}}, () => {
|
|
8
10
|
it("handles post requests", async () => {
|
|
9
11
|
await Dummy.run(async () => {
|
|
10
12
|
for (let i = 0; i <= 5; i++) {
|
|
@@ -20,10 +22,13 @@ describe("HttpServer", () => {
|
|
|
20
22
|
method: "POST"
|
|
21
23
|
}
|
|
22
24
|
)
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
+
const data = await response.json()
|
|
26
|
+
const projectID = digg(data, "project", "id")
|
|
27
|
+
|
|
28
|
+
await wait(100) // Wait a bit to ensure the database connections are in sync
|
|
29
|
+
|
|
30
|
+
const createdProject = await Project.preload({translations: true}).find(projectID)
|
|
25
31
|
|
|
26
|
-
expect(text).toEqual('{"status":"success"}')
|
|
27
32
|
expect(createdProject.name()).toEqual("Test create project")
|
|
28
33
|
}
|
|
29
34
|
})
|
|
@@ -44,10 +49,14 @@ describe("HttpServer", () => {
|
|
|
44
49
|
method: "POST"
|
|
45
50
|
}
|
|
46
51
|
)
|
|
47
|
-
const
|
|
52
|
+
const data = await response.json()
|
|
53
|
+
|
|
54
|
+
expect(data.status).toEqual("success")
|
|
55
|
+
|
|
56
|
+
await wait(100) // Wait a bit to ensure the database connections are in sync
|
|
57
|
+
|
|
48
58
|
const createdProject = await Project.preload({translations: true}).last()
|
|
49
59
|
|
|
50
|
-
expect(text).toEqual('{"status":"success"}')
|
|
51
60
|
expect(createdProject.name()).toEqual("Test create project")
|
|
52
61
|
}
|
|
53
62
|
})
|
|
@@ -67,10 +76,14 @@ describe("HttpServer", () => {
|
|
|
67
76
|
method: "POST"
|
|
68
77
|
}
|
|
69
78
|
)
|
|
70
|
-
const
|
|
79
|
+
const data = await response.json()
|
|
80
|
+
|
|
81
|
+
expect(data.status).toEqual("success")
|
|
82
|
+
|
|
83
|
+
await wait(100) // Wait a bit to ensure the database connections are in sync
|
|
84
|
+
|
|
71
85
|
const createdProject = await Project.preload({translations: true}).last()
|
|
72
86
|
|
|
73
|
-
expect(text).toEqual('{"status":"success"}')
|
|
74
87
|
expect(createdProject.name()).toEqual("Test create project")
|
|
75
88
|
}
|
|
76
89
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fetch from "node-fetch"
|
|
2
2
|
import Dummy from "../dummy/index.js"
|
|
3
3
|
|
|
4
|
-
describe("HttpServer", () => {
|
|
4
|
+
describe("HttpServer - root get", {databaseCleaning: {transaction: false, truncate: true}}, () => {
|
|
5
5
|
it("handles root get requests", async () => {
|
|
6
6
|
await Dummy.run(async () => {
|
|
7
7
|
for (let i = 0; i <= 5; i++) {
|
|
@@ -7,21 +7,22 @@ export default class DbCreate extends BaseCommand{
|
|
|
7
7
|
async execute() {
|
|
8
8
|
for (const databaseIdentifier of this.configuration.getDatabaseIdentifiers()) {
|
|
9
9
|
const databaseType = this.configuration.getDatabaseType(databaseIdentifier)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const databasePool = this.configuration.getDatabasePool(databaseIdentifier)
|
|
11
|
+
const newConfiguration = incorporate({}, databasePool.getConfiguration())
|
|
12
|
+
const DriverClass = digg(newConfiguration, "driver")
|
|
13
13
|
|
|
14
14
|
if (this.args.testing) this.result = []
|
|
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
|
-
|
|
17
|
+
newConfiguration.database = newConfiguration.useDatabase || "mysql"
|
|
18
18
|
|
|
19
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" &&
|
|
21
|
-
delete
|
|
20
|
+
if (databaseType == "mssql" && newConfiguration.sqlConfig?.database) {
|
|
21
|
+
delete newConfiguration.sqlConfig.database
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
this.databaseConnection =
|
|
24
|
+
this.databaseConnection = new DriverClass(newConfiguration, this.configuration)
|
|
25
|
+
|
|
25
26
|
await this.databaseConnection.connect()
|
|
26
27
|
|
|
27
28
|
try {
|
|
@@ -31,7 +32,9 @@ export default class DbCreate extends BaseCommand{
|
|
|
31
32
|
|
|
32
33
|
await this.createSchemaMigrationsTable()
|
|
33
34
|
} finally {
|
|
34
|
-
|
|
35
|
+
if (databaseType != "mssql") {
|
|
36
|
+
await this.databaseConnection.close()
|
|
37
|
+
}
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
if (this.args.testing) return this.result
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import BaseCommand from "../../base-command.js"
|
|
2
|
+
import FilesFinder from "../../../database/migrator/files-finder.js"
|
|
3
|
+
import Migrator from "../../../database/migrator.js"
|
|
4
|
+
|
|
5
|
+
export default class DbDrop extends BaseCommand {
|
|
6
|
+
async execute() {
|
|
7
|
+
const environment = this.configuration.getEnvironment()
|
|
8
|
+
|
|
9
|
+
if (environment != "development" && environment != "test") {
|
|
10
|
+
throw new Error(`This command should only be executed on development and test environments and not: ${environment}`)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
this.migrator = new Migrator({configuration: this.configuration})
|
|
14
|
+
|
|
15
|
+
await this.configuration.ensureConnections(async () => {
|
|
16
|
+
await this.migrator.dropDatabase()
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -11,7 +11,7 @@ export default class DbMigrate extends BaseCommand {
|
|
|
11
11
|
|
|
12
12
|
this.migrator = new Migrator({configuration: this.configuration})
|
|
13
13
|
|
|
14
|
-
await this.configuration.
|
|
14
|
+
await this.configuration.ensureConnections(async () => {
|
|
15
15
|
await this.migrator.prepare()
|
|
16
16
|
await this.migrator.migrateFiles(files, async (importPath) => await import(importPath))
|
|
17
17
|
})
|
|
@@ -4,6 +4,12 @@ import Migrator from "../../../database/migrator.js"
|
|
|
4
4
|
|
|
5
5
|
export default class DbReset extends BaseCommand {
|
|
6
6
|
async execute() {
|
|
7
|
+
const environment = this.configuration.getEnvironment()
|
|
8
|
+
|
|
9
|
+
if (environment != "development" && environment != "test") {
|
|
10
|
+
throw new Error(`This command should only be executed on development and test environments and not: ${environment}`)
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
const projectPath = this.configuration.getDirectory()
|
|
8
14
|
const migrationsPath = `${projectPath}/src/database/migrations`
|
|
9
15
|
const filesFinder = new FilesFinder({path: migrationsPath})
|
|
@@ -11,7 +17,7 @@ export default class DbReset extends BaseCommand {
|
|
|
11
17
|
|
|
12
18
|
this.migrator = new Migrator({configuration: this.configuration})
|
|
13
19
|
|
|
14
|
-
await this.configuration.
|
|
20
|
+
await this.configuration.ensureConnections(async () => {
|
|
15
21
|
await this.migrator.reset()
|
|
16
22
|
await this.migrator.prepare()
|
|
17
23
|
await this.migrator.migrateFiles(files, async (importPath) => await import(importPath))
|
package/src/cli/commands/test.js
CHANGED
|
@@ -2,19 +2,25 @@ import BaseCommand from "../base-command.js"
|
|
|
2
2
|
import TestFilesFinder from "../../testing/test-files-finder.js"
|
|
3
3
|
import TestRunner from "../../testing/test-runner.js"
|
|
4
4
|
|
|
5
|
-
export default class
|
|
5
|
+
export default class VelociousCliCommandsTest extends BaseCommand {
|
|
6
6
|
async execute() {
|
|
7
|
-
const testFilesFinder = new TestFilesFinder({directory: this.directory()
|
|
7
|
+
const testFilesFinder = new TestFilesFinder({directory: `${this.directory()}/..`, processArgs: this.processArgs})
|
|
8
8
|
const testFiles = await testFilesFinder.findTestFiles()
|
|
9
9
|
const testRunner = new TestRunner({configuration: this.configuration, testFiles})
|
|
10
10
|
|
|
11
|
+
await testRunner.prepare()
|
|
12
|
+
|
|
13
|
+
if (testRunner.getTestsCount() === 0) {
|
|
14
|
+
throw new Error("No tests has been found")
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
await testRunner.run()
|
|
12
18
|
|
|
13
19
|
if (testRunner.isFailed()) {
|
|
14
|
-
console.error(
|
|
20
|
+
console.error(`\nTest run failed with ${testRunner.getFailedTests()} failed tests and ${testRunner.getSuccessfulTests()} successfull`)
|
|
15
21
|
process.exit(1)
|
|
16
22
|
} else {
|
|
17
|
-
console.log(
|
|
23
|
+
console.log(`\nTest run succeeded with ${testRunner.getSuccessfulTests()} successful tests`)
|
|
18
24
|
process.exit(0)
|
|
19
25
|
}
|
|
20
26
|
}
|
package/src/configuration.js
CHANGED
|
@@ -9,7 +9,7 @@ export default class VelociousConfiguration {
|
|
|
9
9
|
return this.velociousConfiguration
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
constructor({cors, database, debug, directory, environment, initializeModels, locale, localeFallbacks, locales, ...restArgs}) {
|
|
12
|
+
constructor({cors, database, debug, directory, environment, initializeModels, locale, localeFallbacks, locales, testing, ...restArgs}) {
|
|
13
13
|
restArgsError(restArgs)
|
|
14
14
|
|
|
15
15
|
this.cors = cors
|
|
@@ -24,9 +24,12 @@ export default class VelociousConfiguration {
|
|
|
24
24
|
this.localeFallbacks = localeFallbacks
|
|
25
25
|
this.locales = locales
|
|
26
26
|
this.modelClasses = {}
|
|
27
|
+
this._testing = testing
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
getDatabaseConfiguration() {
|
|
31
|
+
if (!this.database) throw new Error("No database configuration")
|
|
32
|
+
|
|
30
33
|
return digg(this, "database", this.getEnvironment())
|
|
31
34
|
}
|
|
32
35
|
|
|
@@ -103,6 +106,8 @@ export default class VelociousConfiguration {
|
|
|
103
106
|
return modelClass
|
|
104
107
|
}
|
|
105
108
|
|
|
109
|
+
getTesting() { return this._testing }
|
|
110
|
+
|
|
106
111
|
initializeDatabasePool(identifier = "default") {
|
|
107
112
|
if (!this.database) throw new Error("No 'database' was given")
|
|
108
113
|
if (this.databasePools[identifier]) throw new Error("DatabasePool has already been initialized")
|
|
@@ -180,13 +185,31 @@ export default class VelociousConfiguration {
|
|
|
180
185
|
await runRequest()
|
|
181
186
|
}
|
|
182
187
|
|
|
183
|
-
|
|
188
|
+
getCurrentConnections() {
|
|
184
189
|
const dbs = {}
|
|
185
190
|
|
|
186
191
|
for (const identifier of this.getDatabaseIdentifiers()) {
|
|
187
|
-
|
|
192
|
+
try {
|
|
193
|
+
dbs[identifier] = this.getDatabasePool(identifier).getCurrentConnection()
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if (error.message == "ID hasn't been set for this async context" || error.message == "A connection hasn't been made yet") {
|
|
196
|
+
// Ignore
|
|
197
|
+
} else {
|
|
198
|
+
throw error
|
|
199
|
+
}
|
|
200
|
+
}
|
|
188
201
|
}
|
|
189
202
|
|
|
190
203
|
return dbs
|
|
191
204
|
}
|
|
205
|
+
|
|
206
|
+
async ensureConnections(callback) {
|
|
207
|
+
let dbs = this.getCurrentConnections()
|
|
208
|
+
|
|
209
|
+
if (Object.keys(dbs).length > 0) {
|
|
210
|
+
await callback(dbs)
|
|
211
|
+
} else {
|
|
212
|
+
await this.withConnections(callback)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
192
215
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export default class VelociousDatabaseDriversBaseColumn {
|
|
2
|
+
async getIndexByName(indexName) {
|
|
3
|
+
const indexes = await this.getIndexes()
|
|
4
|
+
const index = indexes.find((index) => index.getName() == indexName)
|
|
5
|
+
|
|
6
|
+
return index
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getDriver() {
|
|
10
|
+
return this.getTable().getDriver()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getOptions() {
|
|
14
|
+
return this.getDriver().options()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getTable() {
|
|
18
|
+
if (!this.table) throw new Error("No table set on column")
|
|
19
|
+
|
|
20
|
+
return this.table
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { digg } from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseDriversBaseColumnsIndex {
|
|
4
|
+
constructor(table, data) {
|
|
5
|
+
this.data = data
|
|
6
|
+
this.table = table
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getDriver() {
|
|
10
|
+
return this.getTable().getDriver()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getName() {
|
|
14
|
+
return digg(this, "data", "index_name")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getOptions() {
|
|
18
|
+
return this.getDriver().options()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getTable() {
|
|
22
|
+
if (!this.table) throw new Error("No table set on column")
|
|
23
|
+
|
|
24
|
+
return this.table
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
isPrimaryKey() {
|
|
28
|
+
return digg(this, "data", "is_primary_key")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
isUnique() {
|
|
32
|
+
return digg(this, "data", "is_unique")
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseDriversBaseTable {
|
|
4
|
+
async getColumnByName(columnName) {
|
|
5
|
+
const columnes = await this.getColumns()
|
|
6
|
+
const column = columnes.find((column) => column.getName() == columnName)
|
|
7
|
+
|
|
8
|
+
return column
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
getDriver() {
|
|
12
|
+
if (!this.driver) throw new Error("No driver set on table")
|
|
13
|
+
|
|
14
|
+
return this.driver
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getOptions() {
|
|
18
|
+
return this.getDriver().options()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async rowsCount() {
|
|
22
|
+
const result = await this.getDriver().query(`SELECT COUNT(*) AS count FROM ${this.getOptions().quoteTableName(this.getName())}`)
|
|
23
|
+
|
|
24
|
+
return digg(result, 0, "count")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async truncate(args) {
|
|
28
|
+
const databaseType = this.getDriver().getType()
|
|
29
|
+
let sql
|
|
30
|
+
|
|
31
|
+
if (databaseType == "sqlite") {
|
|
32
|
+
sql = `DELETE FROM ${this.getOptions().quoteTableName(this.getName())}`
|
|
33
|
+
} else {
|
|
34
|
+
sql = `TRUNCATE TABLE ${this.getOptions().quoteTableName(this.getName())}`
|
|
35
|
+
|
|
36
|
+
if (args?.cascade && databaseType == "pgsql") {
|
|
37
|
+
sql += " CASCADE"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
await this.getDriver().query(sql)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -38,7 +38,11 @@ export default class VelociousDatabaseDriversBase {
|
|
|
38
38
|
return this._args
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
getConfiguration
|
|
41
|
+
getConfiguration() {
|
|
42
|
+
if (!this.configuration) throw new Error("No configuration set")
|
|
43
|
+
|
|
44
|
+
return this.configuration
|
|
45
|
+
}
|
|
42
46
|
|
|
43
47
|
getIdSeq() {
|
|
44
48
|
return this.idSeq
|
|
@@ -48,11 +52,11 @@ export default class VelociousDatabaseDriversBase {
|
|
|
48
52
|
throw new Error(`${this.constructor.name}#getTables not implemented`)
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
async getTableByName(name) {
|
|
55
|
+
async getTableByName(name, args) {
|
|
52
56
|
const tables = await this.getTables()
|
|
53
57
|
const table = tables.find((table) => table.getName() == name)
|
|
54
58
|
|
|
55
|
-
if (!table) throw new Error(`Couldn't find a table by that name: ${name}`)
|
|
59
|
+
if (!table && args?.throwError !== false) throw new Error(`Couldn't find a table by that name: ${name}`)
|
|
56
60
|
|
|
57
61
|
return table
|
|
58
62
|
}
|
|
@@ -135,16 +139,7 @@ export default class VelociousDatabaseDriversBase {
|
|
|
135
139
|
|
|
136
140
|
if (this._transactionsCount == 0) {
|
|
137
141
|
this.logger.debug("Start transaction")
|
|
138
|
-
this.
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
await this.startTransaction()
|
|
142
|
-
} catch (error) {
|
|
143
|
-
this._transactionsCount--
|
|
144
|
-
|
|
145
|
-
throw error
|
|
146
|
-
}
|
|
147
|
-
|
|
142
|
+
await this.startTransaction()
|
|
148
143
|
transactionStarted = true
|
|
149
144
|
} else {
|
|
150
145
|
this.logger.debug("Start savepoint", savePointName)
|
|
@@ -165,7 +160,6 @@ export default class VelociousDatabaseDriversBase {
|
|
|
165
160
|
if (transactionStarted) {
|
|
166
161
|
this.logger.debug("Commit transaction")
|
|
167
162
|
await this.commitTransaction()
|
|
168
|
-
this._transactionsCount--
|
|
169
163
|
}
|
|
170
164
|
} catch (error) {
|
|
171
165
|
this.logger.debug("Transaction error", error.message)
|
|
@@ -178,7 +172,6 @@ export default class VelociousDatabaseDriversBase {
|
|
|
178
172
|
if (transactionStarted) {
|
|
179
173
|
this.logger.debug("Rollback transaction")
|
|
180
174
|
await this.rollbackTransaction()
|
|
181
|
-
this._transactionsCount--
|
|
182
175
|
}
|
|
183
176
|
|
|
184
177
|
throw error
|
|
@@ -188,15 +181,18 @@ export default class VelociousDatabaseDriversBase {
|
|
|
188
181
|
}
|
|
189
182
|
|
|
190
183
|
async startTransaction() {
|
|
191
|
-
|
|
184
|
+
await this.query("BEGIN TRANSACTION")
|
|
185
|
+
this._transactionsCount++
|
|
192
186
|
}
|
|
193
187
|
|
|
194
188
|
async commitTransaction() {
|
|
195
189
|
await this.query("COMMIT")
|
|
190
|
+
this._transactionsCount--
|
|
196
191
|
}
|
|
197
192
|
|
|
198
193
|
async rollbackTransaction() {
|
|
199
194
|
await this.query("ROLLBACK")
|
|
195
|
+
this._transactionsCount--
|
|
200
196
|
}
|
|
201
197
|
|
|
202
198
|
generateSavePointName() {
|
|
@@ -1,10 +1,51 @@
|
|
|
1
|
+
import BaseColumn from "../base-column.js"
|
|
2
|
+
import ColumnsIndex from "./columns-index.js"
|
|
1
3
|
import {digg} from "diggerize"
|
|
2
4
|
|
|
3
|
-
export default class VelociousDatabaseDriversMssqlColumn {
|
|
5
|
+
export default class VelociousDatabaseDriversMssqlColumn extends BaseColumn {
|
|
4
6
|
constructor(table, data) {
|
|
7
|
+
super()
|
|
5
8
|
this.data = data
|
|
6
9
|
this.table = table
|
|
7
10
|
}
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
async getIndexes() {
|
|
13
|
+
const options = this.getOptions()
|
|
14
|
+
const sql = `
|
|
15
|
+
SELECT
|
|
16
|
+
sys.tables.name AS TableName,
|
|
17
|
+
sys.columns.name AS ColumnName,
|
|
18
|
+
sys.indexes.name AS index_name,
|
|
19
|
+
sys.indexes.type_desc AS IndexType,
|
|
20
|
+
sys.index_columns.is_included_column AS IsIncludedColumn,
|
|
21
|
+
sys.indexes.is_unique,
|
|
22
|
+
sys.indexes.is_primary_key,
|
|
23
|
+
sys.indexes.is_unique_constraint
|
|
24
|
+
FROM sys.indexes
|
|
25
|
+
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
|
|
26
|
+
INNER JOIN sys.columns ON sys.index_columns.object_id = sys.columns.object_id AND sys.index_columns.column_id = sys.columns.column_id
|
|
27
|
+
INNER JOIN sys.tables ON sys.indexes.object_id = sys.tables.object_id
|
|
28
|
+
WHERE
|
|
29
|
+
sys.tables.name = ${options.quote(this.getTable().getName())} AND
|
|
30
|
+
sys.columns.name = ${options.quote(this.getName())}
|
|
31
|
+
ORDER BY
|
|
32
|
+
sys.indexes.name,
|
|
33
|
+
sys.index_columns.key_ordinal
|
|
34
|
+
`
|
|
35
|
+
|
|
36
|
+
const rows = await this.getDriver().query(sql)
|
|
37
|
+
const indexes = []
|
|
38
|
+
|
|
39
|
+
for (const row of rows) {
|
|
40
|
+
const index = new ColumnsIndex(this.getTable(), row)
|
|
41
|
+
|
|
42
|
+
indexes.push(index)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return indexes
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getName() {
|
|
49
|
+
return digg(this, "data", "COLUMN_NAME")
|
|
50
|
+
}
|
|
10
51
|
}
|