velocious 1.0.97 → 1.0.99

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.
Files changed (85) hide show
  1. package/eslint.config.js +1 -0
  2. package/package.json +2 -1
  3. package/spec/database/connection/drivers/mysql/query-parser-spec.js +4 -4
  4. package/spec/http-server/post-spec.js +2 -0
  5. package/src/application.js +27 -9
  6. package/src/configuration-resolver.js +29 -10
  7. package/src/configuration-types.js +44 -0
  8. package/src/configuration.js +63 -33
  9. package/src/database/drivers/base-column.js +6 -1
  10. package/src/database/drivers/base-columns-index.js +11 -1
  11. package/src/database/drivers/base-foreign-key.js +45 -0
  12. package/src/database/drivers/base-table.js +24 -2
  13. package/src/database/drivers/base.js +211 -39
  14. package/src/database/drivers/mssql/index.js +1 -3
  15. package/src/database/drivers/sqlite/sql/alter-table.js +4 -2
  16. package/src/database/handler.js +5 -0
  17. package/src/database/migration/index.js +79 -20
  18. package/src/database/migrator/files-finder.js +21 -22
  19. package/src/database/migrator/types.js +29 -0
  20. package/src/database/migrator.js +98 -59
  21. package/src/database/pool/async-tracked-multi-connection.js +42 -7
  22. package/src/database/pool/base-methods-forward.js +37 -0
  23. package/src/database/pool/base.js +79 -46
  24. package/src/database/pool/single-multi-use.js +18 -3
  25. package/src/database/query/alter-table-base.js +4 -4
  26. package/src/database/query/base.js +9 -2
  27. package/src/database/query/create-database-base.js +8 -0
  28. package/src/database/query/create-index-base.js +20 -5
  29. package/src/database/query/create-table-base.js +28 -9
  30. package/src/database/query/from-base.js +17 -0
  31. package/src/database/query/from-plain.js +8 -3
  32. package/src/database/query/from-table.js +8 -3
  33. package/src/database/query/index.js +43 -32
  34. package/src/database/query/join-base.js +28 -1
  35. package/src/database/query/join-object.js +67 -0
  36. package/src/database/query/join-plain.js +6 -1
  37. package/src/database/query/order-base.js +18 -0
  38. package/src/database/query/order-plain.js +8 -2
  39. package/src/database/query/select-base.js +15 -0
  40. package/src/database/query/select-plain.js +6 -1
  41. package/src/database/query/select-table-and-column.js +8 -2
  42. package/src/database/query/where-base.js +23 -1
  43. package/src/database/query/where-hash.js +15 -0
  44. package/src/database/query/where-plain.js +6 -0
  45. package/src/database/query-parser/base-query-parser.js +8 -2
  46. package/src/database/query-parser/from-parser.js +2 -0
  47. package/src/database/query-parser/joins-parser.js +10 -45
  48. package/src/database/query-parser/select-parser.js +2 -0
  49. package/src/database/record/index.js +1 -1
  50. package/src/database/table-data/index.js +39 -121
  51. package/src/database/table-data/table-column.js +54 -25
  52. package/src/database/table-data/table-foreign-key.js +5 -3
  53. package/src/database/table-data/table-index.js +12 -6
  54. package/src/database/table-data/table-reference.js +2 -0
  55. package/src/database/use-database.js +4 -2
  56. package/src/environment-handlers/base.js +41 -8
  57. package/src/environment-handlers/node/cli/commands/destroy/migration.js +3 -0
  58. package/src/environment-handlers/node/cli/commands/generate/migration.js +3 -0
  59. package/src/environment-handlers/node/cli/commands/generate/model.js +3 -0
  60. package/src/environment-handlers/node/cli/commands/init.js +3 -0
  61. package/src/environment-handlers/node.js +59 -28
  62. package/src/http-client/header.js +6 -0
  63. package/src/http-client/request.js +31 -5
  64. package/src/http-client/response.js +31 -7
  65. package/src/http-server/client/index.js +24 -4
  66. package/src/http-server/client/request-buffer/form-data-part.js +11 -0
  67. package/src/http-server/client/request-buffer/header.js +6 -0
  68. package/src/http-server/client/request-buffer/index.js +91 -13
  69. package/src/http-server/client/request-parser.js +26 -0
  70. package/src/http-server/client/request-runner.js +15 -3
  71. package/src/http-server/client/request.js +17 -0
  72. package/src/http-server/client/response.js +41 -1
  73. package/src/http-server/index.js +32 -4
  74. package/src/http-server/server-client.js +33 -2
  75. package/src/http-server/worker-handler/index.js +42 -9
  76. package/src/http-server/worker-handler/worker-script.js +2 -0
  77. package/src/http-server/worker-handler/worker-thread.js +34 -6
  78. package/src/logger.js +21 -15
  79. package/src/routes/app-routes.js +1 -1
  80. package/src/testing/test-files-finder.js +8 -4
  81. package/src/testing/test-runner.js +76 -24
  82. package/src/utils/backtrace-cleaner.js +6 -4
  83. package/src/utils/ensure-error.js +13 -0
  84. package/src/utils/file-exists.js +3 -1
  85. package/src/utils/rest-args-error.js +2 -0
