velocious 1.0.4 → 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/index.mjs +1 -19
- package/package.json +6 -3
- package/spec/cli/commands/db/create-spec.mjs +1 -1
- package/spec/cli/commands/db/migrate-spec.mjs +2 -0
- package/spec/database/connection/drivers/mysql/query-parser-spec.mjs +6 -5
- package/spec/database/drivers/mysql/connection-spec.mjs +2 -3
- 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 +6 -2
- 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 +60 -0
- 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 +108 -0
- package/src/database/drivers/sqlite/column.mjs +10 -0
- package/src/database/drivers/sqlite/index.native.mjs +22 -63
- package/src/database/drivers/sqlite/index.web.mjs +28 -37
- 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 +24 -0
- package/src/database/initializer-from-require-context.mjs +21 -0
- package/src/database/migrate-from-require-context.mjs +11 -2
- package/src/database/migration/index.mjs +34 -2
- package/src/database/migrator.mjs +75 -0
- package/src/database/pool/async-tracked-multi-connection.mjs +1 -1
- package/src/database/pool/base.mjs +19 -1
- package/src/database/pool/single-multi-use.mjs +1 -1
- 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/insert-base.mjs +4 -0
- 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 +4 -3
- 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/src/database/drivers/index.mjs +0 -5
- package/src/database/index.mjs +0 -15
- package/src/database/migrator/index.mjs +0 -15
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
import TableData from "./table-data/index"
|
|
3
|
+
|
|
4
|
+
export default class VelociousDatabaseMigrator {
|
|
5
|
+
constructor({configuration}) {
|
|
6
|
+
this.configuration = configuration
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async prepare() {
|
|
10
|
+
const exists = await this.migrationsTableExist()
|
|
11
|
+
|
|
12
|
+
if (!exists) await this.createMigrationsTable()
|
|
13
|
+
|
|
14
|
+
await this.loadMigrationsVersions()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async createMigrationsTable() {
|
|
18
|
+
const schemaMigrationsTable = new TableData("schema_migrations", {ifNotExists: true})
|
|
19
|
+
|
|
20
|
+
schemaMigrationsTable.string("version", {null: false, primaryKey: true})
|
|
21
|
+
|
|
22
|
+
await this.configuration.getDatabasePool().withConnection(async (db) => {
|
|
23
|
+
const createSchemaMigrationsTableSqls = db.createTableSql(schemaMigrationsTable)
|
|
24
|
+
|
|
25
|
+
for (const createSchemaMigrationsTableSql of createSchemaMigrationsTableSqls) {
|
|
26
|
+
await db.query(createSchemaMigrationsTableSql)
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
hasRunMigrationVersion(version) {
|
|
32
|
+
if (!this.migrationsVersions) {
|
|
33
|
+
throw new Error("Migrations versions hasn't been loaded yet")
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (version in this.migrationsVersions) {
|
|
37
|
+
return true
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async loadMigrationsVersions() {
|
|
44
|
+
const db = this.configuration.getDatabasePool()
|
|
45
|
+
|
|
46
|
+
this.migrationsVersions = {}
|
|
47
|
+
|
|
48
|
+
await db.withConnection(async () => {
|
|
49
|
+
const rows = await db.select("schema_migrations")
|
|
50
|
+
|
|
51
|
+
for (const row of rows) {
|
|
52
|
+
const version = digg(row, "version")
|
|
53
|
+
|
|
54
|
+
this.migrationsVersions[version] = true
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async migrationsTableExist() {
|
|
60
|
+
let exists = false
|
|
61
|
+
|
|
62
|
+
await this.configuration.getDatabasePool().withConnection(async (db) => {
|
|
63
|
+
const tables = await db.getTables()
|
|
64
|
+
|
|
65
|
+
for (const table of tables) {
|
|
66
|
+
if (table.getName() == "schema_migrations") {
|
|
67
|
+
exists = true
|
|
68
|
+
break
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
return exists
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -34,11 +34,29 @@ class VelociousDatabasePoolBase {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
const forwardMethods = [
|
|
37
|
+
const forwardMethods = [
|
|
38
|
+
"createIndex",
|
|
39
|
+
"createIndexSql",
|
|
40
|
+
"createTable",
|
|
41
|
+
"createTableSql",
|
|
42
|
+
"delete",
|
|
43
|
+
"deleteSql",
|
|
44
|
+
"getTables",
|
|
45
|
+
"insert",
|
|
46
|
+
"insertSql",
|
|
47
|
+
"query",
|
|
48
|
+
"quote",
|
|
49
|
+
"select",
|
|
50
|
+
"update",
|
|
51
|
+
"updateSql"
|
|
52
|
+
]
|
|
38
53
|
|
|
39
54
|
for (const forwardMethod of forwardMethods) {
|
|
40
55
|
VelociousDatabasePoolBase.prototype[forwardMethod] = function(...args) {
|
|
41
56
|
const connection = this.getCurrentConnection()
|
|
57
|
+
const connectionMethod = connection[forwardMethod]
|
|
58
|
+
|
|
59
|
+
if (!connectionMethod) throw new Error(`${forwardMethod} isn't defined on driver`)
|
|
42
60
|
|
|
43
61
|
return connection[forwardMethod](...args)
|
|
44
62
|
}
|
|
@@ -27,7 +27,7 @@ export default class VelociousDatabasePoolSingleMultiUser extends BasePool {
|
|
|
27
27
|
|
|
28
28
|
async withConnection(callback) {
|
|
29
29
|
await this.checkout() // Ensure a connection is present
|
|
30
|
-
await callback()
|
|
30
|
+
await callback(this.connection)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
getCurrentConnection() {
|
|
@@ -3,7 +3,8 @@ export default class VelociousDatabaseQueryBase {
|
|
|
3
3
|
this.driver = driver
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
getDriver = () => this.driver
|
|
7
|
+
getOptions = () => this.getDriver()?.options()
|
|
7
8
|
|
|
8
9
|
toSql() {
|
|
9
10
|
throw new Error("'toSql' wasn't implemented")
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
import QueryBase from "./base.mjs"
|
|
3
|
+
|
|
4
|
+
export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
|
|
5
|
+
constructor({columns, driver, ifNotExists, name, unique, tableName}) {
|
|
6
|
+
super({driver})
|
|
7
|
+
this.columns = columns
|
|
8
|
+
this.name = name
|
|
9
|
+
this.tableName = tableName
|
|
10
|
+
this.ifNotExists = ifNotExists
|
|
11
|
+
this.unique = unique
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
generateIndexName() {
|
|
15
|
+
let indexName = `index_on_${this.tableName}_`
|
|
16
|
+
|
|
17
|
+
for (const columnIndex in this.columns) {
|
|
18
|
+
if (columnIndex > 0) indexName += "_"
|
|
19
|
+
|
|
20
|
+
indexName += this.columns[columnIndex]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return indexName
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
toSql() {
|
|
27
|
+
const {tableName} = this
|
|
28
|
+
const {columnQuote, indexQuote, tableQuote} = digs(this.getOptions(), "columnQuote", "indexQuote", "tableQuote")
|
|
29
|
+
let sql = "CREATE"
|
|
30
|
+
|
|
31
|
+
if (this.unique) sql += " UNIQUE"
|
|
32
|
+
|
|
33
|
+
sql += " INDEX"
|
|
34
|
+
|
|
35
|
+
if (this.ifNotExists) sql += " IF NOT EXISTS"
|
|
36
|
+
|
|
37
|
+
sql += ` ${indexQuote}${this.name || this.generateIndexName()}${indexQuote}`
|
|
38
|
+
sql += ` ON ${tableQuote}${tableName}${tableQuote} (`
|
|
39
|
+
|
|
40
|
+
for (const columnIndex in this.columns) {
|
|
41
|
+
if (columnIndex > 0) sql += ", "
|
|
42
|
+
|
|
43
|
+
sql += `${columnQuote}${this.columns[columnIndex]}${columnQuote}`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
sql += ")"
|
|
47
|
+
|
|
48
|
+
return sql
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import CreateIndexBase from "./create-index-base.mjs"
|
|
1
2
|
import QueryBase from "./base.mjs"
|
|
2
3
|
|
|
3
4
|
export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
|
|
4
|
-
constructor({driver, ifNotExists, tableData}) {
|
|
5
|
+
constructor({driver, ifNotExists, indexInCreateTable = true, tableData}) {
|
|
5
6
|
super({driver})
|
|
6
7
|
this.ifNotExists = ifNotExists
|
|
8
|
+
this.indexInCreateTable = indexInCreateTable
|
|
7
9
|
this.tableData = tableData
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
toSql() {
|
|
11
13
|
const {tableData} = this
|
|
14
|
+
const sqls = []
|
|
15
|
+
|
|
12
16
|
let sql = "CREATE TABLE"
|
|
13
17
|
|
|
14
18
|
if (this.ifNotExists || tableData.getIfNotExists()) sql += " IF NOT EXISTS"
|
|
@@ -36,34 +40,53 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
|
|
|
36
40
|
|
|
37
41
|
if (column.args.autoIncrement) sql += " AUTO_INCREMENT"
|
|
38
42
|
if (column.args.primaryKey) sql += " PRIMARY KEY"
|
|
43
|
+
if (column.args.null === false) sql += " NOT NULL"
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
if (this.indexInCreateTable) {
|
|
47
|
+
for (const index of tableData.getIndexes()) {
|
|
48
|
+
sql += ","
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
if (index.getUnique()) {
|
|
51
|
+
sql += " UNIQUE"
|
|
52
|
+
}
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
sql += " INDEX"
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
if (index.getName()) {
|
|
57
|
+
sql += ` ${index.getName()}`
|
|
58
|
+
}
|
|
53
59
|
|
|
54
|
-
|
|
60
|
+
sql += " ("
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
index.getColumns().forEach((column, columnIndex) => {
|
|
63
|
+
if (columnIndex > 0) sql += ", "
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
sql += this.driver.quoteColumn(column.name)
|
|
66
|
+
})
|
|
61
67
|
|
|
62
|
-
|
|
68
|
+
sql += ")"
|
|
69
|
+
}
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
sql += ")"
|
|
66
73
|
|
|
67
|
-
|
|
74
|
+
sqls.push(sql)
|
|
75
|
+
|
|
76
|
+
if (!this.indexInCreateTable) {
|
|
77
|
+
for (const index of tableData.getIndexes()) {
|
|
78
|
+
const createIndexArgs = {
|
|
79
|
+
columns: index.getColumns(),
|
|
80
|
+
driver: this.getDriver(),
|
|
81
|
+
tableName: tableData.getName(),
|
|
82
|
+
unique: index.getUnique()
|
|
83
|
+
}
|
|
84
|
+
const sql = new CreateIndexBase(createIndexArgs).toSql()
|
|
85
|
+
|
|
86
|
+
sqls.push(sql)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return [sql]
|
|
68
91
|
}
|
|
69
92
|
}
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import FromPlain from "./from-plain.mjs"
|
|
2
|
+
import {incorporate} from "incorporator"
|
|
3
|
+
import * as inflection from "inflection"
|
|
2
4
|
import JoinPlain from "./join-plain.mjs"
|
|
3
5
|
import OrderPlain from "./order-plain.mjs"
|
|
6
|
+
import Preloader from "./preloader.mjs"
|
|
4
7
|
import SelectPlain from "./select-plain.mjs"
|
|
8
|
+
import WhereHash from "./where-hash.mjs"
|
|
9
|
+
import WherePlain from "./where-plain.mjs"
|
|
5
10
|
|
|
6
11
|
export default class VelociousDatabaseQuery {
|
|
7
|
-
constructor({driver, froms = [], joins = [], handler, limits = [], modelClass, orders = [], selects = [], wheres = []}) {
|
|
8
|
-
if (!driver) throw new Error("No driver given")
|
|
9
|
-
if (!handler) throw new Error("No handler given")
|
|
12
|
+
constructor({driver, froms = [], groups = [], joins = [], handler, limits = [], modelClass, orders = [], preload = {}, selects = [], wheres = []}) {
|
|
13
|
+
if (!driver) throw new Error("No driver given to query")
|
|
14
|
+
if (!handler) throw new Error("No handler given to query")
|
|
10
15
|
|
|
11
16
|
this.driver = driver
|
|
12
17
|
this.handler = handler
|
|
13
18
|
this.modelClass = modelClass
|
|
14
19
|
this._froms = froms
|
|
20
|
+
this._groups = groups
|
|
15
21
|
this._joins = joins
|
|
16
22
|
this._limits = limits
|
|
17
23
|
this._orders = orders
|
|
24
|
+
this._preload = preload
|
|
18
25
|
this._selects = selects
|
|
19
26
|
this._wheres = wheres
|
|
20
27
|
}
|
|
@@ -24,10 +31,12 @@ export default class VelociousDatabaseQuery {
|
|
|
24
31
|
driver: this.driver,
|
|
25
32
|
froms: [...this._froms],
|
|
26
33
|
handler: this.handler.clone(),
|
|
34
|
+
groups: [...this._groups],
|
|
27
35
|
joins: [...this._joins],
|
|
28
36
|
limits: [...this._limits],
|
|
29
37
|
modelClass: this.modelClass,
|
|
30
38
|
orders: [...this._orders],
|
|
39
|
+
preload: {...this._preload},
|
|
31
40
|
selects: [...this._selects],
|
|
32
41
|
wheres: [...this._wheres]
|
|
33
42
|
})
|
|
@@ -35,8 +44,38 @@ export default class VelociousDatabaseQuery {
|
|
|
35
44
|
return newQuery
|
|
36
45
|
}
|
|
37
46
|
|
|
38
|
-
getOptions()
|
|
39
|
-
|
|
47
|
+
getOptions = () => this.driver.options()
|
|
48
|
+
|
|
49
|
+
async findBy(conditions) {
|
|
50
|
+
const newConditions = {}
|
|
51
|
+
|
|
52
|
+
for (const key in conditions) {
|
|
53
|
+
const keyUnderscore = inflection.underscore(key)
|
|
54
|
+
|
|
55
|
+
newConditions[keyUnderscore] = conditions[key]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return await this.clone().where(newConditions).first()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async findOrCreateBy(conditions) {
|
|
62
|
+
const record = await this.findOrInitializeBy(conditions)
|
|
63
|
+
|
|
64
|
+
if (record.isNewRecord()) {
|
|
65
|
+
await record.save()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return record
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async findOrInitializeBy(conditions) {
|
|
72
|
+
const record = await this.findBy(conditions)
|
|
73
|
+
|
|
74
|
+
if (record) return record
|
|
75
|
+
|
|
76
|
+
const newRecord = new this.modelClass(conditions)
|
|
77
|
+
|
|
78
|
+
return newRecord
|
|
40
79
|
}
|
|
41
80
|
|
|
42
81
|
async first() {
|
|
@@ -55,24 +94,31 @@ export default class VelociousDatabaseQuery {
|
|
|
55
94
|
return this
|
|
56
95
|
}
|
|
57
96
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
limit(value) {
|
|
63
|
-
this._limits.push(value)
|
|
97
|
+
group(group) {
|
|
98
|
+
this._groups.push(group)
|
|
64
99
|
return this
|
|
65
100
|
}
|
|
66
101
|
|
|
67
102
|
joins(join) {
|
|
68
|
-
if (typeof join == "string")
|
|
69
|
-
|
|
70
|
-
join
|
|
103
|
+
if (typeof join == "string") {
|
|
104
|
+
join = new JoinPlain({plain: join, query: this})
|
|
105
|
+
} else if (typeof join == "object") {
|
|
106
|
+
// Do nothing
|
|
107
|
+
} else {
|
|
108
|
+
throw new Error(`Unknown type of join: ${typeof join}`)
|
|
109
|
+
}
|
|
71
110
|
|
|
72
111
|
this._joins.push(join)
|
|
73
112
|
return this
|
|
74
113
|
}
|
|
75
114
|
|
|
115
|
+
last = async () => await this.clone().reverseOrder().first()
|
|
116
|
+
|
|
117
|
+
limit(value) {
|
|
118
|
+
this._limits.push(value)
|
|
119
|
+
return this
|
|
120
|
+
}
|
|
121
|
+
|
|
76
122
|
order(order) {
|
|
77
123
|
if (typeof order == "number" || typeof order == "string") order = new OrderPlain({plain: order, query: this})
|
|
78
124
|
|
|
@@ -82,6 +128,11 @@ export default class VelociousDatabaseQuery {
|
|
|
82
128
|
return this
|
|
83
129
|
}
|
|
84
130
|
|
|
131
|
+
preload(data) {
|
|
132
|
+
incorporate(this._preload, data)
|
|
133
|
+
return this
|
|
134
|
+
}
|
|
135
|
+
|
|
85
136
|
reorder(order) {
|
|
86
137
|
this._orders = []
|
|
87
138
|
this.order(order)
|
|
@@ -119,23 +170,34 @@ export default class VelociousDatabaseQuery {
|
|
|
119
170
|
const models = []
|
|
120
171
|
|
|
121
172
|
for (const result of results) {
|
|
122
|
-
const model = new this.modelClass(
|
|
173
|
+
const model = new this.modelClass()
|
|
123
174
|
|
|
175
|
+
model.loadExistingRecord(result)
|
|
124
176
|
models.push(model)
|
|
125
177
|
}
|
|
126
178
|
|
|
179
|
+
if (Object.keys(this._preload).length > 0 && models.length > 0) {
|
|
180
|
+
const preloader = new Preloader({
|
|
181
|
+
modelClass: this.modelClass,
|
|
182
|
+
models,
|
|
183
|
+
preload: this._preload
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
await preloader.run()
|
|
187
|
+
}
|
|
188
|
+
|
|
127
189
|
return models
|
|
128
190
|
}
|
|
129
191
|
|
|
130
|
-
toSql()
|
|
131
|
-
return this.driver.queryToSql(this)
|
|
132
|
-
}
|
|
192
|
+
toSql = () => this.driver.queryToSql(this)
|
|
133
193
|
|
|
134
194
|
where(where) {
|
|
135
195
|
if (typeof where == "string") {
|
|
136
|
-
where = new WherePlain(
|
|
137
|
-
} else if (typeof where == "object" && where.constructor.name == "object") {
|
|
138
|
-
where = new WhereHash(
|
|
196
|
+
where = new WherePlain(this, where)
|
|
197
|
+
} else if (typeof where == "object" && (where.constructor.name == "object" || where.constructor.name == "Object")) {
|
|
198
|
+
where = new WhereHash(this, where)
|
|
199
|
+
} else {
|
|
200
|
+
throw new Error(`Invalid type of where: ${typeof where} (${where.constructor.name})`)
|
|
139
201
|
}
|
|
140
202
|
|
|
141
203
|
this._wheres.push(where)
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export default class VelociousDatabaseQueryInsertBase {
|
|
2
2
|
constructor({driver, tableName, data}) {
|
|
3
|
+
if (!driver) throw new Error("No driver given to insert base")
|
|
4
|
+
if (!tableName) throw new Error(`Invalid table name given to insert base: ${tableName}`)
|
|
5
|
+
if (!data) throw new Error("No data given to insert base")
|
|
6
|
+
|
|
3
7
|
this.data = data
|
|
4
8
|
this.driver = driver
|
|
5
9
|
this.tableName = tableName
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as inflection from "inflection"
|
|
2
|
+
import restArgsError from "../../../utils/rest-args-error.mjs"
|
|
3
|
+
|
|
4
|
+
export default class VelociousDatabaseQueryPreloaderBelongsTo {
|
|
5
|
+
constructor({models, relationship, ...restArgs}) {
|
|
6
|
+
restArgsError(restArgs)
|
|
7
|
+
|
|
8
|
+
this.models = models
|
|
9
|
+
this.relationship = relationship
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async run() {
|
|
13
|
+
const foreignKeyValues = []
|
|
14
|
+
const modelsById = {}
|
|
15
|
+
const foreignKey = this.relationship.getForeignKey()
|
|
16
|
+
const foreignKeyCamelized = inflection.camelize(foreignKey, true)
|
|
17
|
+
const preloadCollections = {}
|
|
18
|
+
|
|
19
|
+
for (const model of this.models) {
|
|
20
|
+
const foreignKeyValue = model[foreignKeyCamelized]()
|
|
21
|
+
|
|
22
|
+
preloadCollections[model.id()] = []
|
|
23
|
+
foreignKeyValues.push(foreignKeyValue)
|
|
24
|
+
modelsById[model.id()] = model
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const whereArgs = {}
|
|
28
|
+
const primaryKey = this.relationship.getPrimaryKey()
|
|
29
|
+
|
|
30
|
+
whereArgs[primaryKey] = foreignKeyValues
|
|
31
|
+
|
|
32
|
+
// Load target models to be preloaded on the given models
|
|
33
|
+
const targetModels = await this.relationship.getTargetModelClass().where(whereArgs).toArray()
|
|
34
|
+
const targetModelsById = {}
|
|
35
|
+
|
|
36
|
+
for (const targetModel of targetModels) {
|
|
37
|
+
targetModelsById[targetModel.id()] = targetModel
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Set the target preloaded models on the given models
|
|
41
|
+
for (const model of this.models) {
|
|
42
|
+
const foreignKeyValue = model[foreignKeyCamelized]()
|
|
43
|
+
const targetModel = targetModelsById[foreignKeyValue]
|
|
44
|
+
const modelRelationship = model.getRelationshipByName(this.relationship.getRelationshipName())
|
|
45
|
+
|
|
46
|
+
modelRelationship.setPreloaded(true)
|
|
47
|
+
modelRelationship.setLoaded(targetModel)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return targetModels
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as inflection from "inflection"
|
|
2
|
+
import restArgsError from "../../../utils/rest-args-error.mjs"
|
|
3
|
+
|
|
4
|
+
export default class VelociousDatabaseQueryPreloaderHasMany {
|
|
5
|
+
constructor({models, relationship, ...restArgs}) {
|
|
6
|
+
restArgsError(restArgs)
|
|
7
|
+
|
|
8
|
+
this.models = models
|
|
9
|
+
this.relationship = relationship
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async run() {
|
|
13
|
+
const modelIds = []
|
|
14
|
+
const modelsById = {}
|
|
15
|
+
const foreignKey = this.relationship.getForeignKey()
|
|
16
|
+
const foreignKeyCamelized = inflection.camelize(foreignKey, true)
|
|
17
|
+
const preloadCollections = {}
|
|
18
|
+
|
|
19
|
+
for (const model of this.models) {
|
|
20
|
+
preloadCollections[model.id()] = []
|
|
21
|
+
modelIds.push(model.id())
|
|
22
|
+
|
|
23
|
+
if (!(model.id in modelsById)) modelsById[model.id()] = []
|
|
24
|
+
|
|
25
|
+
modelsById[model.id()].push(model)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const whereArgs = {}
|
|
29
|
+
|
|
30
|
+
whereArgs[foreignKey] = modelIds
|
|
31
|
+
|
|
32
|
+
// Load target models to be preloaded on the given models
|
|
33
|
+
const targetModels = await this.relationship.getTargetModelClass().where(whereArgs).toArray()
|
|
34
|
+
|
|
35
|
+
for (const targetModel of targetModels) {
|
|
36
|
+
const foreignKeyValue = targetModel[foreignKeyCamelized]()
|
|
37
|
+
|
|
38
|
+
preloadCollections[foreignKeyValue].push(targetModel)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Set the target preloaded models on the given models
|
|
42
|
+
for (const modelId in preloadCollections) {
|
|
43
|
+
const preloadedCollection = preloadCollections[modelId]
|
|
44
|
+
|
|
45
|
+
for (const model of modelsById[modelId]) {
|
|
46
|
+
const modelRelationship = model.getRelationshipByName(this.relationship.getRelationshipName())
|
|
47
|
+
|
|
48
|
+
modelRelationship.setPreloaded(true)
|
|
49
|
+
modelRelationship.addToLoaded(preloadedCollection)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return targetModels
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import BelongsToPreloader from "./preloader/belongs-to.mjs"
|
|
2
|
+
import HasManyPreloader from "./preloader/has-many.mjs"
|
|
3
|
+
import restArgsError from "../../utils/rest-args-error.mjs"
|
|
4
|
+
|
|
5
|
+
export default class VelociousDatabaseQueryPreloader {
|
|
6
|
+
constructor({modelClass, models, preload, ...restArgs}) {
|
|
7
|
+
restArgsError(restArgs)
|
|
8
|
+
|
|
9
|
+
this.modelClass = modelClass
|
|
10
|
+
this.models = models
|
|
11
|
+
this.preload = preload
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async run() {
|
|
15
|
+
for (const preloadRelationshipName in this.preload) {
|
|
16
|
+
const relationship = this.modelClass.getRelationshipByName(preloadRelationshipName)
|
|
17
|
+
let targetModels
|
|
18
|
+
|
|
19
|
+
if (relationship.getType() == "belongsTo") {
|
|
20
|
+
const hasManyPreloader = new BelongsToPreloader({models: this.models, relationship: relationship})
|
|
21
|
+
|
|
22
|
+
targetModels = await hasManyPreloader.run()
|
|
23
|
+
} else if (relationship.getType() == "hasMany") {
|
|
24
|
+
const hasManyPreloader = new HasManyPreloader({models: this.models, relationship: relationship})
|
|
25
|
+
|
|
26
|
+
targetModels = await hasManyPreloader.run()
|
|
27
|
+
} else {
|
|
28
|
+
throw new Error(`Unknown relationship type: ${relationship.getType()}`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle any further preloads in the tree
|
|
32
|
+
const newPreload = this.preload[preloadRelationshipName]
|
|
33
|
+
|
|
34
|
+
if (typeof newPreload == "object" && targetModels.length > 0) {
|
|
35
|
+
const preloader = new VelociousDatabaseQueryPreloader({modelClass: relationship.getTargetModelClass(), models: targetModels, preload: newPreload})
|
|
36
|
+
|
|
37
|
+
await preloader.run()
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import WhereBase from "./where-base.mjs"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseQueryWhereHash extends WhereBase {
|
|
4
|
+
constructor(query, hash) {
|
|
5
|
+
super()
|
|
6
|
+
this.hash = hash
|
|
7
|
+
this.query = query
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
toSql() {
|
|
11
|
+
const options = this.getOptions()
|
|
12
|
+
let sql = "("
|
|
13
|
+
let index = 0
|
|
14
|
+
|
|
15
|
+
for (const whereKey in this.hash) {
|
|
16
|
+
const whereValue = this.hash[whereKey]
|
|
17
|
+
|
|
18
|
+
if (index > 0) sql += " AND "
|
|
19
|
+
|
|
20
|
+
sql += `${options.quoteColumnName(whereKey)}`
|
|
21
|
+
|
|
22
|
+
if (Array.isArray(whereValue)) {
|
|
23
|
+
sql += ` IN (${whereValue.map((value) => options.quote(value)).join(", ")})`
|
|
24
|
+
} else {
|
|
25
|
+
sql += ` = ${options.quote(whereValue)}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
index++
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
sql += ")"
|
|
32
|
+
|
|
33
|
+
return sql
|
|
34
|
+
}
|
|
35
|
+
}
|