velocious 1.0.103 → 1.0.105
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 +1 -1
- package/spec/database/record/create-spec.js +7 -0
- package/spec/dummy/dummy-directory.js +2 -0
- package/spec/dummy/index.js +5 -1
- package/spec/dummy/src/model-bases/project.js +18 -0
- package/src/application.js +1 -0
- package/src/configuration-types.js +6 -0
- package/src/controller.js +44 -24
- package/src/database/drivers/base-foreign-key.js +1 -1
- package/src/database/drivers/base.js +2 -2
- package/src/database/drivers/mssql/column.js +6 -0
- package/src/database/drivers/mssql/columns-index.js +2 -5
- package/src/database/drivers/mssql/foreign-key.js +2 -0
- package/src/database/drivers/mssql/options.js +25 -0
- package/src/database/drivers/mssql/query-parser.js +2 -0
- package/src/database/drivers/mysql/options.js +9 -0
- package/src/database/drivers/mysql/sql/alter-table.js +2 -0
- package/src/database/drivers/mysql/sql/create-database.js +2 -0
- package/src/database/drivers/mysql/sql/create-index.js +2 -0
- package/src/database/drivers/mysql/sql/create-table.js +2 -0
- package/src/database/drivers/mysql/sql/delete.js +2 -0
- package/src/database/drivers/mysql/sql/drop-table.js +2 -0
- package/src/database/drivers/mysql/sql/insert.js +2 -0
- package/src/database/drivers/mysql/sql/update.js +2 -0
- package/src/database/drivers/pgsql/column.js +6 -0
- package/src/database/drivers/pgsql/columns-index.js +2 -0
- package/src/database/drivers/pgsql/foreign-key.js +2 -0
- package/src/database/drivers/pgsql/options.js +9 -0
- package/src/database/drivers/pgsql/query-parser.js +2 -0
- package/src/database/drivers/pgsql/sql/alter-table.js +2 -0
- package/src/database/drivers/pgsql/sql/create-database.js +5 -4
- package/src/database/drivers/pgsql/sql/create-index.js +2 -0
- package/src/database/drivers/pgsql/sql/create-table.js +2 -0
- package/src/database/drivers/pgsql/sql/delete.js +2 -0
- package/src/database/drivers/pgsql/sql/drop-table.js +2 -0
- package/src/database/drivers/pgsql/sql/insert.js +2 -0
- package/src/database/drivers/pgsql/sql/update.js +2 -0
- package/src/database/drivers/pgsql/table.js +6 -0
- package/src/database/drivers/sqlite/columns-index.js +2 -6
- package/src/database/drivers/sqlite/connection-remote.js +7 -0
- package/src/database/drivers/sqlite/connection-sql-js.js +12 -2
- package/src/database/drivers/sqlite/foreign-key.js +7 -0
- package/src/database/drivers/sqlite/index.js +7 -1
- package/src/database/drivers/sqlite/index.web.js +12 -3
- package/src/database/drivers/sqlite/options.js +9 -0
- package/src/database/drivers/sqlite/query-parser.js +2 -0
- package/src/database/drivers/sqlite/query.js +19 -6
- package/src/database/drivers/sqlite/query.web.js +13 -1
- package/src/database/initializer-from-require-context.js +11 -1
- package/src/database/migrator/types.js +2 -0
- package/src/database/pool/base-methods-forward.js +7 -0
- package/src/database/query/delete-base.js +8 -0
- package/src/database/query/preloader/belongs-to.js +16 -1
- package/src/database/query/preloader/has-many.js +19 -1
- package/src/database/query/preloader/has-one.js +20 -2
- package/src/database/query/preloader.js +19 -4
- package/src/database/query/update-base.js +9 -0
- package/src/database/query-parser/limit-parser.js +7 -2
- package/src/database/query-parser/options.js +47 -6
- package/src/database/query-parser/order-parser.js +11 -6
- package/src/database/query-parser/select-parser.js +8 -5
- package/src/database/query-parser/where-parser.js +11 -5
- package/src/database/record/index.js +28 -24
- package/src/database/record/instance-relationships/base.js +10 -1
- package/src/database/record/record-not-found-error.js +2 -0
- package/src/database/record/user-module.js +13 -0
- package/src/database/record/validators/uniqueness.js +13 -2
- package/src/environment-handlers/node/cli/commands/generate/base-models.js +19 -0
- package/src/error-logger.js +17 -3
- package/src/http-client/index.js +34 -2
- package/src/http-client/request.js +1 -1
- package/src/http-server/client/params-to-object.js +28 -0
- package/src/initializer.js +2 -0
- package/src/routes/app-routes.js +3 -1
- package/src/routes/base-route.js +67 -58
- package/src/routes/basic-route.js +76 -0
- package/src/routes/get-route.js +21 -5
- package/src/routes/index.js +10 -0
- package/src/routes/namespace-route.js +21 -5
- package/src/routes/post-route.js +20 -5
- package/src/routes/resolver.js +15 -2
- package/src/routes/resource-route.js +21 -5
- package/src/routes/root-route.js +3 -3
- package/src/testing/request-client.js +19 -14
- package/src/testing/test-runner.js +16 -10
- package/src/testing/test.js +70 -22
- package/src/utils/with-tracked-stack-async-hooks.js +22 -4
- package/src/utils/with-tracked-stack.js +9 -0
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import debounce from "debounce"
|
|
2
4
|
import query from "./query"
|
|
3
5
|
|
|
4
6
|
export default class VelociousDatabaseDriversSqliteConnectionSqlJs {
|
|
7
|
+
/**
|
|
8
|
+
* @param {import("../base.js").default} driver
|
|
9
|
+
* @param {import("sql.js").Database} connection
|
|
10
|
+
*/
|
|
5
11
|
constructor(driver, connection) {
|
|
6
12
|
this.connection = connection
|
|
7
13
|
this.driver = driver
|
|
@@ -9,12 +15,15 @@ export default class VelociousDatabaseDriversSqliteConnectionSqlJs {
|
|
|
9
15
|
|
|
10
16
|
async close() {
|
|
11
17
|
await this.saveDatabase()
|
|
12
|
-
await this.connection.
|
|
13
|
-
this.connection = undefined
|
|
18
|
+
await this.connection.close()
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
async disconnect() { await this.saveDatabase() }
|
|
17
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @param {string} sql
|
|
25
|
+
* @returns {Promise<Record<string, any>[]>}
|
|
26
|
+
*/
|
|
18
27
|
async query(sql) {
|
|
19
28
|
const result = await query(this.connection, sql)
|
|
20
29
|
const downcasedSQL = sql.toLowerCase().trim()
|
|
@@ -30,6 +39,7 @@ export default class VelociousDatabaseDriversSqliteConnectionSqlJs {
|
|
|
30
39
|
saveDatabase = async () => {
|
|
31
40
|
const localStorageContent = this.connection.export()
|
|
32
41
|
|
|
42
|
+
// @ts-expect-error
|
|
33
43
|
await this.driver.betterLocalStorage.set(this.driver.localStorageName(), localStorageContent)
|
|
34
44
|
}
|
|
35
45
|
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import BaseForeignKey from "../base-foreign-key.js"
|
|
2
4
|
import {digg} from "diggerize"
|
|
3
5
|
|
|
4
6
|
export default class VelociousDatabaseDriversSqliteForeignKey extends BaseForeignKey {
|
|
7
|
+
/**
|
|
8
|
+
* @param {Record<string, any>} data
|
|
9
|
+
* @param {object} args
|
|
10
|
+
* @param {string} args.tableName
|
|
11
|
+
*/
|
|
5
12
|
constructor(data, {tableName}) {
|
|
6
13
|
super(data)
|
|
7
14
|
this.tableName = tableName
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import fs from "fs/promises"
|
|
2
4
|
import query from "./query.js"
|
|
3
5
|
import sqlite3 from "sqlite3"
|
|
@@ -30,10 +32,14 @@ export default class VelociousDatabaseDriversSqliteNode extends Base {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
async close() {
|
|
33
|
-
await this.connection
|
|
35
|
+
await this.connection?.close()
|
|
34
36
|
this.connection = undefined
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
/**
|
|
40
|
+
* @param {string} sql
|
|
41
|
+
* @returns {Promise<Record<string, any>[]>}
|
|
42
|
+
*/
|
|
37
43
|
async _queryActual(sql) {
|
|
38
44
|
return await query(this.connection, sql)
|
|
39
45
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import BetterLocalStorage from "better-localstorage"
|
|
2
4
|
import ConnectionSqlJs from "./connection-sql-js"
|
|
3
5
|
import initSqlJs from "sql.js"
|
|
@@ -5,6 +7,9 @@ import initSqlJs from "sql.js"
|
|
|
5
7
|
import Base from "./base.js"
|
|
6
8
|
|
|
7
9
|
export default class VelociousDatabaseDriversSqliteWeb extends Base {
|
|
10
|
+
/** @type {BetterLocalStorage | undefined} */
|
|
11
|
+
betterLocalStorage = undefined
|
|
12
|
+
|
|
8
13
|
async connect() {
|
|
9
14
|
this.args = this.getArgs()
|
|
10
15
|
|
|
@@ -32,7 +37,7 @@ export default class VelociousDatabaseDriversSqliteWeb extends Base {
|
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
getConnection() {
|
|
35
|
-
if (this.args
|
|
40
|
+
if (this.args?.getConnection) {
|
|
36
41
|
return this.args.getConnection()
|
|
37
42
|
} else {
|
|
38
43
|
return this._connection
|
|
@@ -40,13 +45,17 @@ export default class VelociousDatabaseDriversSqliteWeb extends Base {
|
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
localStorageName() {
|
|
43
|
-
if (!this.args
|
|
48
|
+
if (!this.args?.name) {
|
|
44
49
|
throw new Error("No name given in arguments for SQLite Web database")
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
return `VelociousDatabaseDriversSqliteWeb---${this.args
|
|
52
|
+
return `VelociousDatabaseDriversSqliteWeb---${this.args?.name}`
|
|
48
53
|
}
|
|
49
54
|
|
|
55
|
+
/**
|
|
56
|
+
* @param {string} sql
|
|
57
|
+
* @returns {Promise<Record<string, any>[]>}
|
|
58
|
+
*/
|
|
50
59
|
async _queryActual(sql) {
|
|
51
60
|
return await this.getConnection().query(sql)
|
|
52
61
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import QueryParserOptions from "../../query-parser/options.js"
|
|
2
4
|
|
|
3
5
|
export default class VelociousDatabaseDriversSqliteOptions extends QueryParserOptions {
|
|
6
|
+
/**
|
|
7
|
+
* @param {import("../../query-parser/options.js").OptionsObjectArgsType} options
|
|
8
|
+
*/
|
|
4
9
|
constructor(options) {
|
|
5
10
|
options.columnQuote = "`"
|
|
6
11
|
options.indexQuote = "`"
|
|
@@ -10,6 +15,10 @@ export default class VelociousDatabaseDriversSqliteOptions extends QueryParserOp
|
|
|
10
15
|
super(options)
|
|
11
16
|
}
|
|
12
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} string
|
|
20
|
+
* @returns {number | string}
|
|
21
|
+
*/
|
|
13
22
|
quote(string) {
|
|
14
23
|
if (!this.driver) throw new Error("Driver not set")
|
|
15
24
|
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
let result
|
|
1
|
+
// @ts-check
|
|
3
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @param {import("sqlite3").Database} connection
|
|
5
|
+
* @param {string} sql
|
|
6
|
+
* @returns {Promise<Record<string, any>[]>}
|
|
7
|
+
*/
|
|
8
|
+
export default async function query(connection, sql) {
|
|
4
9
|
try {
|
|
10
|
+
/** @type {Record<string, any>[]} */
|
|
11
|
+
let result
|
|
12
|
+
|
|
13
|
+
// @ts-expect-error
|
|
5
14
|
result = await connection.all(sql)
|
|
15
|
+
|
|
16
|
+
return result
|
|
6
17
|
} catch (error) {
|
|
7
18
|
let sqlInErrorMessage = `${sql}`
|
|
8
19
|
|
|
@@ -10,10 +21,12 @@ export default async function query(connection, sql) {
|
|
|
10
21
|
sqlInErrorMessage = `${sqlInErrorMessage.substring(0, 4096)}...`
|
|
11
22
|
}
|
|
12
23
|
|
|
13
|
-
error
|
|
24
|
+
if (error instanceof Error) {
|
|
25
|
+
error.message += `\n\n${sqlInErrorMessage}`
|
|
14
26
|
|
|
15
|
-
|
|
27
|
+
throw new Error(error.message)
|
|
28
|
+
} else {
|
|
29
|
+
throw new Error(`An error occurred: ${error}\n\n${sql}`)
|
|
30
|
+
}
|
|
16
31
|
}
|
|
17
|
-
|
|
18
|
-
return result
|
|
19
32
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {import("sql.js").Database} connection
|
|
5
|
+
* @param {string} sql
|
|
6
|
+
* @returns {Promise<Record<string, any>[]>}
|
|
7
|
+
*/
|
|
1
8
|
export default async function query(connection, sql) {
|
|
2
9
|
const rows = []
|
|
3
10
|
let result
|
|
@@ -11,7 +18,11 @@ export default async function query(connection, sql) {
|
|
|
11
18
|
sqlInErrorMessage = `${sqlInErrorMessage.substring(0, 4096)}...`
|
|
12
19
|
}
|
|
13
20
|
|
|
14
|
-
error
|
|
21
|
+
if (error instanceof Error) {
|
|
22
|
+
error.message += `\n\n${sqlInErrorMessage}`
|
|
23
|
+
} else {
|
|
24
|
+
throw new Error(`An error occurred: ${error}\n\n${sqlInErrorMessage}`)
|
|
25
|
+
}
|
|
15
26
|
|
|
16
27
|
throw error
|
|
17
28
|
}
|
|
@@ -20,6 +31,7 @@ export default async function query(connection, sql) {
|
|
|
20
31
|
const columns = result[0].columns
|
|
21
32
|
|
|
22
33
|
for (const rowValues of result[0].values) {
|
|
34
|
+
/** @type {Record<string, any>} */
|
|
23
35
|
const row = {}
|
|
24
36
|
|
|
25
37
|
for (const columnIndex in columns) {
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {(id: string) => {default: typeof import("./record/index.js").default}} ModelClassRequireContextIDFunctionType
|
|
5
|
+
* @typedef {ModelClassRequireContextIDFunctionType & {
|
|
6
|
+
* keys: () => string[],
|
|
7
|
+
* id: string
|
|
8
|
+
* }} ModelClassRequireContextType
|
|
9
|
+
*/
|
|
10
|
+
|
|
1
11
|
import restArgsError from "../utils/rest-args-error.js"
|
|
2
12
|
|
|
3
13
|
export default class VelociousDatabaseInitializerFromRequireContext {
|
|
4
14
|
/**
|
|
5
15
|
* @param {object} args
|
|
6
|
-
* @param {
|
|
16
|
+
* @param {ModelClassRequireContextType} args.requireContext
|
|
7
17
|
*/
|
|
8
18
|
constructor({requireContext, ...restArgs}) {
|
|
9
19
|
restArgsError(restArgs)
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @param {typeof import("./base.js").default} PoolBase
|
|
5
|
+
* @returns {void}
|
|
3
6
|
*/
|
|
4
7
|
export default function baseMethodsForward(PoolBase) {
|
|
5
8
|
const forwardMethods = [
|
|
@@ -25,12 +28,16 @@ export default function baseMethodsForward(PoolBase) {
|
|
|
25
28
|
]
|
|
26
29
|
|
|
27
30
|
for (const forwardMethod of forwardMethods) {
|
|
31
|
+
// @ts-expect-error
|
|
28
32
|
PoolBase.prototype[forwardMethod] = function(...args) {
|
|
29
33
|
const connection = this.getCurrentConnection()
|
|
34
|
+
|
|
35
|
+
// @ts-expect-error
|
|
30
36
|
const connectionMethod = connection[forwardMethod]
|
|
31
37
|
|
|
32
38
|
if (!connectionMethod) throw new Error(`${forwardMethod} isn't defined on driver`)
|
|
33
39
|
|
|
40
|
+
// @ts-expect-error
|
|
34
41
|
return connection[forwardMethod](...args)
|
|
35
42
|
}
|
|
36
43
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import QueryBase from "./base.js"
|
|
2
4
|
|
|
3
5
|
export default class VelociousDatabaseQueryDeleteBase extends QueryBase {
|
|
6
|
+
/**
|
|
7
|
+
* @param {object} args
|
|
8
|
+
* @param {Record<string, any>} args.conditions
|
|
9
|
+
* @param {import("../drivers/base.js").default} args.driver
|
|
10
|
+
* @param {string} args.tableName
|
|
11
|
+
*/
|
|
4
12
|
constructor({conditions, driver, tableName}) {
|
|
5
13
|
super({driver})
|
|
6
14
|
this.conditions = conditions
|
|
@@ -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 VelociousDatabaseQueryPreloaderBelongsTo {
|
|
6
|
+
/**
|
|
7
|
+
* @param {object} args
|
|
8
|
+
* @param {import("../../record/index.js").default[]} args.models
|
|
9
|
+
* @param {import("../../record/relationships/belongs-to.js").default} args.relationship
|
|
10
|
+
*/
|
|
4
11
|
constructor({models, relationship, ...restArgs}) {
|
|
5
12
|
restArgsError(restArgs)
|
|
6
13
|
|
|
@@ -9,6 +16,7 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
|
|
|
9
16
|
}
|
|
10
17
|
|
|
11
18
|
async run() {
|
|
19
|
+
/** @type {Array<number | string>} */
|
|
12
20
|
const foreignKeyValues = []
|
|
13
21
|
const foreignKey = this.relationship.getForeignKey()
|
|
14
22
|
|
|
@@ -18,13 +26,20 @@ export default class VelociousDatabaseQueryPreloaderBelongsTo {
|
|
|
18
26
|
if (!foreignKeyValues.includes(foreignKeyValue)) foreignKeyValues.push(foreignKeyValue)
|
|
19
27
|
}
|
|
20
28
|
|
|
29
|
+
/** @type {Record<string, any>} */
|
|
21
30
|
const whereArgs = {}
|
|
22
31
|
const primaryKey = this.relationship.getPrimaryKey()
|
|
23
32
|
|
|
24
33
|
whereArgs[primaryKey] = foreignKeyValues
|
|
25
34
|
|
|
35
|
+
const targetModelClass = this.relationship.getTargetModelClass()
|
|
36
|
+
|
|
37
|
+
if (!targetModelClass) throw new Error("No target model class could be gotten from relationship")
|
|
38
|
+
|
|
26
39
|
// Load target models to be preloaded on the given models
|
|
27
|
-
const targetModels = await
|
|
40
|
+
const targetModels = await targetModelClass.where(whereArgs).toArray()
|
|
41
|
+
|
|
42
|
+
/** @type {Record<string, import("../../record/index.js").default>} */
|
|
28
43
|
const targetModelsById = {}
|
|
29
44
|
|
|
30
45
|
for (const targetModel of targetModels) {
|
|
@@ -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 VelociousDatabaseQueryPreloaderHasMany {
|
|
6
|
+
/**
|
|
7
|
+
* @param {object} args
|
|
8
|
+
* @param {import("../../record/index.js").default[]} args.models
|
|
9
|
+
* @param {import("../../record/relationships/has-many.js").default} args.relationship
|
|
10
|
+
*/
|
|
4
11
|
constructor({models, relationship, ...restArgs}) {
|
|
5
12
|
restArgsError(restArgs)
|
|
6
13
|
|
|
@@ -9,10 +16,16 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
|
|
|
9
16
|
}
|
|
10
17
|
|
|
11
18
|
async run() {
|
|
19
|
+
/** @type {Array<number | string>} */
|
|
12
20
|
const modelsPrimaryKeyValues = []
|
|
21
|
+
|
|
22
|
+
/** @type {Record<number | string, Array<import("../../record/index.js").default>>} */
|
|
13
23
|
const modelsByPrimaryKeyValue = {}
|
|
24
|
+
|
|
14
25
|
const foreignKey = this.relationship.getForeignKey()
|
|
15
26
|
const primaryKey = this.relationship.getPrimaryKey()
|
|
27
|
+
|
|
28
|
+
/** @type {Record<number | string, Array<import("../../record/index.js").default>>} */
|
|
16
29
|
const preloadCollections = {}
|
|
17
30
|
|
|
18
31
|
if (!primaryKey) {
|
|
@@ -30,12 +43,17 @@ export default class VelociousDatabaseQueryPreloaderHasMany {
|
|
|
30
43
|
modelsByPrimaryKeyValue[primaryKeyValue].push(model)
|
|
31
44
|
}
|
|
32
45
|
|
|
46
|
+
/** @type {Record<string, any>} */
|
|
33
47
|
const whereArgs = {}
|
|
34
48
|
|
|
35
49
|
whereArgs[foreignKey] = modelsPrimaryKeyValues
|
|
36
50
|
|
|
51
|
+
const targetModelClass = this.relationship.getTargetModelClass()
|
|
52
|
+
|
|
53
|
+
if (!targetModelClass) throw new Error("No target model class could be gotten from relationship")
|
|
54
|
+
|
|
37
55
|
// Load target models to be preloaded on the given models
|
|
38
|
-
const targetModels = await
|
|
56
|
+
const targetModels = await targetModelClass.where(whereArgs).toArray()
|
|
39
57
|
|
|
40
58
|
for (const targetModel of targetModels) {
|
|
41
59
|
const foreignKeyValue = targetModel.readColumn(foreignKey)
|
|
@@ -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 VelociousDatabaseQueryPreloaderHasOne {
|
|
6
|
+
/**
|
|
7
|
+
* @param {object} args
|
|
8
|
+
* @param {Array<import("../../record/index.js").default>} args.models
|
|
9
|
+
* @param {import("../../record/relationships/has-one.js").default} args.relationship
|
|
10
|
+
*/
|
|
4
11
|
constructor({models, relationship, ...restArgs}) {
|
|
5
12
|
restArgsError(restArgs)
|
|
6
13
|
|
|
@@ -9,16 +16,22 @@ export default class VelociousDatabaseQueryPreloaderHasOne {
|
|
|
9
16
|
}
|
|
10
17
|
|
|
11
18
|
async run() {
|
|
19
|
+
/** @type {Array<number | string>} */
|
|
12
20
|
const modelsPrimaryKeyValues = []
|
|
21
|
+
|
|
22
|
+
/** @type {Record<number | string, Array<import("../../record/index.js").default>>} */
|
|
13
23
|
const modelsByPrimaryKeyValue = {}
|
|
24
|
+
|
|
14
25
|
const foreignKey = this.relationship.getForeignKey()
|
|
15
26
|
const primaryKey = this.relationship.getPrimaryKey()
|
|
27
|
+
|
|
28
|
+
/** @type {Record<number | string, import("../../record/index.js").default | undefined>} */
|
|
16
29
|
const preloadCollections = {}
|
|
17
30
|
|
|
18
31
|
for (const model of this.models) {
|
|
19
32
|
const primaryKeyValue = model.readColumn(primaryKey)
|
|
20
33
|
|
|
21
|
-
preloadCollections[primaryKeyValue] =
|
|
34
|
+
preloadCollections[primaryKeyValue] = undefined
|
|
22
35
|
|
|
23
36
|
if (!modelsPrimaryKeyValues.includes(primaryKeyValue)) modelsPrimaryKeyValues.push(primaryKeyValue)
|
|
24
37
|
if (!(primaryKeyValue in modelsByPrimaryKeyValue)) modelsByPrimaryKeyValue[primaryKeyValue] = []
|
|
@@ -26,12 +39,17 @@ export default class VelociousDatabaseQueryPreloaderHasOne {
|
|
|
26
39
|
modelsByPrimaryKeyValue[primaryKeyValue].push(model)
|
|
27
40
|
}
|
|
28
41
|
|
|
42
|
+
/** @type {Record<string, any>} */
|
|
29
43
|
const whereArgs = {}
|
|
30
44
|
|
|
31
45
|
whereArgs[foreignKey] = modelsPrimaryKeyValues
|
|
32
46
|
|
|
47
|
+
const targetModelClass = this.relationship.getTargetModelClass()
|
|
48
|
+
|
|
49
|
+
if (!targetModelClass) throw new Error("No target model class could be gotten from relationship")
|
|
50
|
+
|
|
33
51
|
// Load target models to be preloaded on the given models
|
|
34
|
-
const targetModels = await
|
|
52
|
+
const targetModels = await targetModelClass.where(whereArgs).toArray()
|
|
35
53
|
|
|
36
54
|
for (const targetModel of targetModels) {
|
|
37
55
|
const foreignKeyValue = targetModel.readColumn(foreignKey)
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
import BelongsToPreloader from "./preloader/belongs-to.js"
|
|
2
4
|
import HasManyPreloader from "./preloader/has-many.js"
|
|
3
5
|
import HasOnePreloader from "./preloader/has-one.js"
|
|
4
6
|
import restArgsError from "../../utils/rest-args-error.js"
|
|
5
7
|
|
|
6
8
|
export default class VelociousDatabaseQueryPreloader {
|
|
9
|
+
/**
|
|
10
|
+
* @param {object} args
|
|
11
|
+
* @param {typeof import("../record/index.js").default} args.modelClass
|
|
12
|
+
* @param {import("../record/index.js").default[]} args.models
|
|
13
|
+
* @param {Record<string, any>} args.preload
|
|
14
|
+
*/
|
|
7
15
|
constructor({modelClass, models, preload, ...restArgs}) {
|
|
8
16
|
restArgsError(restArgs)
|
|
9
17
|
|
|
@@ -18,15 +26,18 @@ export default class VelociousDatabaseQueryPreloader {
|
|
|
18
26
|
let targetModels
|
|
19
27
|
|
|
20
28
|
if (relationship.getType() == "belongsTo") {
|
|
21
|
-
const
|
|
29
|
+
const belongsToRelationship = /** @type {import("../record/relationships/belongs-to.js").default} */ (relationship)
|
|
30
|
+
const hasManyPreloader = new BelongsToPreloader({models: this.models, relationship: belongsToRelationship})
|
|
22
31
|
|
|
23
32
|
targetModels = await hasManyPreloader.run()
|
|
24
33
|
} else if (relationship.getType() == "hasMany") {
|
|
25
|
-
const
|
|
34
|
+
const hasManyRelationship = /** @type {import("../record/relationships/has-many.js").default} */ (relationship)
|
|
35
|
+
const hasManyPreloader = new HasManyPreloader({models: this.models, relationship: hasManyRelationship})
|
|
26
36
|
|
|
27
37
|
targetModels = await hasManyPreloader.run()
|
|
28
38
|
} else if (relationship.getType() == "hasOne") {
|
|
29
|
-
const
|
|
39
|
+
const hasOneRelationship = /** @type {import("../record/relationships/has-one.js").default} */ (relationship)
|
|
40
|
+
const hasOnePreloader = new HasOnePreloader({models: this.models, relationship: hasOneRelationship})
|
|
30
41
|
|
|
31
42
|
targetModels = await hasOnePreloader.run()
|
|
32
43
|
} else {
|
|
@@ -37,7 +48,11 @@ export default class VelociousDatabaseQueryPreloader {
|
|
|
37
48
|
const newPreload = this.preload[preloadRelationshipName]
|
|
38
49
|
|
|
39
50
|
if (typeof newPreload == "object" && targetModels.length > 0) {
|
|
40
|
-
const
|
|
51
|
+
const targetModelClass = relationship.getTargetModelClass()
|
|
52
|
+
|
|
53
|
+
if (!targetModelClass) throw new Error("No target model class could be gotten from relationship")
|
|
54
|
+
|
|
55
|
+
const preloader = new VelociousDatabaseQueryPreloader({modelClass: targetModelClass, models: targetModels, preload: newPreload})
|
|
41
56
|
|
|
42
57
|
await preloader.run()
|
|
43
58
|
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
export default class VelociousDatabaseQueryUpdateBase {
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} args
|
|
6
|
+
* @param {Record<string, any>} args.conditions
|
|
7
|
+
* @param {Record<string, any>} args.data
|
|
8
|
+
* @param {import("../drivers/base.js").default} args.driver
|
|
9
|
+
* @param {string} args.tableName
|
|
10
|
+
*/
|
|
2
11
|
constructor({conditions, data, driver, tableName}) {
|
|
3
12
|
this.conditions = conditions
|
|
4
13
|
this.data = data
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
2
|
|
|
3
3
|
export default class VelocuiousDatabaseQueryParserLimitParser {
|
|
4
|
+
/**
|
|
5
|
+
* @param {object} args
|
|
6
|
+
* @param {boolean} args.pretty
|
|
7
|
+
* @param {import("../query/index.js").default} args.query
|
|
8
|
+
*/
|
|
4
9
|
constructor({pretty, query}) {
|
|
5
10
|
this.pretty = pretty
|
|
6
11
|
this.query = query
|
|
7
12
|
}
|
|
8
13
|
|
|
9
14
|
toSql() {
|
|
10
|
-
const {pretty, query} =
|
|
15
|
+
const {pretty, query} = this
|
|
11
16
|
const driver = query.driver
|
|
12
17
|
const options = this.query.getOptions()
|
|
13
18
|
let sql = ""
|
|
@@ -1,28 +1,52 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} OptionsObjectArgsType
|
|
5
|
+
* @property {string} columnQuote
|
|
6
|
+
* @property {string} indexQuote
|
|
7
|
+
* @property {import("../drivers/base.js").default} driver
|
|
8
|
+
* @property {string} tableQuote
|
|
9
|
+
* @property {string} stringQuote
|
|
10
|
+
*/
|
|
2
11
|
|
|
3
12
|
export default class VelociousDatabaseQueryParserOptions {
|
|
13
|
+
/**
|
|
14
|
+
* @param {OptionsObjectArgsType} options
|
|
15
|
+
*/
|
|
4
16
|
constructor(options) {
|
|
5
|
-
this.columnQuote =
|
|
6
|
-
this.indexQuote =
|
|
7
|
-
this.driver =
|
|
8
|
-
this.tableQuote =
|
|
9
|
-
this.stringQuote =
|
|
17
|
+
this.columnQuote = options.columnQuote
|
|
18
|
+
this.indexQuote = options.indexQuote
|
|
19
|
+
this.driver = options.driver
|
|
20
|
+
this.tableQuote = options.tableQuote
|
|
21
|
+
this.stringQuote = options.stringQuote
|
|
10
22
|
|
|
11
23
|
if (!this.driver) throw new Error("No driver given to parser options")
|
|
12
24
|
}
|
|
13
25
|
|
|
26
|
+
/**
|
|
27
|
+
* @param {any} value
|
|
28
|
+
* @returns {number | string}
|
|
29
|
+
*/
|
|
14
30
|
quote(value) {
|
|
15
31
|
if (typeof value == "number") return value
|
|
16
32
|
|
|
17
33
|
return this.quoteString(value)
|
|
18
34
|
}
|
|
19
35
|
|
|
36
|
+
/**
|
|
37
|
+
* @param {string} databaseName
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
20
40
|
quoteDatabaseName(databaseName) {
|
|
21
41
|
if (databaseName.includes(this.tableQuote)) throw new Error(`Possible SQL injection in database name: ${databaseName}`)
|
|
22
42
|
|
|
23
43
|
return `${this.tableQuote}${databaseName}${this.tableQuote}`
|
|
24
44
|
}
|
|
25
45
|
|
|
46
|
+
/**
|
|
47
|
+
* @param {string} columnName
|
|
48
|
+
* @returns {string}
|
|
49
|
+
*/
|
|
26
50
|
quoteColumnName(columnName) {
|
|
27
51
|
if (!columnName) throw new Error("No column name was given")
|
|
28
52
|
if (columnName.includes(this.columnQuote)) throw new Error(`Invalid column name: ${columnName}`)
|
|
@@ -30,12 +54,29 @@ export default class VelociousDatabaseQueryParserOptions {
|
|
|
30
54
|
return `${this.columnQuote}${columnName}${this.columnQuote}`
|
|
31
55
|
}
|
|
32
56
|
|
|
57
|
+
/**
|
|
58
|
+
* @param {string} indexName
|
|
59
|
+
* @returns {string}
|
|
60
|
+
*/
|
|
33
61
|
quoteIndexName(indexName) {
|
|
34
62
|
if (!indexName || indexName.includes(this.columnQuote)) throw new Error(`Invalid column name: ${indexName}`)
|
|
35
63
|
|
|
36
64
|
return `${this.columnQuote}${indexName}${this.columnQuote}`
|
|
37
65
|
}
|
|
38
66
|
|
|
67
|
+
/**
|
|
68
|
+
* @abstract
|
|
69
|
+
* @param {any} string
|
|
70
|
+
* @returns {string}
|
|
71
|
+
*/
|
|
72
|
+
quoteString(string) { // eslint-disable-line no-unused-vars
|
|
73
|
+
throw new Error("quoteString not implemented")
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {string} tableName
|
|
78
|
+
* @returns {string}
|
|
79
|
+
*/
|
|
39
80
|
quoteTableName(tableName) {
|
|
40
81
|
if (!tableName || tableName.includes(this.tableQuote)) throw new Error(`Invalid table name: ${tableName}`)
|
|
41
82
|
|