@@ -1,6 +1,13 @@
1
+ // @ts-check
2
+
1
3
  import restArgsError from "../../utils/rest-args-error.js"
2
4
 
3
5
  export default class VelociousDatabaseQueryBase {
6
+ /**
7
+ * @param {object} args
8
+ * @param {import("../drivers/base.js").default} args.driver
9
+ * @param {import("../query-parser/options.js").default} [args.options]
10
+ */
4
11
  constructor({driver, options, ...restArgs}) {
5
12
  restArgsError(restArgs)
6
13
 
@@ -33,7 +40,7 @@ export default class VelociousDatabaseQueryBase {
33
40
  * @interface
34
41
  * @returns {string[]}
35
42
  */
36
- toSql() {
37
- throw new Error("'toSql' wasn't implemented")
43
+ toSqls() {
44
+ throw new Error("'toSqls' wasn't implemented")
38
45
  }
39
46
  }
@@ -1,6 +1,14 @@
1
+ // @ts-check
2
+
1
3
  import QueryBase from "./base.js"
2
4
 
3
5
  export default class VelociousDatabaseQueryCreateDatabaseBase extends QueryBase {
6
+ /**
7
+ * @param {object} args
8
+ * @param {import("../drivers/base.js").default} args.driver
9
+ * @param {string} args.databaseName
10
+ * @param {boolean} [args.ifNotExists]
11
+ */
4
12
  constructor({driver, databaseName, ifNotExists}) {
5
13
  super({driver})
6
14
  this.databaseName = databaseName
@@ -1,6 +1,21 @@
1
+ // @ts-check
2
+
1
3
  import QueryBase from "./base.js"
2
4
 
5
+ /**
6
+ * @typedef {object} CreateIndexBaseArgsType
7
+ * @property {Array<string | import("./../table-data/table-column.js").default>} columns
8
+ * @property {import("../drivers/base.js").default} driver
9
+ * @property {boolean} [ifNotExists]
10
+ * @property {string} [name]
11
+ * @property {boolean} [unique]
12
+ * @property {string} tableName
13
+ */
14
+
3
15
  export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
16
+ /**
17
+ * @param {CreateIndexBaseArgsType} args
18
+ */
4
19
  constructor({columns, driver, ifNotExists, name, unique, tableName}) {
5
20
  super({driver})
6
21
  this.columns = columns
@@ -17,7 +32,7 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
17
32
  if (databaseType == "sqlite") indexName += `${this.tableName}_`
18
33
 
19
34
  for (const columnIndex in this.columns) {
20
- if (columnIndex > 0) indexName += "_and_"
35
+ if (typeof columnIndex == "number" && columnIndex > 0) indexName += "_and_"
21
36
 
22
37
  const column = this.columns[columnIndex]
23
38
  let columnName
@@ -35,9 +50,9 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
35
50
  }
36
51
 
37
52
  /**
38
- * @returns {string}
53
+ * @returns {string[]}
39
54
  */
40
- toSql() {
55
+ toSqls() {
41
56
  const databaseType = this.getDriver().getType()
42
57
  const indexName = this.name || this.generateIndexName()
43
58
  const options = this.getOptions()
@@ -69,7 +84,7 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
69
84
  sql += ` ON ${options.quoteTableName(tableName)} (`
70
85
 
71
86
  for (const columnIndex in this.columns) {
72
- if (columnIndex > 0) sql += ", "
87
+ if (typeof columnIndex == "number" && columnIndex > 0) sql += ", "
73
88
 
74
89
  const column = this.columns[columnIndex]
75
90
  let columnName
@@ -89,6 +104,6 @@ export default class VelociousDatabaseQueryCreateIndexBase extends QueryBase {
89
104
  sql += " END"
90
105
  }
91
106
 
92
- return sql
107
+ return [sql]
93
108
  }
94
109
  }
@@ -1,10 +1,19 @@
1
+ // @ts-check
2
+
1
3
  import CreateIndexBase from "./create-index-base.js"
2
- import {digs} from "diggerize"
3
4
  import QueryBase from "./base.js"
4
5
  import restArgsError from "../../utils/rest-args-error.js"
5
6
  import TableData from "../table-data/index.js"
7
+ import TableColumn from "../table-data/table-column.js"
6
8
 
7
9
  export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
10
+ /**
11
+ * @param {object} args
12
+ * @param {import("../drivers/base.js").default} args.driver
13
+ * @param {boolean} args.ifNotExists
14
+ * @param {boolean} args.indexInCreateTable
15
+ * @param {TableData} args.tableData
16
+ */
8
17
  constructor({driver, ifNotExists, indexInCreateTable = true, tableData}) {
9
18
  if (!(tableData instanceof TableData)) throw new Error("Invalid table data was given")
10
19
 
@@ -21,7 +30,7 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
21
30
  const databaseType = this.getDatabaseType()
22
31
  const driver = this.getDriver()
23
32
  const options = this.getOptions()
24
- const {tableData} = digs(this, "tableData")
33
+ const {tableData} = this
25
34
  const sqls = []
26
35
  const ifNotExists = this.ifNotExists || tableData.getIfNotExists()
27
36
  let sql = ""
@@ -65,7 +74,13 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
65
74
  index.getColumns().forEach((column, columnIndex) => {
66
75
  if (columnIndex > 0) sql += ", "
67
76
 
68
- sql += driver.quoteColumn(column.name)
77
+ if (column instanceof TableColumn) {
78
+ sql += driver.quoteColumn(column.getName())
79
+ } else if (typeof column == "string") {
80
+ sql += driver.quoteColumn(column)
81
+ } else {
82
+ throw new Error(`Unknown column type: ${typeof column}`)
83
+ }
69
84
  })
70
85
 
71
86
  sql += ")"
@@ -83,7 +98,7 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
83
98
 
84
99
  sql += ","
85
100
 
86
- const {unique, ...restIndexArgs} = column.getIndex()
101
+ const {unique, ...restIndexArgs} = column.getIndexArgs()
87
102
 
88
103
  restArgsError(restIndexArgs)
89
104
 
@@ -113,16 +128,18 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
113
128
  tableName: tableData.getName(),
114
129
  unique: index.getUnique()
115
130
  }
116
- const sql = new CreateIndexBase(createIndexArgs).toSql()
131
+ const createIndexSQLs = new CreateIndexBase(createIndexArgs).toSqls()
117
132
 
118
- sqls.push(sql)
133
+ for (const createIndexSQL of createIndexSQLs) {
134
+ sqls.push(createIndexSQL)
135
+ }
119
136
  }
120
137
 
121
138
  // Create indexes for all columns with the index argument
122
139
  for (const column of tableData.getColumns()) {
123
140
  if (!column.getIndex()) continue
124
141
 
125
- const {unique, ...restIndexArgs} = column.getIndex()
142
+ const {unique, ...restIndexArgs} = column.getIndexArgs()
126
143
 
127
144
  restArgsError(restIndexArgs)
128
145
 
@@ -139,9 +156,11 @@ export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
139
156
  tableName: tableData.getName(),
140
157
  unique
141
158
  }
142
- const sql = new CreateIndexBase(createIndexArgs).toSql()
159
+ const createIndexSQLs = new CreateIndexBase(createIndexArgs).toSqls()
143
160
 
144
- sqls.push(sql)
161
+ for (const createIndexSQL of createIndexSQLs) {
162
+ sqls.push(createIndexSQL)
163
+ }
145
164
  }
146
165
  }
147
166
 
@@ -1,8 +1,25 @@
1
+ // @ts-check
2
+
3
+ import Query from "./index.js"
4
+
1
5
  export default class VelociousDatabaseQueryFromBase {
6
+ /** @type {Query | null} */
7
+ query = null
8
+
9
+ /**
10
+ * @param {import("./index.js").default} query
11
+ * @returns {void}
12
+ */
13
+ setQuery(query) {
14
+ this.query = query
15
+ }
16
+
2
17
  /**
3
18
  * @returns {import("../query-parser/options.js").default}
4
19
  */
5
20
  getOptions() {
21
+ if (!this.query) throw new Error("'query' hasn't been set")
22
+
6
23
  return this.query.getOptions()
7
24
  }
8
25
 
@@ -1,10 +1,15 @@
1
+ // @ts-check
2
+
1
3
  import FromBase from "./from-base.js"
2
4
 
3
5
  export default class VelociousDatabaseQueryFromPlain extends FromBase {
4
- constructor({driver, plain}) {
5
- super({driver})
6
+ /**
7
+ * @param {string} plain
8
+ */
9
+ constructor(plain) {
10
+ super()
6
11
  this.plain = plain
7
12
  }
8
13
 
9
- toSql() { return this.plain }
14
+ toSql() { return [this.plain] }
10
15
  }
@@ -1,12 +1,17 @@
1
+ // @ts-check
2
+
1
3
  import FromBase from "./from-base.js"
2
4
 
3
5
  export default class VelociousDatabaseQueryFromTable extends FromBase {
4
- constructor({driver, tableName}) {
5
- super({driver})
6
+ /**
7
+ * @param {string} tableName
8
+ */
9
+ constructor(tableName) {
10
+ super()
6
11
  this.tableName = tableName
7
12
  }
8
13
 
9
14
  toSql() {
10
- return this.getOptions().quoteTableName(this.tableName)
15
+ return [this.getOptions().quoteTableName(this.tableName)]
11
16
  }
12
17
  }
@@ -1,18 +1,23 @@
1
+ // @ts-check
2
+
1
3
  import FromPlain from "./from-plain.js"
2
4
  import {incorporate} from "incorporator"
3
5
  import * as inflection from "inflection"
6
+ import {isPlainObject} from "is-plain-object"
7
+ import JoinObject from "./join-object.js"
4
8
  import JoinPlain from "./join-plain.js"
5
9
  import {Logger} from "../../logger.js"
6
10
  import OrderPlain from "./order-plain.js"
7
11
  import Preloader from "./preloader.js"
8
12
  import RecordNotFoundError from "../record/record-not-found-error.js"
13
+ import SelectBase from "./select-base.js"
9
14
  import SelectPlain from "./select-plain.js"
10
15
  import WhereHash from "./where-hash.js"
11
16
  import WherePlain from "./where-plain.js"
12
17
  import restArgsError from "../../utils/rest-args-error.js"
13
18
 
14
19
  /**
15
- * @typedef {Record<string, boolean|NestedPreloadRecord>} NestedPreloadRecord
20
+ * @typedef {{[key: string]: boolean | NestedPreloadRecord }} NestedPreloadRecord
16
21
  */
17
22
 
18
23
  /**
@@ -27,11 +32,11 @@ export default class VelociousDatabaseQuery {
27
32
  * @param {Array<import("./join-base.js").default>} [args.joins]
28
33
  * @param {import("../handler.js").default} args.handler
29
34
  * @param {number | null} [args.limit]
30
- * @param {typeof import("../record/index.js").default} args.modelClass
35
+ * @param {typeof import("../record/index.js").default} [args.modelClass]
31
36
  * @param {number | null} [args.offset]
32
37
  * @param {Array<import("./order-base.js").default>} [args.orders]
33
38
  * @param {number | null} [args.page]
34
- * @param {number} args.perPage
39
+ * @param {number} [args.perPage]
35
40
  * @param {NestedPreloadRecord} [args.preload]
36
41
  * @param {Array<import("./select-base.js").default>} [args.selects]
37
42
  * @param {Array<import("./where-base.js").default>} [args.wheres]
@@ -73,6 +78,8 @@ export default class VelociousDatabaseQuery {
73
78
  this._perPage = perPage
74
79
  this._preload = preload
75
80
  this._selects = selects
81
+
82
+ /** @type {import("./where-base.js").default[]} */
76
83
  this._wheres = wheres
77
84
  }
78
85
 
@@ -118,7 +125,7 @@ export default class VelociousDatabaseQuery {
118
125
  countQuery._selects = []
119
126
  countQuery.select(sql)
120
127
 
121
- const results = await countQuery._executeQuery()
128
+ const results = /** @type {{ count: number }[]} */ (await countQuery._executeQuery())
122
129
 
123
130
 
124
131
  // The query isn't grouped and a single result has been given
@@ -142,8 +149,7 @@ export default class VelociousDatabaseQuery {
142
149
  }
143
150
 
144
151
  /**
145
- * @template {import("./from-base.js").default} T
146
- * @returns {T[]}
152
+ * @returns {import("./from-base.js").default[]}
147
153
  */
148
154
  getFroms() {
149
155
  return this._froms
@@ -182,6 +188,7 @@ export default class VelociousDatabaseQuery {
182
188
  * @returns {Promise<import("../record/index.js").default>}
183
189
  */
184
190
  async find(recordId) {
191
+ /** @type {{[key: string]: number | string}} */
185
192
  const conditions = {}
186
193
 
187
194
  conditions[this.modelClass.primaryKey()] = recordId
@@ -197,10 +204,11 @@ export default class VelociousDatabaseQuery {
197
204
  }
198
205
 
199
206
  /**
200
- * @param {object} conditions
207
+ * @param {{[key: string]: any}} conditions
201
208
  * @returns {Promise<import("../record/index.js").default|null>}
202
209
  */
203
210
  async findBy(conditions) {
211
+ /** @type {{[key: string]: number | string}} */
204
212
  const newConditions = {}
205
213
 
206
214
  for (const key in conditions) {
@@ -213,11 +221,12 @@ export default class VelociousDatabaseQuery {
213
221
  }
214
222
 
215
223
  /**
216
- * @param {...Parameters<this["findOrInitializeBy"]>} args
224
+ * @param {{[key: string]: any}} conditions
225
+ * @param {function() : void} callback
217
226
  * @returns {Promise<import("../record/index.js").default>}
218
227
  */
219
- async findOrCreateBy(...args) {
220
- const record = await this.findOrInitializeBy(...args)
228
+ async findOrCreateBy(conditions, callback) {
229
+ const record = await this.findOrInitializeBy(conditions, callback)
221
230
 
222
231
  if (record.isNewRecord()) {
223
232
  await record.save()
@@ -227,10 +236,11 @@ export default class VelociousDatabaseQuery {
227
236
  }
228
237
 
229
238
  /**
230
- * @param {object} conditions
239
+ * @param {{[key: string]: any}} conditions
231
240
  * @returns {Promise<import("../record/index.js").default>}
232
241
  */
233
242
  async findByOrFail(conditions) {
243
+ /** @type {{[key: string]: number | string}} */
234
244
  const newConditions = {}
235
245
 
236
246
  for (const key in conditions) {
@@ -250,7 +260,7 @@ export default class VelociousDatabaseQuery {
250
260
 
251
261
  /**
252
262
  * @param {object} conditions
253
- * @param {function() : void} callback
263
+ * @param {function(import("../record/index.js").default) : void} callback
254
264
  * @returns {Promise<import("../record/index.js").default>}
255
265
  */
256
266
  async findOrInitializeBy(conditions, callback) {
@@ -282,9 +292,7 @@ export default class VelociousDatabaseQuery {
282
292
  * @returns {this}
283
293
  */
284
294
  from(from) {
285
- if (typeof from == "string") from = new FromPlain({plain: from, query: this})
286
-
287
- from.query = this
295
+ if (typeof from == "string") from = new FromPlain(from)
288
296
 
289
297
  this._froms.push(from)
290
298
  return this
@@ -300,19 +308,18 @@ export default class VelociousDatabaseQuery {
300
308
  }
301
309
 
302
310
  /**
303
- * @param {string|JoinPlain} join
311
+ * @param {string|{[key: string]: any}} join
304
312
  * @returns {this}
305
313
  */
306
314
  joins(join) {
307
315
  if (typeof join == "string") {
308
- join = new JoinPlain({plain: join, query: this})
309
- } else if (typeof join == "object") {
310
- // Do nothing
316
+ this._joins.push(new JoinPlain(join))
317
+ } else if (isPlainObject(join)) {
318
+ this._joins.push(new JoinObject(join))
311
319
  } else {
312
320
  throw new Error(`Unknown type of join: ${typeof join}`)
313
321
  }
314
322
 
315
- this._joins.push(join)
316
323
  return this
317
324
  }
318
325
 
@@ -350,11 +357,14 @@ export default class VelociousDatabaseQuery {
350
357
  * @returns {this}
351
358
  */
352
359
  order(order) {
353
- if (typeof order == "number" || typeof order == "string") order = new OrderPlain({plain: order, query: this})
354
-
355
- order.query = this
360
+ if (typeof order == "string") {
361
+ this._orders.push(new OrderPlain(this, order))
362
+ } else if (typeof order == "number") {
363
+ this._orders.push(new OrderPlain(this, `${order}`))
364
+ } else {
365
+ throw new Error(`Unknown order type: ${typeof order}`)
366
+ }
356
367
 
357
- this._orders.push(order)
358
368
  return this
359
369
  }
360
370
 
@@ -425,11 +435,14 @@ export default class VelociousDatabaseQuery {
425
435
  return this
426
436
  }
427
437
 
428
- if (typeof select == "string") select = new SelectPlain({plain: select})
429
-
430
- select.query = this
438
+ if (typeof select == "string") {
439
+ this._selects.push(new SelectPlain(select))
440
+ } else if (select instanceof SelectBase) {
441
+ this._selects.push(select)
442
+ } else {
443
+ throw new Error(`Invalid select type: ${typeof select}`)
444
+ }
431
445
 
432
- this._selects.push(select)
433
446
  return this
434
447
  }
435
448
 
@@ -492,15 +505,13 @@ export default class VelociousDatabaseQuery {
492
505
  */
493
506
  where(where) {
494
507
  if (typeof where == "string") {
495
- where = new WherePlain(this, where)
508
+ this._wheres.push(new WherePlain(this, where))
496
509
  } else if (typeof where == "object" && (where.constructor.name == "object" || where.constructor.name == "Object")) {
497
- where = new WhereHash(this, where)
510
+ this._wheres.push(new WhereHash(this, where))
498
511
  } else {
499
512
  throw new Error(`Invalid type of where: ${typeof where} (${where.constructor.name})`)
500
513
  }
501
514
 
502
- this._wheres.push(where)
503
-
504
515
  return this
505
516
  }
506
517
  }
@@ -1,9 +1,36 @@
1
+ // @ts-check
2
+
1
3
  export default class VelociousDatabaseQueryJoinBase {
4
+ pretty = false
5
+
2
6
  /**
3
7
  * @returns {import("../query-parser/options.js").default}
4
8
  */
5
9
  getOptions() {
6
- return this.query.driver.options()
10
+ return this.getQuery().driver.options()
11
+ }
12
+
13
+ /**
14
+ * @returns {import("./index.js").default}
15
+ */
16
+ getQuery() {
17
+ if (!this.query) throw new Error("'query' hasn't been set")
18
+
19
+ return this.query
20
+ }
21
+
22
+ /**
23
+ * @param {boolean} value
24
+ */
25
+ setPretty(value) {
26
+ this.pretty = value
27
+ }
28
+
29
+ /**
30
+ * @param {import("./index.js").default} query
31
+ */
32
+ setQuery(query) {
33
+ this.query = query
7
34
  }
8
35
 
9
36
  toSql() {
@@ -0,0 +1,67 @@
1
+ // @ts-check
2
+
3
+ import JoinBase from "./join-base.js"
4
+
5
+ /**
6
+ * @typedef {{[key: string]: boolean | JoinObject}} JoinObject
7
+ */
8
+
9
+ export default class VelociousDatabaseQueryJoinObject extends JoinBase {
10
+ /**
11
+ * @param {JoinObject} object
12
+ */
13
+ constructor(object) {
14
+ super()
15
+ this.object = object
16
+ }
17
+
18
+ toSql() {
19
+ const modelClass = this.getQuery().modelClass
20
+
21
+ return this.joinObject(this.object, modelClass, "", 0)
22
+ }
23
+
24
+ /**
25
+ * @param {JoinObject} join
26
+ * @param {typeof import("../record/index.js").default} modelClass
27
+ * @param {string} sql
28
+ * @param {number} joinsCount
29
+ * @returns {string}
30
+ */
31
+ joinObject(join, modelClass, sql, joinsCount) {
32
+ const pretty = this.pretty
33
+ const conn = this.getQuery().driver
34
+
35
+ for (const joinKey in join) {
36
+ const joinValue = join[joinKey]
37
+ const relationship = modelClass.getRelationshipByName(joinKey)
38
+ const targetModelClass = relationship.getTargetModelClass()
39
+
40
+ if (joinsCount > 0) {
41
+ if (pretty) {
42
+ sql += "\n\n"
43
+ } else {
44
+ sql += " "
45
+ }
46
+ }
47
+
48
+ sql += `LEFT JOIN ${conn.quoteTable(targetModelClass.tableName())} ON `
49
+
50
+ if (relationship.getType() == "belongsTo") {
51
+ sql += `${conn.quoteTable(targetModelClass.tableName())}.${conn.quoteColumn(relationship.getPrimaryKey())} = `
52
+ sql += `${conn.quoteTable(modelClass.tableName())}.${conn.quoteColumn(relationship.getForeignKey())}`
53
+ } else if (relationship.getType() == "hasMany" || relationship.getType() == "hasOne") {
54
+ sql += `${conn.quoteTable(targetModelClass.tableName())}.${conn.quoteColumn(relationship.getForeignKey())} = `
55
+ sql += `${conn.quoteTable(modelClass.tableName())}.${conn.quoteColumn(relationship.getPrimaryKey())}`
56
+ } else {
57
+ throw new Error(`Unknown relationship type: ${relationship.getType()}`)
58
+ }
59
+
60
+ if (typeof joinValue == "object") {
61
+ sql = this.joinObject(joinValue, targetModelClass, sql, joinsCount + 1)
62
+ }
63
+ }
64
+
65
+ return sql
66
+ }
67
+ }
@@ -1,7 +1,12 @@
1
+ // @ts-check
2
+
1
3
  import JoinBase from "./join-base.js"
2
4
 
3
5
  export default class VelociousDatabaseQueryJoinPlain extends JoinBase {
4
- constructor({plain}) {
6
+ /**
7
+ * @param {string} plain
8
+ */
9
+ constructor(plain) {
5
10
  super()
6
11
  this.plain = plain
7
12
  }
@@ -1,4 +1,13 @@
1
+ // @ts-check
2
+
1
3
  export default class VelociousDatabaseQueryOrderBase {
4
+ /**
5
+ * @param {import("./index.js").default} query
6
+ */
7
+ constructor(query) {
8
+ this.query = query
9
+ }
10
+
2
11
  /**
3
12
  * @returns {import("../query-parser/options.js").default}
4
13
  */
@@ -6,6 +15,15 @@ export default class VelociousDatabaseQueryOrderBase {
6
15
  return this.query.driver.options()
7
16
  }
8
17
 
18
+ /**
19
+ * @interface
20
+ * @param {boolean} _reverseOrder
21
+ * @returns {void}
22
+ */
23
+ setReverseOrder(_reverseOrder) { // eslint-disable-line no-unused-vars
24
+ throw new Error("setReverseOrder not implemented")
25
+ }
26
+
9
27
  toSql() {
10
28
  throw new Error("'toSql' wasn't implemented")
11
29
  }
@@ -1,8 +1,14 @@
1
+ // @ts-check
2
+
1
3
  import OrderBase from "./order-base.js"
2
4
 
3
5
  export default class VelociousDatabaseQueryOrderPlain extends OrderBase {
4
- constructor({plain}) {
5
- super()
6
+ /**
7
+ * @param {import("./index.js").default} query
8
+ * @param {string} plain
9
+ */
10
+ constructor(query, plain) {
11
+ super(query)
6
12
  this.plain = plain
7
13
  this.reverseOrder = false
8
14
  }
@@ -1,11 +1,26 @@
1
+ // @ts-check
2
+
1
3
  export default class VelociousDatabaseQuerySelectBase {
2
4
  /**
3
5
  * @returns {import("../query-parser/options.js").default}
4
6
  */
5
7
  getOptions() {
8
+ if (!this.query) throw new Error("'query' hasn't been set")
9
+
6
10
  return this.query.driver.options()
7
11
  }
8
12
 
13
+ /**
14
+ * @param {import("./index.js").default} query
15
+ */
16
+ setQuery(query) {
17
+ this.query = query
18
+ }
19
+
20
+ /**
21
+ * @interface
22
+ * @returns {string}
23
+ */
9
24
  toSql() {
10
25
  throw new Error("'toSql' wasn't implemented")
11
26
  }
@@ -1,7 +1,12 @@
1
+ // @ts-check
2
+
1
3
  import SelectBase from "./select-base.js"
2
4
 
3
5
  export default class VelociousDatabaseQuerySelectPlain extends SelectBase {
4
- constructor({plain}) {
6
+ /**
7
+ * @param {string} plain
8
+ */
9
+ constructor(plain) {
5
10
  super()
6
11
  this.plain = plain
7
12
  }