velocious 1.0.12 → 1.0.15
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 +6 -2
- package/peak_flow.yml +12 -4
- package/spec/cli/commands/db/create-spec.js +21 -11
- package/spec/cli/commands/db/migrate-spec.js +21 -9
- package/spec/database/drivers/mysql/connection-spec.js +9 -7
- package/spec/database/record/create-spec.js +1 -1
- package/spec/database/record/translation-fallbacks-spec.js +1 -1
- package/spec/dummy/db/.keep +0 -0
- package/spec/dummy/index.js +20 -5
- package/spec/dummy/src/config/configuration.peakflow.sqlite.js +37 -0
- package/spec/dummy/src/config/configuration.sqlite.js +37 -0
- package/spec/dummy/src/config/routes.js +2 -0
- package/spec/dummy/src/database/migrations/20230728075328-create-projects.js +0 -1
- package/spec/dummy/src/database/migrations/20230728075329-create-tasks.js +1 -1
- package/spec/dummy/src/database/migrations/20250605133926-create-project-translations.js +1 -1
- package/spec/dummy/src/routes/projects/controller.js +28 -0
- package/spec/dummy/src/routes/tasks/controller.js +2 -1
- package/spec/http-server/post-spec.js +15 -15
- package/src/cli/commands/db/create.js +5 -3
- package/src/cli/index.js +2 -0
- package/src/configuration.js +10 -0
- package/src/database/drivers/base.js +5 -2
- package/src/database/drivers/mysql/foreign-key.js +13 -0
- package/src/database/drivers/mysql/index.js +13 -0
- package/src/database/drivers/mysql/sql/create-index.js +4 -0
- package/src/database/drivers/mysql/table.js +22 -0
- package/src/database/drivers/sqlite/base.js +4 -0
- package/src/database/drivers/sqlite/foreign-key.js +14 -0
- package/src/database/drivers/sqlite/index.js +3 -20
- package/src/database/drivers/sqlite/sql/create-index.js +1 -1
- package/src/database/drivers/sqlite/table.js +15 -1
- package/src/database/initializer-from-require-context.js +5 -1
- package/src/database/migration/index.js +40 -5
- package/src/database/pool/async-tracked-multi-connection.js +0 -12
- package/src/database/pool/base.js +22 -1
- package/src/database/pool/single-multi-use.js +0 -12
- package/src/database/query/create-index-base.js +1 -1
- package/src/database/query/create-table-base.js +29 -8
- package/src/database/query/insert-base.js +23 -8
- package/src/database/table-data/index.js +20 -0
- /package/spec/dummy/src/config/{configuration.peakflow.js → configuration.peakflow.mariadb.js} +0 -0
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"velocious": "bin/velocious.js"
|
|
4
4
|
},
|
|
5
5
|
"name": "velocious",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.15",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"test": "jasmine",
|
|
@@ -25,16 +25,20 @@
|
|
|
25
25
|
"jasmine": "^5.0.2",
|
|
26
26
|
"mysql": "^2.18.1",
|
|
27
27
|
"node-fetch": "^3.3.1",
|
|
28
|
-
"require-context": "^1.1.0"
|
|
28
|
+
"require-context": "^1.1.0",
|
|
29
|
+
"sqlite": "^5.1.1",
|
|
30
|
+
"sqlite3": "^5.1.7"
|
|
29
31
|
},
|
|
30
32
|
"dependencies": {
|
|
31
33
|
"better-localstorage": "^1.0.7",
|
|
34
|
+
"debounce": "^2.2.0",
|
|
32
35
|
"diggerize": "^1.0.5",
|
|
33
36
|
"ejs": "^3.1.6",
|
|
34
37
|
"escape-string-regexp": "^1.0.5",
|
|
35
38
|
"incorporator": "^1.0.2",
|
|
36
39
|
"inflection": "^3.0.0",
|
|
37
40
|
"sql-escape-string": "^1.1.0",
|
|
41
|
+
"sql-string-escape": "^1.1.6",
|
|
38
42
|
"sql.js": "^1.12.0",
|
|
39
43
|
"strftime": "^0.10.2"
|
|
40
44
|
}
|
package/peak_flow.yml
CHANGED
|
@@ -5,9 +5,7 @@ before_install:
|
|
|
5
5
|
- sudo apt-get update
|
|
6
6
|
- sudo apt-get install -y nodejs
|
|
7
7
|
before_script:
|
|
8
|
-
- cp spec/dummy/src/config/configuration.peakflow.js spec/dummy/src/config/configuration.js
|
|
9
8
|
- npm install
|
|
10
|
-
- wait-for-it mariadb:3306
|
|
11
9
|
services:
|
|
12
10
|
mariadb:
|
|
13
11
|
environment:
|
|
@@ -20,5 +18,15 @@ services:
|
|
|
20
18
|
- 3306
|
|
21
19
|
mem_limit: 4096m
|
|
22
20
|
restart_policy: on-failure
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
builds:
|
|
22
|
+
build_1:
|
|
23
|
+
name: MariaDB
|
|
24
|
+
script:
|
|
25
|
+
- cp spec/dummy/src/config/configuration.peakflow.mariadb.js spec/dummy/src/config/configuration.js
|
|
26
|
+
- wait-for-it mariadb:3306
|
|
27
|
+
- npm test
|
|
28
|
+
build_2:
|
|
29
|
+
name: SQLite
|
|
30
|
+
script:
|
|
31
|
+
- cp spec/dummy/src/config/configuration.peakflow.sqlite.js spec/dummy/src/config/configuration.js
|
|
32
|
+
- npm test
|
|
@@ -10,16 +10,26 @@ describe("Cli - Commands - db:create", () => {
|
|
|
10
10
|
})
|
|
11
11
|
const result = await cli.execute()
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
if (cli.getConfiguration().getDatabaseType() == "sqlite") {
|
|
14
|
+
expect(result).toEqual(
|
|
15
|
+
[
|
|
16
|
+
{
|
|
17
|
+
createSchemaMigrationsTableSql: 'CREATE TABLE IF NOT EXISTS schema_migrations (`version` VARCHAR(255) PRIMARY KEY NOT NULL)'
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
)
|
|
21
|
+
} else {
|
|
22
|
+
expect(result).toEqual(
|
|
23
|
+
[
|
|
24
|
+
{
|
|
25
|
+
databaseName: 'velocious_test',
|
|
26
|
+
sql: 'CREATE DATABASE IF NOT EXISTS `velocious_test`'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
createSchemaMigrationsTableSql: 'CREATE TABLE IF NOT EXISTS schema_migrations (`version` VARCHAR(255) PRIMARY KEY NOT NULL)'
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
)
|
|
33
|
+
}
|
|
24
34
|
})
|
|
25
35
|
})
|
|
@@ -12,28 +12,40 @@ describe("Cli - Commands - db:migrate", () => {
|
|
|
12
12
|
|
|
13
13
|
await cli.loadConfiguration()
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const dbPool = cli.configuration.getDatabasePool()
|
|
16
16
|
|
|
17
|
-
await
|
|
17
|
+
await dbPool.withConnection(async (db) => {
|
|
18
18
|
await db.query("DROP TABLE IF EXISTS tasks")
|
|
19
|
-
await db.query("DROP TABLE IF EXISTS projects")
|
|
20
19
|
await db.query("DROP TABLE IF EXISTS project_translations")
|
|
20
|
+
await db.query("DROP TABLE IF EXISTS projects")
|
|
21
21
|
})
|
|
22
22
|
|
|
23
23
|
await cli.execute()
|
|
24
24
|
|
|
25
|
-
let tablesResult
|
|
25
|
+
let projectForeignKey, tablesResult
|
|
26
|
+
|
|
27
|
+
await dbPool.withConnection(async (db) => {
|
|
28
|
+
const tables = await db.getTables()
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
tablesResult = tables.map((table) => table.getName())
|
|
31
|
+
|
|
32
|
+
const table = await db.getTableByName("tasks")
|
|
33
|
+
const foreignKeys = await table.getForeignKeys()
|
|
34
|
+
|
|
35
|
+
projectForeignKey = foreignKeys.find((foreignKey) => foreignKey.getColumnName() == "project_id")
|
|
29
36
|
})
|
|
30
37
|
|
|
31
38
|
expect(tablesResult).toEqual(
|
|
32
39
|
[
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
"project_translations",
|
|
41
|
+
"projects",
|
|
42
|
+
"tasks"
|
|
36
43
|
]
|
|
37
44
|
)
|
|
45
|
+
|
|
46
|
+
expect(projectForeignKey.getTableName()).toEqual("tasks")
|
|
47
|
+
expect(projectForeignKey.getColumnName()).toEqual("project_id")
|
|
48
|
+
expect(projectForeignKey.getReferencedTableName()).toEqual("projects")
|
|
49
|
+
expect(projectForeignKey.getReferencedColumnName()).toEqual("id")
|
|
38
50
|
})
|
|
39
51
|
})
|
|
@@ -6,15 +6,17 @@ const mysqlConfig = digg(configuration, "database", "default", "master")
|
|
|
6
6
|
|
|
7
7
|
describe("Database - Drivers - Mysql - Connection", () => {
|
|
8
8
|
it("connects", async () => {
|
|
9
|
-
|
|
9
|
+
if (configuration.getDatabaseType() != "sqlite") {
|
|
10
|
+
const mysql = new DatabaseDriversMysql(mysqlConfig)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
await mysql.connect()
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
const result = await mysql.query("SELECT \"1\" AS test1, \"2\" AS test2")
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
expect(result).toEqual([{
|
|
17
|
+
test1: "1",
|
|
18
|
+
test2: "2"
|
|
19
|
+
}])
|
|
20
|
+
}
|
|
19
21
|
})
|
|
20
22
|
})
|
|
@@ -2,7 +2,7 @@ import Dummy from "../../dummy/index.js"
|
|
|
2
2
|
import Task from "../../dummy/src/models/task.js"
|
|
3
3
|
|
|
4
4
|
describe("Record - create", () => {
|
|
5
|
-
it("creates a new simple record", async () => {
|
|
5
|
+
it("creates a new simple record with relationships and translations", async () => {
|
|
6
6
|
await Dummy.run(async () => {
|
|
7
7
|
const task = new Task({name: "Test task"})
|
|
8
8
|
const project = task.buildProject({nameEn: "Test project", nameDe: "Test projekt"})
|
|
@@ -2,7 +2,7 @@ import Dummy from "../../dummy/index.js"
|
|
|
2
2
|
import Task from "../../dummy/src/models/task.js"
|
|
3
3
|
|
|
4
4
|
describe("Record - create", () => {
|
|
5
|
-
it("creates a new simple record", async () => {
|
|
5
|
+
it("creates a new simple record with relationships and translations with fallbacks", async () => {
|
|
6
6
|
await Dummy.run(async () => {
|
|
7
7
|
const task = new Task({name: "Test task"})
|
|
8
8
|
const project = task.buildProject({nameDe: "Test projekt"})
|
|
File without changes
|
package/spec/dummy/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Application from "../../src/application.js"
|
|
2
2
|
import dummyConfiguration from "./src/config/configuration.js"
|
|
3
|
+
import Migration from "../../src/database/migration/index.js"
|
|
3
4
|
|
|
4
5
|
export default class Dummy {
|
|
5
6
|
static current() {
|
|
@@ -17,13 +18,27 @@ export default class Dummy {
|
|
|
17
18
|
|
|
18
19
|
await db.withConnection(async () => {
|
|
19
20
|
await db.query("DROP TABLE IF EXISTS tasks")
|
|
20
|
-
await db.query("DROP TABLE IF EXISTS projects")
|
|
21
21
|
await db.query("DROP TABLE IF EXISTS project_translations")
|
|
22
|
+
await db.query("DROP TABLE IF EXISTS projects")
|
|
23
|
+
|
|
24
|
+
const migration = new Migration({configuration: dummyConfiguration})
|
|
25
|
+
|
|
26
|
+
await migration.createTable("projects", (t) => {
|
|
27
|
+
t.timestamps()
|
|
28
|
+
})
|
|
29
|
+
await migration.createTable("project_translations", (t) => {
|
|
30
|
+
t.references("project", {null: false, foreignKey: true})
|
|
31
|
+
t.string("locale", {null: false})
|
|
32
|
+
t.string("name")
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
await migration.addIndex("project_translations", ["project_id", "locale"], {unique: true})
|
|
22
36
|
|
|
23
|
-
await
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
await migration.createTable("tasks", (t) => {
|
|
38
|
+
t.references("project")
|
|
39
|
+
t.string("name")
|
|
40
|
+
t.text("description")
|
|
41
|
+
})
|
|
27
42
|
|
|
28
43
|
if (!dummyConfiguration.isInitialized()) {
|
|
29
44
|
await dummyConfiguration.initialize()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Configuration from "../../../../src/configuration.js"
|
|
2
|
+
import dummyDirectory from "../../dummy-directory.js"
|
|
3
|
+
import fs from "fs/promises"
|
|
4
|
+
import InitializerFromRequireContext from "../../../../src/database/initializer-from-require-context.js"
|
|
5
|
+
import SqliteDriver from "../../../../src/database/drivers/sqlite/index.js"
|
|
6
|
+
import path from "path"
|
|
7
|
+
import requireContext from "require-context"
|
|
8
|
+
import SingleMultiUsePool from "../../../../src/database/pool/single-multi-use.js"
|
|
9
|
+
|
|
10
|
+
export default new Configuration({
|
|
11
|
+
database: {
|
|
12
|
+
default: {
|
|
13
|
+
master: {
|
|
14
|
+
driver: SqliteDriver,
|
|
15
|
+
poolType: SingleMultiUsePool,
|
|
16
|
+
type: "sqlite",
|
|
17
|
+
name: "test-db"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
directory: dummyDirectory(),
|
|
22
|
+
initializeModels: async ({configuration}) => {
|
|
23
|
+
const modelsPath = await fs.realpath(`${path.dirname(import.meta.dirname)}/../src/models`)
|
|
24
|
+
const requireContextModels = requireContext(modelsPath, true, /^(.+)\.js$/)
|
|
25
|
+
const initializerFromRequireContext = new InitializerFromRequireContext({requireContext: requireContextModels})
|
|
26
|
+
|
|
27
|
+
await configuration.getDatabasePool().withConnection(async () => {
|
|
28
|
+
await initializerFromRequireContext.initialize({configuration})
|
|
29
|
+
})
|
|
30
|
+
},
|
|
31
|
+
locale: () => "en",
|
|
32
|
+
localeFallbacks: {
|
|
33
|
+
de: ["de", "en"],
|
|
34
|
+
en: ["en", "de"]
|
|
35
|
+
},
|
|
36
|
+
locales: ["de", "en"]
|
|
37
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Configuration from "../../../../src/configuration.js"
|
|
2
|
+
import dummyDirectory from "../../dummy-directory.js"
|
|
3
|
+
import fs from "fs/promises"
|
|
4
|
+
import InitializerFromRequireContext from "../../../../src/database/initializer-from-require-context.js"
|
|
5
|
+
import path from "path"
|
|
6
|
+
import requireContext from "require-context"
|
|
7
|
+
import SqliteDriver from "../../../../src/database/drivers/sqlite/index.js"
|
|
8
|
+
import SingleMultiUsePool from "../../../../src/database/pool/single-multi-use.js"
|
|
9
|
+
|
|
10
|
+
export default new Configuration({
|
|
11
|
+
database: {
|
|
12
|
+
default: {
|
|
13
|
+
master: {
|
|
14
|
+
driver: SqliteDriver,
|
|
15
|
+
poolType: SingleMultiUsePool,
|
|
16
|
+
type: "sqlite",
|
|
17
|
+
name: "test-db"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
directory: dummyDirectory(),
|
|
22
|
+
initializeModels: async ({configuration}) => {
|
|
23
|
+
const modelsPath = await fs.realpath(`${path.dirname(import.meta.dirname)}/../src/models`)
|
|
24
|
+
const requireContextModels = requireContext(modelsPath, true, /^(.+)\.js$/)
|
|
25
|
+
const initializerFromRequireContext = new InitializerFromRequireContext({requireContext: requireContextModels})
|
|
26
|
+
|
|
27
|
+
await configuration.getDatabasePool().withConnection(async () => {
|
|
28
|
+
await initializerFromRequireContext.initialize({configuration})
|
|
29
|
+
})
|
|
30
|
+
},
|
|
31
|
+
locale: () => "en",
|
|
32
|
+
localeFallbacks: {
|
|
33
|
+
de: ["de", "en"],
|
|
34
|
+
en: ["en", "de"]
|
|
35
|
+
},
|
|
36
|
+
locales: ["de", "en"]
|
|
37
|
+
})
|
|
@@ -3,7 +3,6 @@ import Migration from "../../../../../src/database/migration/index.js"
|
|
|
3
3
|
export default class CreateProjects extends Migration {
|
|
4
4
|
async change() {
|
|
5
5
|
await this.createTable("projects", (table) => {
|
|
6
|
-
table.string("name", {maxLength: 100, null: false})
|
|
7
6
|
table.timestamps()
|
|
8
7
|
})
|
|
9
8
|
}
|
|
@@ -3,7 +3,7 @@ import Migration from "../../../../../src/database/migration/index.js"
|
|
|
3
3
|
export default class CreateTasks extends Migration {
|
|
4
4
|
async change() {
|
|
5
5
|
await this.createTable("tasks", (table) => {
|
|
6
|
-
table.references("project")
|
|
6
|
+
table.references("project", {foreignKey: true, null: false})
|
|
7
7
|
table.string("name")
|
|
8
8
|
table.text("description")
|
|
9
9
|
table.timestamps()
|
|
@@ -3,7 +3,7 @@ import Migration from "../../../../../src/database/migration/index.js"
|
|
|
3
3
|
export default class CreateProjectTranslations extends Migration {
|
|
4
4
|
async up() {
|
|
5
5
|
await this.createTable("project_translations", (t) => {
|
|
6
|
-
t.references("project", {null: false})
|
|
6
|
+
t.references("project", {foreignKey: true, null: false})
|
|
7
7
|
t.string("locale", {null: false})
|
|
8
8
|
t.string("name")
|
|
9
9
|
t.timestamps()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
|
|
3
|
+
import Controller from "../../../../../src/controller.js"
|
|
4
|
+
import Project from "../../models/project.js"
|
|
5
|
+
import Task from "../../models/task.js"
|
|
6
|
+
|
|
7
|
+
export default class ProjectsController extends Controller {
|
|
8
|
+
index() {
|
|
9
|
+
this.viewParams.numbers = [1, 2, 3, 4, 5]
|
|
10
|
+
this.render()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async show() {
|
|
14
|
+
const projectId = digg(params, "id")
|
|
15
|
+
const project = await Project.find(projectId)
|
|
16
|
+
|
|
17
|
+
this.viewParams.project = project
|
|
18
|
+
this.render()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async create() {
|
|
22
|
+
const project = new Project(this.params().project)
|
|
23
|
+
|
|
24
|
+
await project.save()
|
|
25
|
+
|
|
26
|
+
this.render({json: {status: "success"}})
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import fetch from "node-fetch"
|
|
2
|
-
import Dummy from "../dummy/index.js"
|
|
3
2
|
import querystring from "querystring"
|
|
4
|
-
|
|
3
|
+
|
|
4
|
+
import Dummy from "../dummy/index.js"
|
|
5
|
+
import Project from "../dummy/src/models/project.js"
|
|
5
6
|
|
|
6
7
|
describe("HttpServer", () => {
|
|
7
8
|
it("handles post requests", async () => {
|
|
8
9
|
await Dummy.run(async () => {
|
|
9
|
-
const postData = querystring.stringify({"
|
|
10
|
+
const postData = querystring.stringify({"project[name]": "Test create project"})
|
|
10
11
|
const response = await fetch(
|
|
11
|
-
"http://localhost:3006/
|
|
12
|
+
"http://localhost:3006/projects",
|
|
12
13
|
{
|
|
13
14
|
body: postData,
|
|
14
15
|
headers: {
|
|
@@ -19,18 +20,18 @@ describe("HttpServer", () => {
|
|
|
19
20
|
}
|
|
20
21
|
)
|
|
21
22
|
const text = await response.text()
|
|
22
|
-
const
|
|
23
|
+
const createdProject = await Project.preload({translations: true}).last()
|
|
23
24
|
|
|
24
25
|
expect(text).toEqual('{"status":"success"}')
|
|
25
|
-
expect(
|
|
26
|
+
expect(createdProject.name()).toEqual("Test create project")
|
|
26
27
|
})
|
|
27
28
|
})
|
|
28
29
|
|
|
29
30
|
it("handles post json requests", async () => {
|
|
30
31
|
await Dummy.run(async () => {
|
|
31
|
-
const postData = JSON.stringify({
|
|
32
|
+
const postData = JSON.stringify({project: {name: "Test create project"}})
|
|
32
33
|
const response = await fetch(
|
|
33
|
-
"http://localhost:3006/
|
|
34
|
+
"http://localhost:3006/projects",
|
|
34
35
|
{
|
|
35
36
|
body: postData,
|
|
36
37
|
headers: {
|
|
@@ -41,10 +42,10 @@ describe("HttpServer", () => {
|
|
|
41
42
|
}
|
|
42
43
|
)
|
|
43
44
|
const text = await response.text()
|
|
44
|
-
const
|
|
45
|
+
const createdProject = await Project.preload({translations: true}).last()
|
|
45
46
|
|
|
46
47
|
expect(text).toEqual('{"status":"success"}')
|
|
47
|
-
expect(
|
|
48
|
+
expect(createdProject.name()).toEqual("Test create project")
|
|
48
49
|
})
|
|
49
50
|
})
|
|
50
51
|
|
|
@@ -52,21 +53,20 @@ describe("HttpServer", () => {
|
|
|
52
53
|
await Dummy.run(async () => {
|
|
53
54
|
const body = new FormData()
|
|
54
55
|
|
|
55
|
-
body.append("
|
|
56
|
-
body.append("task[description]", "This is a task")
|
|
56
|
+
body.append("project[name]", "Test create project")
|
|
57
57
|
|
|
58
58
|
const response = await fetch(
|
|
59
|
-
"http://localhost:3006/
|
|
59
|
+
"http://localhost:3006/projects",
|
|
60
60
|
{
|
|
61
61
|
body,
|
|
62
62
|
method: "POST"
|
|
63
63
|
}
|
|
64
64
|
)
|
|
65
65
|
const text = await response.text()
|
|
66
|
-
const
|
|
66
|
+
const createdProject = await Project.preload({translations: true}).last()
|
|
67
67
|
|
|
68
68
|
expect(text).toEqual('{"status":"success"}')
|
|
69
|
-
expect(
|
|
69
|
+
expect(createdProject.name()).toEqual("Test create project")
|
|
70
70
|
})
|
|
71
71
|
})
|
|
72
72
|
})
|
|
@@ -15,16 +15,18 @@ export default class DbCreate extends BaseCommand{
|
|
|
15
15
|
this.databaseConnection = await this.databasePool.spawnConnectionWithConfiguration(this.newConfiguration)
|
|
16
16
|
await this.databaseConnection.connect()
|
|
17
17
|
|
|
18
|
-
this.
|
|
19
|
-
|
|
18
|
+
if (this.configuration.getDatabaseType() != "sqlite") {
|
|
19
|
+
await this.createDatabase()
|
|
20
|
+
}
|
|
20
21
|
|
|
22
|
+
await this.createSchemaMigrationsTable()
|
|
21
23
|
await this.databaseConnection.close()
|
|
22
24
|
|
|
23
25
|
if (this.args.testing) return this.result
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
async createDatabase() {
|
|
27
|
-
const databaseName = digg(this
|
|
29
|
+
const databaseName = digg(this, "configuration", "database", "default", "master", "database")
|
|
28
30
|
const sql = this.databaseConnection.createDatabaseSql(databaseName, {ifNotExists: true})
|
|
29
31
|
|
|
30
32
|
if (this.args.testing) {
|
package/src/cli/index.js
CHANGED
package/src/configuration.js
CHANGED
|
@@ -42,6 +42,16 @@ export default class VelociousConfiguration {
|
|
|
42
42
|
return poolTypeClass
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
getDatabaseType() {
|
|
46
|
+
const databaseType = digg(this, "database", "default", "master", "type")
|
|
47
|
+
|
|
48
|
+
if (!databaseType) {
|
|
49
|
+
throw new Error("No database type given in database configuration")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return databaseType
|
|
53
|
+
}
|
|
54
|
+
|
|
45
55
|
getDirectory() {
|
|
46
56
|
if (!this._directory) {
|
|
47
57
|
this._directory = process.cwd()
|
|
@@ -2,8 +2,9 @@ import Query from "../query/index.js"
|
|
|
2
2
|
import Handler from "../handler.js"
|
|
3
3
|
|
|
4
4
|
export default class VelociousDatabaseDriversBase {
|
|
5
|
-
constructor(
|
|
6
|
-
this._args =
|
|
5
|
+
constructor(config, configuration) {
|
|
6
|
+
this._args = config
|
|
7
|
+
this.configuration = configuration
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
async createTable(...args) {
|
|
@@ -24,6 +25,8 @@ export default class VelociousDatabaseDriversBase {
|
|
|
24
25
|
return this._args
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
getConfiguration = () => this.configuration
|
|
29
|
+
|
|
27
30
|
getIdSeq() {
|
|
28
31
|
return this.idSeq
|
|
29
32
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseDriversMysqlForeignKey {
|
|
4
|
+
constructor(data) {
|
|
5
|
+
this.data = data
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
getColumnName = () => digg(this, "data", "COLUMN_NAME")
|
|
9
|
+
getName = () => digg(this, "data", "CONSTRAINT_NAME")
|
|
10
|
+
getTableName = () => digg(this, "data", "TABLE_NAME")
|
|
11
|
+
getReferencedColumnName = () => digg(this, "data", "REFERENCED_COLUMN_NAME")
|
|
12
|
+
getReferencedTableName = () => digg(this, "data", "REFERENCED_TABLE_NAME")
|
|
13
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Base from "../base.js"
|
|
2
2
|
import connectConnection from "./connect-connection.js"
|
|
3
3
|
import CreateDatabase from "./sql/create-database.js"
|
|
4
|
+
import CreateIndex from "./sql/create-index.js"
|
|
4
5
|
import CreateTable from "./sql/create-table.js"
|
|
5
6
|
import Delete from "./sql/delete.js"
|
|
6
7
|
import {digg} from "diggerize"
|
|
@@ -50,6 +51,13 @@ export default class VelociousDatabaseDriversMysql extends Base{
|
|
|
50
51
|
return createDatabase.toSql()
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
createIndexSql(indexData) {
|
|
55
|
+
const createArgs = Object.assign({driver: this}, indexData)
|
|
56
|
+
const createIndex = new CreateIndex(createArgs)
|
|
57
|
+
|
|
58
|
+
return createIndex.toSql()
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
createTableSql(tableData) {
|
|
54
62
|
const createArgs = Object.assign({tableData, driver: this})
|
|
55
63
|
const createTable = new CreateTable(createArgs)
|
|
@@ -57,6 +65,9 @@ export default class VelociousDatabaseDriversMysql extends Base{
|
|
|
57
65
|
return createTable.toSql()
|
|
58
66
|
}
|
|
59
67
|
|
|
68
|
+
getType = () => "mysql"
|
|
69
|
+
primaryKeyType = () => "bigint"
|
|
70
|
+
|
|
60
71
|
async query(sql) {
|
|
61
72
|
return await query(this.connection, sql)
|
|
62
73
|
}
|
|
@@ -65,6 +76,8 @@ export default class VelociousDatabaseDriversMysql extends Base{
|
|
|
65
76
|
return new QueryParser({query}).toSql()
|
|
66
77
|
}
|
|
67
78
|
|
|
79
|
+
shouldSetAutoIncrementWhenPrimaryKey = () => true
|
|
80
|
+
|
|
68
81
|
escape(string) {
|
|
69
82
|
if (!this.connection) throw new Error("Can't escape before connected")
|
|
70
83
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Column from "./column.js"
|
|
2
|
+
import ForeignKey from "./foreign-key.js"
|
|
2
3
|
|
|
3
4
|
export default class VelociousDatabaseDriversMysqlTable {
|
|
4
5
|
constructor(driver, data) {
|
|
@@ -19,6 +20,27 @@ export default class VelociousDatabaseDriversMysqlTable {
|
|
|
19
20
|
return columns
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
async getForeignKeys() {
|
|
24
|
+
const sql = `
|
|
25
|
+
SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
|
|
26
|
+
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
27
|
+
WHERE
|
|
28
|
+
REFERENCED_TABLE_SCHEMA = (SELECT DATABASE()) AND
|
|
29
|
+
TABLE_NAME = ${this.driver.quote(this.getName())}
|
|
30
|
+
`
|
|
31
|
+
|
|
32
|
+
const foreignKeyRows = await this.driver.query(sql)
|
|
33
|
+
const foreignKeys = []
|
|
34
|
+
|
|
35
|
+
for (const foreignKeyRow of foreignKeyRows) {
|
|
36
|
+
const foreignKey = new ForeignKey(foreignKeyRow)
|
|
37
|
+
|
|
38
|
+
foreignKeys.push(foreignKey)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return foreignKeys
|
|
42
|
+
}
|
|
43
|
+
|
|
22
44
|
getName() {
|
|
23
45
|
return Object.values(this.data)[0]
|
|
24
46
|
}
|
|
@@ -35,6 +35,7 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
deleteSql = (args) => new Delete(Object.assign({driver: this}, args)).toSql()
|
|
38
|
+
getType = () => "sqlite"
|
|
38
39
|
insertSql = (args) => new Insert(Object.assign({driver: this}, args)).toSql()
|
|
39
40
|
|
|
40
41
|
async getTableByName(tableName) {
|
|
@@ -125,6 +126,7 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
|
|
|
125
126
|
return this._options
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
primaryKeyType = () => "integer" // Because bigint on SQLite doesn't support auto increment
|
|
128
130
|
queryToSql = (query) => new QueryParser({query}).toSql()
|
|
129
131
|
|
|
130
132
|
async registerVersion() {
|
|
@@ -139,6 +141,8 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
|
|
|
139
141
|
this.versionPatch = versionParts[2]
|
|
140
142
|
}
|
|
141
143
|
|
|
144
|
+
shouldSetAutoIncrementWhenPrimaryKey = () => false
|
|
145
|
+
|
|
142
146
|
escape(value) {
|
|
143
147
|
const type = typeof value
|
|
144
148
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseDriversSqliteForeignKey {
|
|
4
|
+
constructor(data, {tableName}) {
|
|
5
|
+
this.data = data
|
|
6
|
+
this.tableName = tableName
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getColumnName = () => digg(this, "data", "from")
|
|
10
|
+
getName = () => `${this.getTableName()}_${this.getColumnName()}_${this.data.id}`
|
|
11
|
+
getTableName = () => digg(this, "tableName")
|
|
12
|
+
getReferencedColumnName = () => digg(this, "data", "to")
|
|
13
|
+
getReferencedTableName = () => digg(this, "data", "table")
|
|
14
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import debounce from "debounce"
|
|
2
1
|
import {digg} from "diggerize"
|
|
3
2
|
import fs from "fs/promises"
|
|
4
3
|
import query from "./query.js"
|
|
@@ -10,7 +9,7 @@ import Base from "./base.js"
|
|
|
10
9
|
export default class VelociousDatabaseDriversSqliteNode extends Base {
|
|
11
10
|
async connect() {
|
|
12
11
|
const args = this.getArgs()
|
|
13
|
-
const databasePath =
|
|
12
|
+
const databasePath = `${this.getConfiguration().getDirectory()}/db/${this.localStorageName()}.sqlite`
|
|
14
13
|
|
|
15
14
|
if (args.reset) {
|
|
16
15
|
await fs.unlink(databasePath)
|
|
@@ -24,29 +23,13 @@ export default class VelociousDatabaseDriversSqliteNode extends Base {
|
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
localStorageName = () => `VelociousDatabaseDriversSqlite---${digg(this.getArgs(), "name")}`
|
|
27
|
-
disconnect = () => this.saveDatabase()
|
|
28
|
-
saveDatabase = async () => {
|
|
29
|
-
const localStorageContent = this.connection.export()
|
|
30
|
-
await this.betterLocaleStorage.set(this.localStorageName(), localStorageContent)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
saveDatabaseDebounce = debounce(this.saveDatabase, 500)
|
|
34
26
|
|
|
35
27
|
async close() {
|
|
36
|
-
await this.
|
|
37
|
-
await this.connection.end()
|
|
28
|
+
await this.connection.close()
|
|
38
29
|
this.connection = undefined
|
|
39
30
|
}
|
|
40
31
|
|
|
41
32
|
query = async (sql) => {
|
|
42
|
-
|
|
43
|
-
const downcasedSQL = sql.toLowerCase().trim()
|
|
44
|
-
|
|
45
|
-
// Auto-save database in local storage in case we can find manipulating instructions in the SQL
|
|
46
|
-
if (downcasedSQL.startsWith("delete ") || downcasedSQL.startsWith("insert into ") || downcasedSQL.startsWith("update ")) {
|
|
47
|
-
this.saveDatabaseDebounce()
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return result
|
|
33
|
+
return await query(this.connection, sql)
|
|
51
34
|
}
|
|
52
35
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import CreateIndexBase from "../../../query/create-index-base.js"
|
|
2
2
|
|
|
3
|
-
export default class
|
|
3
|
+
export default class VelociousDatabaseConnectionDriversSqliteSqlCreateIndex extends CreateIndexBase {
|
|
4
4
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Column from "./column.js"
|
|
2
2
|
import {digg} from "diggerize"
|
|
3
|
+
import ForeignKey from "./foreign-key.js"
|
|
3
4
|
|
|
4
5
|
export default class VelociousDatabaseDriversSqliteTable {
|
|
5
6
|
constructor({driver, row}) {
|
|
@@ -7,7 +8,7 @@ export default class VelociousDatabaseDriversSqliteTable {
|
|
|
7
8
|
this.row = row
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
async getColumns() {
|
|
11
12
|
const result = await this.driver.query(`PRAGMA table_info('${this.getName()}')`)
|
|
12
13
|
const columns = []
|
|
13
14
|
|
|
@@ -20,5 +21,18 @@ export default class VelociousDatabaseDriversSqliteTable {
|
|
|
20
21
|
return columns
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
async getForeignKeys() {
|
|
25
|
+
const foreignKeysData = await this.driver.query(`SELECT * FROM pragma_foreign_key_list(${this.driver.quote(this.getName())})`)
|
|
26
|
+
const foreignKeys = []
|
|
27
|
+
|
|
28
|
+
for (const foreignKeyData of foreignKeysData) {
|
|
29
|
+
const foreignKey = new ForeignKey(foreignKeyData, {tableName: this.getName()})
|
|
30
|
+
|
|
31
|
+
foreignKeys.push(foreignKey)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return foreignKeys
|
|
35
|
+
}
|
|
36
|
+
|
|
23
37
|
getName = () => digg(this, "row", "name")
|
|
24
38
|
}
|
|
@@ -9,7 +9,11 @@ export default class VelociousDatabaseInitializerFromRequireContext {
|
|
|
9
9
|
|
|
10
10
|
async initialize({configuration}) {
|
|
11
11
|
for (const fileName of this.requireContext.keys()) {
|
|
12
|
-
const
|
|
12
|
+
const modelClassImport = this.requireContext(fileName)
|
|
13
|
+
|
|
14
|
+
if (!modelClassImport) throw new Error(`Couldn't import model class from ${fileName}`)
|
|
15
|
+
|
|
16
|
+
const modelClass = modelClassImport.default
|
|
13
17
|
|
|
14
18
|
await modelClass.initializeRecord({configuration})
|
|
15
19
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as inflection from "inflection"
|
|
1
2
|
import TableData, {TableColumn} from "../table-data/index.js"
|
|
2
3
|
|
|
3
4
|
export default class VelociousDatabaseMigration {
|
|
@@ -5,10 +6,12 @@ export default class VelociousDatabaseMigration {
|
|
|
5
6
|
this.configuration = configuration
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
async addColumn(tableName, columnName, args) {
|
|
9
|
+
async addColumn(tableName, columnName, columnType, args) {
|
|
9
10
|
const databasePool = this.configuration.getDatabasePool()
|
|
11
|
+
const tableColumnArgs = Object.assign({type: columnType}, args)
|
|
12
|
+
|
|
10
13
|
const sqls = databasePool.alterTableSql({
|
|
11
|
-
columns: [new TableColumn(columnName,
|
|
14
|
+
columns: [new TableColumn(columnName, tableColumnArgs)],
|
|
12
15
|
tableName
|
|
13
16
|
})
|
|
14
17
|
|
|
@@ -31,14 +34,46 @@ export default class VelociousDatabaseMigration {
|
|
|
31
34
|
await databasePool.query(sql)
|
|
32
35
|
}
|
|
33
36
|
|
|
37
|
+
async addForeignKey(tableName, referenceName) {
|
|
38
|
+
const referenceNameUnderscore = inflection.underscore(referenceName)
|
|
39
|
+
const tableNameUnderscore = inflection.underscore(tableName)
|
|
40
|
+
const columnName = `${referenceNameUnderscore}_id`
|
|
41
|
+
const databasePool = this.configuration.getDatabasePool()
|
|
42
|
+
const foreignKeyName = `fk_${tableName}_${referenceName}`
|
|
43
|
+
let sql = ""
|
|
44
|
+
|
|
45
|
+
sql += `ALTER TABLE ${databasePool.quoteTable(tableName)}`
|
|
46
|
+
sql += ` ADD CONSTRAINT ${foreignKeyName} `
|
|
47
|
+
sql += ` FOREIGN KEY (${databasePool.quoteColumn(columnName)})`
|
|
48
|
+
sql += ` REFERENCES ${tableNameUnderscore}(id)`
|
|
49
|
+
|
|
50
|
+
await databasePool.query(sql)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async addReference(tableName, referenceName, args) {
|
|
54
|
+
const columnName = `${inflection.underscore(referenceName)}_id`
|
|
55
|
+
|
|
56
|
+
await this.addColumn(tableName, columnName, {type: args?.type})
|
|
57
|
+
await this.addIndex(tableName, [columnName], {unique: args?.unique})
|
|
58
|
+
|
|
59
|
+
if (args?.foreignKey) {
|
|
60
|
+
await this.addForeignKey(tableName, referenceName)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
34
64
|
async createTable(tableName, callback) {
|
|
65
|
+
const databasePool = this.configuration.getDatabasePool()
|
|
66
|
+
const primaryKeyType = databasePool.primaryKeyType()
|
|
35
67
|
const tableData = new TableData(tableName)
|
|
36
68
|
|
|
37
|
-
tableData
|
|
69
|
+
if (!(primaryKeyType in tableData)) throw new Error(`Unsupported primary key type: ${primaryKeyType}`)
|
|
38
70
|
|
|
39
|
-
|
|
71
|
+
tableData[primaryKeyType]("id", {autoIncrement: true, null: false, primaryKey: true})
|
|
72
|
+
|
|
73
|
+
if (callback) {
|
|
74
|
+
callback(tableData)
|
|
75
|
+
}
|
|
40
76
|
|
|
41
|
-
const databasePool = this.configuration.getDatabasePool()
|
|
42
77
|
const sqls = databasePool.createTableSql(tableData)
|
|
43
78
|
|
|
44
79
|
for (const sql of sqls) {
|
|
@@ -4,14 +4,6 @@ import BasePool from "./base.js"
|
|
|
4
4
|
let idSeq = 0
|
|
5
5
|
|
|
6
6
|
export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends BasePool {
|
|
7
|
-
static current() {
|
|
8
|
-
if (!this.velociousDatabasePoolAsyncTrackedMultiConnection) {
|
|
9
|
-
this.velociousDatabasePoolAsyncTrackedMultiConnection = new VelociousDatabasePoolAsyncTrackedMultiConnection()
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return this.velociousDatabasePoolAsyncTrackedMultiConnection
|
|
13
|
-
}
|
|
14
|
-
|
|
15
7
|
constructor(args = {}) {
|
|
16
8
|
super(args)
|
|
17
9
|
this.connections = []
|
|
@@ -48,10 +40,6 @@ export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends Ba
|
|
|
48
40
|
return connection
|
|
49
41
|
}
|
|
50
42
|
|
|
51
|
-
setCurrent() {
|
|
52
|
-
this.constructor.velociousDatabasePoolAsyncTrackedMultiConnection = this
|
|
53
|
-
}
|
|
54
|
-
|
|
55
43
|
async withConnection(callback) {
|
|
56
44
|
const connection = await this.checkout()
|
|
57
45
|
const id = connection.getIdSeq()
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import Configuration from "../../configuration.js"
|
|
2
2
|
import {digg} from "diggerize"
|
|
3
3
|
|
|
4
|
+
if (!globalThis.velociousDatabasePoolBase) {
|
|
5
|
+
globalThis.velociousDatabasePoolBase = {
|
|
6
|
+
current: null
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
class VelociousDatabasePoolBase {
|
|
11
|
+
static current() {
|
|
12
|
+
if (!globalThis.velociousDatabasePoolBase.current) {
|
|
13
|
+
globalThis.velociousDatabasePoolBase.current = new this()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return globalThis.velociousDatabasePoolBase.current
|
|
17
|
+
}
|
|
18
|
+
|
|
5
19
|
constructor(args = {}) {
|
|
6
20
|
this.configuration = args.configuration || Configuration.current()
|
|
7
21
|
this.connections = []
|
|
@@ -10,6 +24,10 @@ class VelociousDatabasePoolBase {
|
|
|
10
24
|
|
|
11
25
|
getConfiguration = () => digg(this, "configuration", "database", "default", "master")
|
|
12
26
|
|
|
27
|
+
setCurrent() {
|
|
28
|
+
globalThis.velociousDatabasePoolBase.current = this
|
|
29
|
+
}
|
|
30
|
+
|
|
13
31
|
setDriverClass(driverClass) {
|
|
14
32
|
this.driverClass = driverClass
|
|
15
33
|
}
|
|
@@ -26,7 +44,7 @@ class VelociousDatabasePoolBase {
|
|
|
26
44
|
|
|
27
45
|
if (!DriverClass) throw new Error("No driver class set in database pool or in given config")
|
|
28
46
|
|
|
29
|
-
const connection = new DriverClass(config)
|
|
47
|
+
const connection = new DriverClass(config, this.configuration)
|
|
30
48
|
|
|
31
49
|
await connection.connect()
|
|
32
50
|
|
|
@@ -46,8 +64,11 @@ const forwardMethods = [
|
|
|
46
64
|
"getTables",
|
|
47
65
|
"insert",
|
|
48
66
|
"insertSql",
|
|
67
|
+
"primaryKeyType",
|
|
49
68
|
"query",
|
|
50
69
|
"quote",
|
|
70
|
+
"quoteColumn",
|
|
71
|
+
"quoteTable",
|
|
51
72
|
"select",
|
|
52
73
|
"update",
|
|
53
74
|
"updateSql"
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import BasePool from "./base.js"
|
|
2
2
|
|
|
3
3
|
export default class VelociousDatabasePoolSingleMultiUser extends BasePool {
|
|
4
|
-
static current() {
|
|
5
|
-
if (!this.velociousDatabasePoolSingleMultiUser) {
|
|
6
|
-
this.velociousDatabasePoolSingleMultiUser = new VelociousDatabasePoolSingleMultiUser()
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
return this.velociousDatabasePoolSingleMultiUser
|
|
10
|
-
}
|
|
11
|
-
|
|
12
4
|
checkin = (connection) => {
|
|
13
5
|
// Do nothing
|
|
14
6
|
}
|
|
@@ -21,10 +13,6 @@ export default class VelociousDatabasePoolSingleMultiUser extends BasePool {
|
|
|
21
13
|
return this.connection
|
|
22
14
|
}
|
|
23
15
|
|
|
24
|
-
setCurrent() {
|
|
25
|
-
this.constructor.velociousDatabasePoolSingleMultiUser = this
|
|
26
|
-
}
|
|
27
|
-
|
|
28
16
|
async withConnection(callback) {
|
|
29
17
|
await this.checkout() // Ensure a connection is present
|
|
30
18
|
await callback(this.connection)
|
|
@@ -15,7 +15,7 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
|
|
|
15
15
|
let indexName = `index_on_${this.tableName}_`
|
|
16
16
|
|
|
17
17
|
for (const columnIndex in this.columns) {
|
|
18
|
-
if (columnIndex > 0) indexName += "
|
|
18
|
+
if (columnIndex > 0) indexName += "_and_"
|
|
19
19
|
|
|
20
20
|
indexName += this.columns[columnIndex]
|
|
21
21
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import CreateIndexBase from "./create-index-base.js"
|
|
2
|
+
import * as inflection from "inflection"
|
|
2
3
|
import QueryBase from "./base.js"
|
|
3
4
|
|
|
4
5
|
export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
|
|
@@ -9,7 +10,10 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
|
|
|
9
10
|
this.tableData = tableData
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
getConfiguration = () => this.driver.getConfiguration()
|
|
14
|
+
|
|
12
15
|
toSql() {
|
|
16
|
+
const databaseType = this.getConfiguration().getDatabaseType()
|
|
13
17
|
const {tableData} = this
|
|
14
18
|
const sqls = []
|
|
15
19
|
|
|
@@ -24,23 +28,40 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
|
|
|
24
28
|
for (const column of tableData.getColumns()) {
|
|
25
29
|
columnCount++
|
|
26
30
|
|
|
27
|
-
let maxlength = column.
|
|
28
|
-
let type = column.
|
|
31
|
+
let maxlength = column.getMaxLength()
|
|
32
|
+
let type = column.getType().toUpperCase()
|
|
29
33
|
|
|
30
|
-
if (type == "
|
|
31
|
-
type = "
|
|
34
|
+
if (type == "STRING") {
|
|
35
|
+
type = "VARCHAR"
|
|
32
36
|
maxlength ||= 255
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
if (databaseType == "sqlite" && column.getAutoIncrement() && column.getPrimaryKey()) {
|
|
40
|
+
type = "INTEGER"
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
if (columnCount > 1) sql += ", "
|
|
36
44
|
|
|
37
|
-
sql += `${this.driver.quoteColumn(column.
|
|
45
|
+
sql += `${this.driver.quoteColumn(column.getName())} ${type}`
|
|
38
46
|
|
|
39
47
|
if (maxlength !== undefined) sql += `(${maxlength})`
|
|
40
48
|
|
|
41
|
-
if (column.
|
|
42
|
-
if (column.
|
|
43
|
-
if (column.
|
|
49
|
+
if (column.getAutoIncrement() && this.driver.shouldSetAutoIncrementWhenPrimaryKey()) sql += " AUTO_INCREMENT"
|
|
50
|
+
if (column.getPrimaryKey()) sql += " PRIMARY KEY"
|
|
51
|
+
if (column.getNull() === false) sql += " NOT NULL"
|
|
52
|
+
|
|
53
|
+
if (column.getForeignKey()) {
|
|
54
|
+
let foreignKeyTable, foreignKeyColumn
|
|
55
|
+
|
|
56
|
+
if (column.getForeignKey() === true) {
|
|
57
|
+
foreignKeyColumn = "id"
|
|
58
|
+
foreignKeyTable = inflection.pluralize(column.getName().replace(/_id$/, ""))
|
|
59
|
+
} else {
|
|
60
|
+
throw new Error(`Unknown foreign key type given: ${column.getForeignKey()} (${typeof column.getForeignKey()})`)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
sql += ` REFERENCES ${this.driver.quoteTable(foreignKeyTable)}(${this.driver.quoteColumn(foreignKeyColumn)})`
|
|
64
|
+
}
|
|
44
65
|
}
|
|
45
66
|
|
|
46
67
|
if (this.indexInCreateTable) {
|
|
@@ -20,7 +20,7 @@ export default class VelociousDatabaseQueryInsertBase {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
toSql() {
|
|
23
|
-
let sql = `INSERT INTO ${this.getOptions().quoteTableName(this.tableName)}
|
|
23
|
+
let sql = `INSERT INTO ${this.getOptions().quoteTableName(this.tableName)}`
|
|
24
24
|
let count = 0
|
|
25
25
|
let columns
|
|
26
26
|
|
|
@@ -32,16 +32,24 @@ export default class VelociousDatabaseQueryInsertBase {
|
|
|
32
32
|
throw new Error("Neither 'column' and 'rows' or data was given")
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
if (columns.length > 0) {
|
|
36
|
+
sql += " ("
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
for (const columnName of columns) {
|
|
39
|
+
if (count > 0) sql += ", "
|
|
40
|
+
|
|
41
|
+
sql += this.getOptions().quoteColumnName(columnName)
|
|
42
|
+
count++
|
|
43
|
+
}
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
sql += ")"
|
|
46
|
+
}
|
|
43
47
|
|
|
44
48
|
if (this.columns && this.rows) {
|
|
49
|
+
if (this.rows.length > 0) {
|
|
50
|
+
sql += " VALUES "
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
let count = 0
|
|
46
54
|
|
|
47
55
|
for (const row of this.rows) {
|
|
@@ -51,7 +59,14 @@ export default class VelociousDatabaseQueryInsertBase {
|
|
|
51
59
|
sql += this._valuesSql(row)
|
|
52
60
|
}
|
|
53
61
|
} else {
|
|
54
|
-
|
|
62
|
+
if (Object.keys(this.data).length > 0) {
|
|
63
|
+
sql += " VALUES "
|
|
64
|
+
sql += this._valuesSql(Object.values(this.data))
|
|
65
|
+
} else if (this.driver.getType() == "sqlite") {
|
|
66
|
+
sql += " DEFAULT VALUES"
|
|
67
|
+
} else if (this.driver.getType() == "mysql") {
|
|
68
|
+
sql += " () VALUES ()"
|
|
69
|
+
}
|
|
55
70
|
}
|
|
56
71
|
|
|
57
72
|
return sql
|
|
@@ -1,14 +1,34 @@
|
|
|
1
|
+
import restArgsError from "../../utils/rest-args-error.js"
|
|
2
|
+
|
|
1
3
|
class TableColumn {
|
|
2
4
|
constructor(name, args) {
|
|
5
|
+
if (args) {
|
|
6
|
+
const {autoIncrement, foreignKey, maxLength, name, null: argsNull, primaryKey, type, ...restArgs} = args
|
|
7
|
+
|
|
8
|
+
restArgsError(restArgs)
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
this.args = args
|
|
4
12
|
this.name = name
|
|
5
13
|
}
|
|
6
14
|
|
|
15
|
+
getAutoIncrement = () => this.args?.autoIncrement
|
|
16
|
+
getForeignKey = () => this.args?.foreignKey
|
|
17
|
+
getMaxLength = () => this.args?.maxLength
|
|
7
18
|
getName = () => this.name
|
|
19
|
+
getNull = () => this.args?.null
|
|
20
|
+
getPrimaryKey = () => this.args?.primaryKey
|
|
21
|
+
getType = () => this.args?.type
|
|
8
22
|
}
|
|
9
23
|
|
|
10
24
|
class TableIndex {
|
|
11
25
|
constructor(columns, args) {
|
|
26
|
+
if (args) {
|
|
27
|
+
const {name, unique, ...restArgs} = args
|
|
28
|
+
|
|
29
|
+
restArgsError(restArgs)
|
|
30
|
+
}
|
|
31
|
+
|
|
12
32
|
this.args = args
|
|
13
33
|
this.columns = columns
|
|
14
34
|
}
|
/package/spec/dummy/src/config/{configuration.peakflow.js → configuration.peakflow.mariadb.js}
RENAMED
|
File without changes
|