velocious 1.0.5 → 1.0.6
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 -3
- package/spec/cli/commands/db/create-spec.mjs +1 -1
- package/spec/cli/commands/db/migrate-spec.mjs +2 -0
- package/spec/database/record/create-spec.mjs +9 -0
- package/spec/database/record/find-spec.mjs +0 -1
- package/spec/database/record/query-spec.mjs +37 -0
- package/spec/dummy/index.mjs +14 -2
- package/spec/dummy/src/config/configuration.example.mjs +16 -1
- package/spec/dummy/src/config/configuration.peakflow.mjs +16 -1
- package/spec/dummy/src/database/migrations/20230728075328-create-projects.mjs +0 -1
- package/spec/dummy/src/database/migrations/20230728075329-create-tasks.mjs +0 -1
- package/spec/dummy/src/database/migrations/20250605133926-create-project-translations.mjs +16 -0
- package/spec/dummy/src/models/project.mjs +9 -0
- package/spec/dummy/src/models/task.mjs +5 -1
- package/src/big-brother.mjs +37 -0
- package/src/cli/commands/db/create.mjs +8 -6
- package/src/cli/commands/db/migrate.mjs +1 -2
- package/src/cli/commands/generate/migration.mjs +1 -1
- package/src/cli/commands/generate/model.mjs +1 -1
- package/src/configuration.mjs +39 -3
- package/src/database/drivers/base.mjs +21 -2
- package/src/database/drivers/mysql/column.mjs +8 -0
- package/src/database/drivers/mysql/index.mjs +34 -2
- package/src/database/drivers/mysql/options.mjs +1 -0
- package/src/database/drivers/mysql/query-parser.mjs +2 -23
- package/src/database/drivers/mysql/table.mjs +25 -0
- package/src/database/drivers/sqlite/base.mjs +76 -4
- package/src/database/drivers/sqlite/column.mjs +10 -0
- package/src/database/drivers/sqlite/index.native.mjs +19 -22
- package/src/database/drivers/sqlite/index.web.mjs +27 -17
- package/src/database/drivers/sqlite/options.mjs +2 -1
- package/src/database/drivers/sqlite/query-parser.mjs +2 -23
- package/src/database/drivers/sqlite/query.native.mjs +16 -1
- package/src/database/drivers/sqlite/query.web.mjs +27 -2
- package/src/database/drivers/sqlite/sql/create-index.mjs +4 -0
- package/src/database/drivers/sqlite/table.mjs +16 -1
- package/src/database/initializer-from-require-context.mjs +21 -0
- package/src/database/migration/index.mjs +34 -2
- package/src/database/migrator.mjs +4 -2
- package/src/database/pool/base.mjs +5 -0
- package/src/database/query/base.mjs +2 -1
- package/src/database/query/create-index-base.mjs +50 -0
- package/src/database/query/create-table-base.mjs +40 -17
- package/src/database/query/index.mjs +83 -21
- package/src/database/query/preloader/belongs-to.mjs +52 -0
- package/src/database/query/preloader/has-many.mjs +55 -0
- package/src/database/query/preloader.mjs +41 -0
- package/src/database/query/where-base.mjs +9 -0
- package/src/database/query/where-hash.mjs +35 -0
- package/src/database/query/where-plain.mjs +13 -0
- package/src/database/query-parser/base-query-parser.mjs +33 -0
- package/src/database/query-parser/group-parser.mjs +40 -0
- package/src/database/query-parser/joins-parser.mjs +48 -7
- package/src/database/query-parser/limit-parser.mjs +40 -0
- package/src/database/query-parser/options.mjs +2 -1
- package/src/database/query-parser/order-parser.mjs +39 -0
- package/src/database/query-parser/select-parser.mjs +5 -1
- package/src/database/query-parser/where-parser.mjs +39 -0
- package/src/database/record/index.mjs +464 -29
- package/src/database/record/instance-relationships/base.mjs +28 -0
- package/src/database/record/instance-relationships/belongs-to.mjs +20 -0
- package/src/database/record/instance-relationships/has-many.mjs +47 -0
- package/src/database/record/relationships/base.mjs +32 -0
- package/src/database/record/relationships/belongs-to.mjs +12 -0
- package/src/database/record/relationships/has-many.mjs +12 -0
- package/src/database/table-data/index.mjs +15 -25
- package/src/http-server/worker-handler/worker-thread.mjs +7 -4
- package/src/templates/generate-model.mjs +3 -1
- package/src/utils/rest-args-error.mjs +9 -0
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"velocious": "bin/velocious.mjs"
|
|
4
4
|
},
|
|
5
5
|
"name": "velocious",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.6",
|
|
7
7
|
"main": "index.mjs",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"test": "jasmine",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "git+https://github.com/kaspernj/velocious.git"
|
|
16
16
|
},
|
|
17
|
-
"author": "
|
|
17
|
+
"author": "kasper@diestoeckels.de",
|
|
18
18
|
"license": "ISC",
|
|
19
19
|
"bugs": {
|
|
20
20
|
"url": "https://github.com/kaspernj/velocious/issues"
|
|
@@ -24,9 +24,11 @@
|
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"jasmine": "^5.0.2",
|
|
26
26
|
"mysql": "^2.18.1",
|
|
27
|
-
"node-fetch": "^3.3.1"
|
|
27
|
+
"node-fetch": "^3.3.1",
|
|
28
|
+
"require-context": "^1.1.0"
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
31
|
+
"better-localstorage": "^1.0.7",
|
|
30
32
|
"diggerize": "^1.0.5",
|
|
31
33
|
"ejs": "^3.1.6",
|
|
32
34
|
"escape-string-regexp": "^1.0.5",
|
|
@@ -17,7 +17,7 @@ describe("Cli - Commands - db:create", () => {
|
|
|
17
17
|
sql: 'CREATE DATABASE IF NOT EXISTS `velocious_test`'
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
createSchemaMigrationsTableSql: 'CREATE TABLE IF NOT EXISTS schema_migrations (`version` varchar(255) PRIMARY KEY)'
|
|
20
|
+
createSchemaMigrationsTableSql: 'CREATE TABLE IF NOT EXISTS schema_migrations (`version` varchar(255) PRIMARY KEY NOT NULL)'
|
|
21
21
|
}
|
|
22
22
|
]
|
|
23
23
|
)
|
|
@@ -17,6 +17,7 @@ describe("Cli - Commands - db:migrate", () => {
|
|
|
17
17
|
await db.withConnection(async () => {
|
|
18
18
|
await db.query("DROP TABLE IF EXISTS tasks")
|
|
19
19
|
await db.query("DROP TABLE IF EXISTS projects")
|
|
20
|
+
await db.query("DROP TABLE IF EXISTS project_translations")
|
|
20
21
|
})
|
|
21
22
|
|
|
22
23
|
await cli.execute()
|
|
@@ -29,6 +30,7 @@ describe("Cli - Commands - db:migrate", () => {
|
|
|
29
30
|
|
|
30
31
|
expect(tablesResult).toEqual(
|
|
31
32
|
[
|
|
33
|
+
{Tables_in_velocious_test: "project_translations"},
|
|
32
34
|
{Tables_in_velocious_test: "projects"},
|
|
33
35
|
{Tables_in_velocious_test: "tasks"}
|
|
34
36
|
]
|
|
@@ -5,10 +5,19 @@ describe("Record - create", () => {
|
|
|
5
5
|
it("creates a new simple record", async () => {
|
|
6
6
|
await Dummy.run(async () => {
|
|
7
7
|
const task = new Task({name: "Test task"})
|
|
8
|
+
const project = task.buildProject({nameEn: "Test project", nameDe: "Test projekt"})
|
|
8
9
|
|
|
9
10
|
await task.save()
|
|
10
11
|
|
|
11
12
|
expect(task.id()).not.toBeUndefined()
|
|
13
|
+
expect(task.name()).toEqual("Test task")
|
|
14
|
+
expect(task.project().id()).toEqual(project.id())
|
|
15
|
+
expect(task.project()).toEqual(project)
|
|
16
|
+
|
|
17
|
+
expect(project.id()).not.toBeUndefined()
|
|
18
|
+
expect(project.name()).toEqual("Test project")
|
|
19
|
+
expect(project.nameDe()).toEqual("Test projekt")
|
|
20
|
+
expect(project.nameEn()).toEqual("Test project")
|
|
12
21
|
})
|
|
13
22
|
})
|
|
14
23
|
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Dummy from "../../dummy/index.mjs"
|
|
2
|
+
import Task from "../../dummy/src/models/task.mjs"
|
|
3
|
+
|
|
4
|
+
describe("Record - query", () => {
|
|
5
|
+
it("queries for records", async () => {
|
|
6
|
+
await Dummy.run(async () => {
|
|
7
|
+
const task = new Task({name: "Test task"})
|
|
8
|
+
const project = task.buildProject({nameEn: "Test project", nameDe: "Test projekt"})
|
|
9
|
+
|
|
10
|
+
await task.save()
|
|
11
|
+
|
|
12
|
+
expect(task.id()).not.toBeUndefined()
|
|
13
|
+
expect(task.name()).toEqual("Test task")
|
|
14
|
+
expect(task.project().id()).toEqual(project.id())
|
|
15
|
+
expect(task.project()).toEqual(project)
|
|
16
|
+
|
|
17
|
+
expect(project.id()).not.toBeUndefined()
|
|
18
|
+
expect(project.name()).toEqual("Test project")
|
|
19
|
+
expect(project.nameDe()).toEqual("Test projekt")
|
|
20
|
+
expect(project.nameEn()).toEqual("Test project")
|
|
21
|
+
|
|
22
|
+
const tasks = await Task.preload({project: {translations: true}}).toArray()
|
|
23
|
+
const newTask = tasks[0]
|
|
24
|
+
const newProject = newTask.project()
|
|
25
|
+
|
|
26
|
+
expect(newTask.id()).not.toBeUndefined()
|
|
27
|
+
expect(newTask.name()).toEqual("Test task")
|
|
28
|
+
expect(task.project().id()).toEqual(newProject.id())
|
|
29
|
+
expect(newTask.project()).toEqual(newProject)
|
|
30
|
+
|
|
31
|
+
expect(newProject.id()).not.toBeUndefined()
|
|
32
|
+
expect(newProject.name()).toEqual("Test project")
|
|
33
|
+
expect(newProject.nameDe()).toEqual("Test projekt")
|
|
34
|
+
expect(newProject.nameEn()).toEqual("Test project")
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
})
|
package/spec/dummy/index.mjs
CHANGED
|
@@ -11,11 +11,23 @@ export default class Dummy {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
static async prepare() {
|
|
14
|
+
dummyConfiguration.setCurrent()
|
|
15
|
+
|
|
14
16
|
const db = dummyConfiguration.getDatabasePool()
|
|
15
17
|
|
|
16
18
|
await db.withConnection(async () => {
|
|
17
19
|
await db.query("DROP TABLE IF EXISTS tasks")
|
|
18
|
-
await db.query("
|
|
20
|
+
await db.query("DROP TABLE IF EXISTS projects")
|
|
21
|
+
await db.query("DROP TABLE IF EXISTS project_translations")
|
|
22
|
+
|
|
23
|
+
await db.query("CREATE TABLE tasks (id MEDIUMINT NOT NULL AUTO_INCREMENT, project_id MEDIUMINT, name VARCHAR(255), description TEXT, PRIMARY KEY (id))")
|
|
24
|
+
await db.query("CREATE TABLE projects (id MEDIUMINT NOT NULL AUTO_INCREMENT, PRIMARY KEY (id))")
|
|
25
|
+
await db.query("CREATE TABLE project_translations (id MEDIUMINT NOT NULL AUTO_INCREMENT, project_id MEDIUMINT, locale VARCHAR(255), name VARCHAR(255), PRIMARY KEY (id))")
|
|
26
|
+
await db.query("CREATE UNIQUE INDEX unique_project_translation ON project_translations (project_id, locale)")
|
|
27
|
+
|
|
28
|
+
if (!dummyConfiguration.isInitialized()) {
|
|
29
|
+
await dummyConfiguration.initialize()
|
|
30
|
+
}
|
|
19
31
|
})
|
|
20
32
|
}
|
|
21
33
|
|
|
@@ -25,10 +37,10 @@ export default class Dummy {
|
|
|
25
37
|
|
|
26
38
|
async run(callback) {
|
|
27
39
|
await dummyConfiguration.getDatabasePool().withConnection(async () => {
|
|
40
|
+
await Dummy.prepare()
|
|
28
41
|
await this.start()
|
|
29
42
|
|
|
30
43
|
try {
|
|
31
|
-
await Dummy.prepare()
|
|
32
44
|
await callback()
|
|
33
45
|
} finally {
|
|
34
46
|
await this.stop()
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import AsyncTrackedMultiConnection from "../../../../src/database/pool/async-tracked-multi-connection.mjs"
|
|
2
2
|
import Configuration from "../../../../src/configuration.mjs"
|
|
3
3
|
import dummyDirectory from "../../dummy-directory.mjs"
|
|
4
|
+
import fs from "fs/promises"
|
|
5
|
+
import InitializerFromRequireContext from "../../../../src/database/initializer-from-require-context.mjs"
|
|
4
6
|
import MysqlDriver from "../../../../src/database/drivers/mysql/index.mjs"
|
|
7
|
+
import path from "path"
|
|
8
|
+
import requireContext from "require-context"
|
|
5
9
|
|
|
6
10
|
export default new Configuration({
|
|
7
11
|
database: {
|
|
@@ -17,5 +21,16 @@ export default new Configuration({
|
|
|
17
21
|
}
|
|
18
22
|
}
|
|
19
23
|
},
|
|
20
|
-
directory: dummyDirectory()
|
|
24
|
+
directory: dummyDirectory(),
|
|
25
|
+
initializeModels: async ({configuration}) => {
|
|
26
|
+
const modelsPath = await fs.realpath(`${path.dirname(import.meta.dirname)}/../src/models`)
|
|
27
|
+
const requireContextModels = requireContext(modelsPath, true, /^(.+)\.mjs$/)
|
|
28
|
+
const initializerFromRequireContext = new InitializerFromRequireContext({requireContext: requireContextModels})
|
|
29
|
+
|
|
30
|
+
await configuration.getDatabasePool().withConnection(async () => {
|
|
31
|
+
await initializerFromRequireContext.initialize({configuration})
|
|
32
|
+
})
|
|
33
|
+
},
|
|
34
|
+
locale: () => "en",
|
|
35
|
+
locales: ["de", "en"]
|
|
21
36
|
})
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import AsyncTrackedMultiConnection from "../../../../src/database/pool/async-tracked-multi-connection.mjs"
|
|
2
2
|
import Configuration from "../../../../src/configuration.mjs"
|
|
3
3
|
import dummyDirectory from "../../dummy-directory.mjs"
|
|
4
|
+
import fs from "fs/promises"
|
|
5
|
+
import InitializerFromRequireContext from "../../../../src/database/initializer-from-require-context.mjs"
|
|
4
6
|
import MysqlDriver from "../../../../src/database/drivers/mysql/index.mjs"
|
|
7
|
+
import path from "path"
|
|
8
|
+
import requireContext from "require-context"
|
|
5
9
|
|
|
6
10
|
export default new Configuration({
|
|
7
11
|
database: {
|
|
@@ -18,5 +22,16 @@ export default new Configuration({
|
|
|
18
22
|
}
|
|
19
23
|
}
|
|
20
24
|
},
|
|
21
|
-
directory: dummyDirectory()
|
|
25
|
+
directory: dummyDirectory(),
|
|
26
|
+
initializeModels: async ({configuration}) => {
|
|
27
|
+
const modelsPath = await fs.realpath(`${path.dirname(import.meta.dirname)}/../src/models`)
|
|
28
|
+
const requireContextModels = requireContext(modelsPath, true, /^(.+)\.mjs$/)
|
|
29
|
+
const initializerFromRequireContext = new InitializerFromRequireContext({requireContext: requireContextModels})
|
|
30
|
+
|
|
31
|
+
await configuration.getDatabasePool().withConnection(async () => {
|
|
32
|
+
await initializerFromRequireContext.initialize({configuration})
|
|
33
|
+
})
|
|
34
|
+
},
|
|
35
|
+
locale: () => "en",
|
|
36
|
+
locales: ["de", "en"]
|
|
22
37
|
})
|
|
@@ -3,7 +3,6 @@ import Migration from "../../../../../src/database/migration/index.mjs"
|
|
|
3
3
|
export default class CreateProjects extends Migration {
|
|
4
4
|
async change() {
|
|
5
5
|
await this.createTable("projects", (table) => {
|
|
6
|
-
table.bigint("id", {autoIncrement: true, primaryKey: true})
|
|
7
6
|
table.string("name", {maxLength: 100, null: false})
|
|
8
7
|
table.timestamps()
|
|
9
8
|
})
|
|
@@ -3,7 +3,6 @@ import Migration from "../../../../../src/database/migration/index.mjs"
|
|
|
3
3
|
export default class CreateTasks extends Migration {
|
|
4
4
|
async change() {
|
|
5
5
|
await this.createTable("tasks", (table) => {
|
|
6
|
-
table.bigint("id", {autoIncrement: true, primaryKey: true})
|
|
7
6
|
table.references("project")
|
|
8
7
|
table.string("name")
|
|
9
8
|
table.text("description")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Migration from "../../../../../src/database/migration/index.mjs"
|
|
2
|
+
|
|
3
|
+
export default class CreateProjectTranslations extends Migration {
|
|
4
|
+
async up() {
|
|
5
|
+
await this.createTable("project_translations", (t) => {
|
|
6
|
+
t.references("project", {null: false})
|
|
7
|
+
t.string("locale", {null: false})
|
|
8
|
+
t.string("name")
|
|
9
|
+
t.timestamps()
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async down() {
|
|
14
|
+
await this.dropTable("project_translations")
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export default class VelociousBigBrother {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.enabledLoggers = {
|
|
4
|
+
databaseQuery: false
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
checkExists(name) {
|
|
9
|
+
if (!(name in this.enabledLoggers)) throw new Error(`Invalid logger name: ${name}`)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
isEnabled(name) {
|
|
13
|
+
this.checkExists(name)
|
|
14
|
+
|
|
15
|
+
return this.enabledLoggers[name]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async run({after, before, name}, callback) {
|
|
19
|
+
this.checkExists(name)
|
|
20
|
+
|
|
21
|
+
if (!this.enabledLoggers[name]) {
|
|
22
|
+
return await callback()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (before) {
|
|
26
|
+
before()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const startTime = new Date()
|
|
30
|
+
const result = await callback()
|
|
31
|
+
const endTime = new Date()
|
|
32
|
+
|
|
33
|
+
if (after) {
|
|
34
|
+
after({result})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -39,12 +39,14 @@ export default class DbCreate extends BaseCommand{
|
|
|
39
39
|
|
|
40
40
|
schemaMigrationsTable.string("version", {null: false, primaryKey: true})
|
|
41
41
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
const createSchemaMigrationsTableSqls = this.databaseConnection.createTableSql(schemaMigrationsTable)
|
|
43
|
+
|
|
44
|
+
for (const createSchemaMigrationsTableSql of createSchemaMigrationsTableSqls) {
|
|
45
|
+
if (this.args.testing) {
|
|
46
|
+
this.result.push({createSchemaMigrationsTableSql})
|
|
47
|
+
} else {
|
|
48
|
+
await this.databaseConnection.query(createSchemaMigrationsTableSql)
|
|
49
|
+
}
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
52
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import BaseCommand from "../../base-command.mjs"
|
|
2
|
-
import {digg} from "diggerize"
|
|
3
2
|
import fs from "node:fs/promises"
|
|
4
|
-
import inflection from "inflection"
|
|
3
|
+
import * as inflection from "inflection"
|
|
5
4
|
|
|
6
5
|
export default class DbMigrate extends BaseCommand {
|
|
7
6
|
async execute() {
|
|
@@ -3,7 +3,7 @@ import {dirname} from "path"
|
|
|
3
3
|
import {fileURLToPath} from "url"
|
|
4
4
|
import fileExists from "../../../utils/file-exists.mjs"
|
|
5
5
|
import fs from "node:fs/promises"
|
|
6
|
-
import inflection from "inflection"
|
|
6
|
+
import * as inflection from "inflection"
|
|
7
7
|
import strftime from "strftime"
|
|
8
8
|
|
|
9
9
|
export default class DbGenerateMigration extends BaseCommand {
|
|
@@ -3,7 +3,7 @@ import {dirname} from "path"
|
|
|
3
3
|
import {fileURLToPath} from "url"
|
|
4
4
|
import fileExists from "../../../utils/file-exists.mjs"
|
|
5
5
|
import fs from "node:fs/promises"
|
|
6
|
-
import inflection from "inflection"
|
|
6
|
+
import * as inflection from "inflection"
|
|
7
7
|
|
|
8
8
|
export default class DbGenerateModel extends BaseCommand {
|
|
9
9
|
async execute() {
|
package/src/configuration.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {digg} from "diggerize"
|
|
2
|
+
import restArgsError from "./utils/rest-args-error.mjs"
|
|
2
3
|
|
|
3
4
|
export default class VelociousConfiguration {
|
|
4
5
|
static current(throwError = true) {
|
|
@@ -7,10 +8,19 @@ export default class VelociousConfiguration {
|
|
|
7
8
|
return this.velociousConfiguration
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
constructor({database, debug, directory}) {
|
|
11
|
+
constructor({database, debug, directory, initializeModels, locale, locales, ...restArgs}) {
|
|
12
|
+
restArgsError(restArgs)
|
|
13
|
+
|
|
14
|
+
if (!initializeModels) throw new Error("initializeModels wasn't given")
|
|
15
|
+
|
|
11
16
|
this.database = database
|
|
12
17
|
this.debug = debug
|
|
13
18
|
this._directory = directory
|
|
19
|
+
this._initializeModels = initializeModels
|
|
20
|
+
this._isInitialized = false
|
|
21
|
+
this.locale = locale
|
|
22
|
+
this.locales = locales
|
|
23
|
+
this.modelClasses = {}
|
|
14
24
|
}
|
|
15
25
|
|
|
16
26
|
getDatabasePool() {
|
|
@@ -39,6 +49,26 @@ export default class VelociousConfiguration {
|
|
|
39
49
|
return this._directory
|
|
40
50
|
}
|
|
41
51
|
|
|
52
|
+
getLocale() {
|
|
53
|
+
if (typeof this.locale == "function") {
|
|
54
|
+
return this.locale()
|
|
55
|
+
} else if (this.locale) {
|
|
56
|
+
return this.locale
|
|
57
|
+
} else {
|
|
58
|
+
return this.getLocales()[0]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getLocales = () => digg(this, "locales")
|
|
63
|
+
|
|
64
|
+
getModelClass(name) {
|
|
65
|
+
const modelClass = this.modelClasses[name]
|
|
66
|
+
|
|
67
|
+
if (!modelClass) throw new Error(`No such model class ${name} in ${Object.keys(this.modelClasses).join(", ")}}`)
|
|
68
|
+
|
|
69
|
+
return modelClass
|
|
70
|
+
}
|
|
71
|
+
|
|
42
72
|
initializeDatabasePool() {
|
|
43
73
|
if (!this.database) throw new Error("No 'database' was given")
|
|
44
74
|
if (this.databasePool) throw new Error("DatabasePool has already been initialized")
|
|
@@ -50,9 +80,15 @@ export default class VelociousConfiguration {
|
|
|
50
80
|
}
|
|
51
81
|
|
|
52
82
|
isDatabasePoolInitialized = () => Boolean(this.databasePool)
|
|
83
|
+
isInitialized = () => this._isInitialized
|
|
84
|
+
|
|
85
|
+
async initialize() {
|
|
86
|
+
await this._initializeModels({configuration: this})
|
|
87
|
+
this._isInitialized = true
|
|
88
|
+
}
|
|
53
89
|
|
|
54
|
-
|
|
55
|
-
|
|
90
|
+
registerModelClass(modelClass) {
|
|
91
|
+
this.modelClasses[modelClass.name] = modelClass
|
|
56
92
|
}
|
|
57
93
|
|
|
58
94
|
setCurrent() {
|
|
@@ -7,9 +7,11 @@ export default class VelociousDatabaseDriversBase {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
async createTable(...args) {
|
|
10
|
-
const
|
|
10
|
+
const sqls = this.createTableSql(...args)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
for (const sql of sqls) {
|
|
13
|
+
await this.query(sql)
|
|
14
|
+
}
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
async delete(...args) {
|
|
@@ -26,12 +28,29 @@ export default class VelociousDatabaseDriversBase {
|
|
|
26
28
|
return this.idSeq
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
getTables() {
|
|
32
|
+
throw new Error(`${this.constructor.name}#getTables not implemented`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async getTableByName(name) {
|
|
36
|
+
const tables = await this.getTables()
|
|
37
|
+
const table = tables.find((table) => table.getName() == name)
|
|
38
|
+
|
|
39
|
+
if (!table) throw new Error(`Couldn't find a table by that name: ${name}`)
|
|
40
|
+
|
|
41
|
+
return table
|
|
42
|
+
}
|
|
43
|
+
|
|
29
44
|
async insert(...args) {
|
|
30
45
|
const sql = this.insertSql(...args)
|
|
31
46
|
|
|
32
47
|
await this.query(sql)
|
|
33
48
|
}
|
|
34
49
|
|
|
50
|
+
lastInsertID() {
|
|
51
|
+
throw new Error(`${this.constructor.name}#lastInsertID not implemented`)
|
|
52
|
+
}
|
|
53
|
+
|
|
35
54
|
async select(tableName) {
|
|
36
55
|
const handler = new Handler()
|
|
37
56
|
const query = new Query({
|
|
@@ -9,6 +9,7 @@ import Options from "./options.mjs"
|
|
|
9
9
|
import mysql from "mysql"
|
|
10
10
|
import query from "./query.mjs"
|
|
11
11
|
import QueryParser from "./query-parser.mjs"
|
|
12
|
+
import Table from "./table.mjs"
|
|
12
13
|
import Update from "./sql/update.mjs"
|
|
13
14
|
|
|
14
15
|
export default class VelociousDatabaseDriversMysql extends Base{
|
|
@@ -64,13 +65,25 @@ export default class VelociousDatabaseDriversMysql extends Base{
|
|
|
64
65
|
return new QueryParser({query}).toSql()
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
escape(string) {
|
|
68
69
|
if (!this.connection) throw new Error("Can't escape before connected")
|
|
69
70
|
|
|
70
71
|
return this.connection.escape(string)
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
|
|
74
|
+
quote(string) {
|
|
75
|
+
return `${this.escape(string)}`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
quoteColumn = (string) => {
|
|
79
|
+
if (string.includes("`")) throw new Error(`Possible SQL injection in column name: ${string}`)
|
|
80
|
+
|
|
81
|
+
return `\`${string}\``
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
quoteTable = (string) => {
|
|
85
|
+
if (string.includes("`")) throw new Error(`Possible SQL injection in table name: ${string}`)
|
|
86
|
+
|
|
74
87
|
return `\`${string}\``
|
|
75
88
|
}
|
|
76
89
|
|
|
@@ -86,6 +99,25 @@ export default class VelociousDatabaseDriversMysql extends Base{
|
|
|
86
99
|
return insert.toSql()
|
|
87
100
|
}
|
|
88
101
|
|
|
102
|
+
async getTables() {
|
|
103
|
+
const result = await this.query("SHOW FULL TABLES")
|
|
104
|
+
const tables = []
|
|
105
|
+
|
|
106
|
+
for (const row of result) {
|
|
107
|
+
const table = new Table(this, row)
|
|
108
|
+
|
|
109
|
+
tables.push(table)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return tables
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async lastInsertID() {
|
|
116
|
+
const result = await this.query("SELECT LAST_INSERT_ID() AS last_insert_id")
|
|
117
|
+
|
|
118
|
+
return digg(result, 0, "last_insert_id")
|
|
119
|
+
}
|
|
120
|
+
|
|
89
121
|
options() {
|
|
90
122
|
if (!this._options) {
|
|
91
123
|
this._options = new Options({driver: this})
|
|
@@ -3,6 +3,7 @@ import QueryParserOptions from "../../query-parser/options.mjs"
|
|
|
3
3
|
export default class VelociousDatabaseDriversMysqlOptions extends QueryParserOptions {
|
|
4
4
|
constructor(options) {
|
|
5
5
|
options.columnQuote = "`"
|
|
6
|
+
options.indexQuote = "`"
|
|
6
7
|
options.stringQuote = "'"
|
|
7
8
|
options.tableQuote = "`"
|
|
8
9
|
|
|
@@ -1,25 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import FromParser from "../../query-parser/from-parser.mjs"
|
|
3
|
-
import JoinsParser from "../../query-parser/joins-parser.mjs"
|
|
4
|
-
import SelectParser from "../../query-parser/select-parser.mjs"
|
|
1
|
+
import BaseQueryParser from "../../query-parser/base-query-parser.mjs"
|
|
5
2
|
|
|
6
|
-
export default class VelociousDatabaseConnectionDriversMysqlQueryParser {
|
|
7
|
-
constructor({pretty, query}) {
|
|
8
|
-
if (!query) throw new Error("No query given")
|
|
9
|
-
|
|
10
|
-
this.pretty = pretty
|
|
11
|
-
this.query = query
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
toSql() {
|
|
15
|
-
const {pretty, query} = digs(this, "pretty", "query")
|
|
16
|
-
|
|
17
|
-
let sql = ""
|
|
18
|
-
|
|
19
|
-
sql += new SelectParser({pretty, query}).toSql()
|
|
20
|
-
sql += new FromParser({pretty, query}).toSql()
|
|
21
|
-
sql += new JoinsParser({pretty, query}).toSql()
|
|
22
|
-
|
|
23
|
-
return sql
|
|
24
|
-
}
|
|
3
|
+
export default class VelociousDatabaseConnectionDriversMysqlQueryParser extends BaseQueryParser {
|
|
25
4
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import Column from "./column.mjs"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseDriversMysqlTable {
|
|
4
|
+
constructor(driver, data) {
|
|
5
|
+
this.data = data
|
|
6
|
+
this.driver = driver
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async getColumns() {
|
|
10
|
+
const result = await this.driver.query(`SHOW FULL COLUMNS FROM \`${this.getName()}\``)
|
|
11
|
+
const columns = []
|
|
12
|
+
|
|
13
|
+
for (const data of result) {
|
|
14
|
+
const column = new Column(this, data)
|
|
15
|
+
|
|
16
|
+
columns.push(column)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return columns
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getName() {
|
|
23
|
+
return Object.values(this.data)[0]
|
|
24
|
+
}
|
|
25
|
+
}
|