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
|
@@ -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)
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
import FromParser from "./from-parser.mjs"
|
|
3
|
+
import GroupParser from "./group-parser.mjs"
|
|
4
|
+
import JoinsParser from "./joins-parser.mjs"
|
|
5
|
+
import LimitParser from "./limit-parser.mjs"
|
|
6
|
+
import OrderParser from "./order-parser.mjs"
|
|
7
|
+
import SelectParser from "./select-parser.mjs"
|
|
8
|
+
import WhereParser from "./where-parser.mjs"
|
|
9
|
+
|
|
10
|
+
export default class VelociousDatabaseBaseQueryParser {
|
|
11
|
+
constructor({pretty, query}) {
|
|
12
|
+
if (!query) throw new Error("No query given")
|
|
13
|
+
|
|
14
|
+
this.pretty = pretty
|
|
15
|
+
this.query = query
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
toSql() {
|
|
19
|
+
const {pretty, query} = digs(this, "pretty", "query")
|
|
20
|
+
|
|
21
|
+
let sql = ""
|
|
22
|
+
|
|
23
|
+
sql += new SelectParser({pretty, query}).toSql()
|
|
24
|
+
sql += new FromParser({pretty, query}).toSql()
|
|
25
|
+
sql += new JoinsParser({pretty, query}).toSql()
|
|
26
|
+
sql += new WhereParser({pretty, query}).toSql()
|
|
27
|
+
sql += new GroupParser({pretty, query}).toSql()
|
|
28
|
+
sql += new OrderParser({pretty, query}).toSql()
|
|
29
|
+
sql += new LimitParser({pretty, query}).toSql()
|
|
30
|
+
|
|
31
|
+
return sql
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseQueryParserFromParser {
|
|
4
|
+
constructor({pretty, query}) {
|
|
5
|
+
this.pretty = pretty
|
|
6
|
+
this.query = query
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
toSql() {
|
|
10
|
+
const {pretty, query} = digs(this, "pretty", "query")
|
|
11
|
+
|
|
12
|
+
if (query._groups.length == 0) {
|
|
13
|
+
return ""
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let sql = " GROUP BY"
|
|
17
|
+
|
|
18
|
+
for (const groupKey in query._groups) {
|
|
19
|
+
const group = query._groups[groupKey]
|
|
20
|
+
|
|
21
|
+
if (groupKey > 0) {
|
|
22
|
+
sql += ","
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (pretty) {
|
|
26
|
+
sql += "\n "
|
|
27
|
+
} else {
|
|
28
|
+
sql += " "
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (typeof group == "string") {
|
|
32
|
+
sql += group
|
|
33
|
+
} else {
|
|
34
|
+
sql += group.toSql()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return sql
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,28 +1,69 @@
|
|
|
1
1
|
import {digs} from "diggerize"
|
|
2
|
+
import JoinPlain from "../query/join-plain.mjs"
|
|
2
3
|
|
|
3
4
|
export default class VelocuiousDatabaseQueryParserJoinsParser {
|
|
4
5
|
constructor({pretty, query}) {
|
|
5
6
|
this.pretty = pretty
|
|
6
7
|
this.query = query
|
|
8
|
+
this.conn = this.query.driver
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
toSql() {
|
|
10
12
|
const {pretty, query} = digs(this, "pretty", "query")
|
|
11
|
-
|
|
12
13
|
let sql = ""
|
|
13
14
|
|
|
14
15
|
for (const joinKey in query._joins) {
|
|
15
16
|
const join = query._joins[joinKey]
|
|
16
17
|
|
|
17
|
-
if (
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
if (join instanceof JoinPlain) {
|
|
19
|
+
if (joinKey == 0) {
|
|
20
|
+
if (pretty) {
|
|
21
|
+
sql += "\n\n"
|
|
22
|
+
} else {
|
|
23
|
+
sql += " "
|
|
24
|
+
}
|
|
22
25
|
}
|
|
26
|
+
|
|
27
|
+
sql += join.toSql()
|
|
28
|
+
} else if (typeof join == "object") {
|
|
29
|
+
sql = this.joinObject({join, modelClass: query.modelClass, sql})
|
|
30
|
+
} else {
|
|
31
|
+
throw new Error(`Unknown join object: ${join.constructor.name}`)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return sql
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
joinObject({join, modelClass, sql}) {
|
|
39
|
+
const {conn, pretty} = this
|
|
40
|
+
|
|
41
|
+
for (const joinKey in join) {
|
|
42
|
+
const joinValue = join[joinKey]
|
|
43
|
+
const relationship = modelClass.getRelationshipByName(joinKey)
|
|
44
|
+
const targetModelClass = relationship.getTargetModelClass()
|
|
45
|
+
|
|
46
|
+
if (pretty) {
|
|
47
|
+
sql += "\n\n"
|
|
48
|
+
} else {
|
|
49
|
+
sql += " "
|
|
23
50
|
}
|
|
24
51
|
|
|
25
|
-
sql +=
|
|
52
|
+
sql += `LEFT JOIN ${conn.quoteTable(targetModelClass.tableName())} ON `
|
|
53
|
+
|
|
54
|
+
if (relationship.getType() == "belongsTo") {
|
|
55
|
+
sql += `${conn.quoteTable(targetModelClass.tableName())}.${conn.quoteColumn(relationship.getPrimaryKey())} = `
|
|
56
|
+
sql += `${conn.quoteTable(modelClass.tableName())}.${conn.quoteColumn(relationship.getForeignKey())}`
|
|
57
|
+
} else if (relationship.getType() == "hasMany" || relationship.getType() == "hasOne") {
|
|
58
|
+
sql += `${conn.quoteTable(targetModelClass.tableName())}.${conn.quoteColumn(relationship.getForeignKey())} = `
|
|
59
|
+
sql += `${conn.quoteTable(modelClass.tableName())}.${conn.quoteColumn(relationship.getPrimaryKey())}`
|
|
60
|
+
} else {
|
|
61
|
+
throw new Error(`Unknown relationship type: ${relationship.getType()}`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (typeof joinValue == "object") {
|
|
65
|
+
sql = this.joinObject({join: joinValue, modelClass: targetModelClass, sql})
|
|
66
|
+
}
|
|
26
67
|
}
|
|
27
68
|
|
|
28
69
|
return sql
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelocuiousDatabaseQueryParserLimitParser {
|
|
4
|
+
constructor({pretty, query}) {
|
|
5
|
+
this.pretty = pretty
|
|
6
|
+
this.query = query
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
toSql() {
|
|
10
|
+
const {pretty, query} = digs(this, "pretty", "query")
|
|
11
|
+
let sql = ""
|
|
12
|
+
|
|
13
|
+
if (query._limits.length == 0) return sql
|
|
14
|
+
if (query._limits.length >= 2) throw new Error(`Multiple limits found: ${query._limits.join(", ")}`)
|
|
15
|
+
|
|
16
|
+
if (pretty) {
|
|
17
|
+
sql += "\n\n"
|
|
18
|
+
} else {
|
|
19
|
+
sql += " "
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
sql += "LIMIT"
|
|
23
|
+
|
|
24
|
+
for (const limitKey in query._limits) {
|
|
25
|
+
const limit = query._limits[limitKey]
|
|
26
|
+
|
|
27
|
+
if (limitKey > 0) sql += ","
|
|
28
|
+
|
|
29
|
+
if (pretty) {
|
|
30
|
+
sql += "\n "
|
|
31
|
+
} else {
|
|
32
|
+
sql += " "
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
sql += this.query.getOptions().quote(limit)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return sql
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -3,11 +3,12 @@ import {digg} from "diggerize"
|
|
|
3
3
|
export default class VelociousDatabaseQueryParserOptions {
|
|
4
4
|
constructor(options) {
|
|
5
5
|
this.columnQuote = digg(options, "columnQuote")
|
|
6
|
+
this.indexQuote = digg(options, "indexQuote")
|
|
6
7
|
this.driver = digg(options, "driver")
|
|
7
8
|
this.tableQuote = digg(options, "tableQuote")
|
|
8
9
|
this.stringQuote = digg(options, "stringQuote")
|
|
9
10
|
|
|
10
|
-
if (!this.driver) throw new Error("No driver given")
|
|
11
|
+
if (!this.driver) throw new Error("No driver given to parser options")
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
quoteColumnName(columnName) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelocuiousDatabaseQueryParserOrderParser {
|
|
4
|
+
constructor({pretty, query}) {
|
|
5
|
+
this.pretty = pretty
|
|
6
|
+
this.query = query
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
toSql() {
|
|
10
|
+
const {pretty, query} = digs(this, "pretty", "query")
|
|
11
|
+
let sql = ""
|
|
12
|
+
|
|
13
|
+
if (query._orders.length == 0) return sql
|
|
14
|
+
|
|
15
|
+
if (pretty) {
|
|
16
|
+
sql += "\n\n"
|
|
17
|
+
} else {
|
|
18
|
+
sql += " "
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
sql += "ORDER BY"
|
|
22
|
+
|
|
23
|
+
for (const orderKey in query._orders) {
|
|
24
|
+
const order = query._orders[orderKey]
|
|
25
|
+
|
|
26
|
+
if (orderKey > 0) sql += " ,"
|
|
27
|
+
|
|
28
|
+
if (pretty) {
|
|
29
|
+
sql += "\n "
|
|
30
|
+
} else {
|
|
31
|
+
sql += " "
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
sql += order.toSql()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return sql
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -35,7 +35,11 @@ export default class VelociousDatabaseQueryParserSelectParser {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
if (query._selects.length == 0) {
|
|
38
|
-
|
|
38
|
+
if (query.modelClass) {
|
|
39
|
+
sql += `${query.modelClass.connection().quoteTable(query.modelClass.tableName())}.*`
|
|
40
|
+
} else {
|
|
41
|
+
sql += "*"
|
|
42
|
+
}
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
return sql
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelocuiousDatabaseQueryParserWhereParser {
|
|
4
|
+
constructor({pretty, query}) {
|
|
5
|
+
this.pretty = pretty
|
|
6
|
+
this.query = query
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
toSql() {
|
|
10
|
+
const {pretty, query} = digs(this, "pretty", "query")
|
|
11
|
+
let sql = ""
|
|
12
|
+
|
|
13
|
+
if (query._wheres.length == 0) return sql
|
|
14
|
+
|
|
15
|
+
if (pretty) {
|
|
16
|
+
sql += "\n\n"
|
|
17
|
+
} else {
|
|
18
|
+
sql += " "
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
sql += "WHERE"
|
|
22
|
+
|
|
23
|
+
for (const whereKey in query._wheres) {
|
|
24
|
+
const where = query._wheres[whereKey]
|
|
25
|
+
|
|
26
|
+
if (whereKey > 0) sql += " &&"
|
|
27
|
+
|
|
28
|
+
if (pretty) {
|
|
29
|
+
sql += "\n "
|
|
30
|
+
} else {
|
|
31
|
+
sql += " "
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
sql += where.toSql()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return sql
|
|
38
|
+
}
|
|
39
|
+
}
|