velocious 1.0.2 → 1.0.4
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/.github/dependabot.yml +1 -1
- package/README.md +19 -3
- package/bin/velocious.mjs +4 -4
- package/index.mjs +5 -3
- package/package.json +5 -3
- package/peak_flow.yml +5 -2
- package/spec/cli/commands/db/create-spec.mjs +25 -0
- package/spec/cli/commands/db/migrate-spec.mjs +37 -0
- package/spec/cli/commands/destroy/migration-spec.mjs +15 -0
- package/spec/cli/commands/generate/migration-spec.mjs +18 -0
- package/spec/cli/commands/init-spec.mjs +19 -0
- package/spec/cli/commands/test/test-files-finder-spec.mjs +12 -0
- package/spec/database/drivers/mysql/connection-spec.mjs +2 -2
- package/spec/dummy/dummy-directory.mjs +11 -0
- package/spec/dummy/index.mjs +22 -26
- package/spec/dummy/src/config/configuration.example.mjs +21 -0
- package/spec/dummy/src/config/configuration.peakflow.mjs +22 -0
- package/spec/dummy/src/database/migrations/20230728075328-create-projects.mjs +11 -0
- package/spec/dummy/src/database/migrations/20230728075329-create-tasks.mjs +13 -0
- package/spec/http-server/client-spec.mjs +7 -12
- package/src/application.mjs +10 -11
- package/src/cli/base-command.mjs +11 -0
- package/src/cli/commands/db/create.mjs +44 -8
- package/src/cli/commands/db/migrate.mjs +105 -0
- package/src/cli/commands/destroy/migration.mjs +35 -0
- package/src/cli/commands/generate/migration.mjs +31 -7
- package/src/cli/commands/generate/model.mjs +36 -0
- package/src/cli/commands/init.mjs +60 -0
- package/src/cli/commands/server.mjs +15 -0
- package/src/cli/commands/test/index.mjs +14 -0
- package/src/cli/commands/test/test-files-finder.mjs +99 -0
- package/src/cli/commands/test/test-runner.mjs +19 -0
- package/src/cli/index.mjs +37 -16
- package/src/configuration-resolver.mjs +26 -0
- package/src/configuration.mjs +51 -13
- package/src/controller.mjs +1 -1
- package/src/database/drivers/base.mjs +8 -0
- package/src/database/drivers/mysql/index.mjs +25 -0
- package/src/database/drivers/mysql/sql/create-database.mjs +4 -0
- package/src/database/drivers/mysql/sql/create-table.mjs +4 -0
- package/src/database/drivers/sqlite/index.native.mjs +92 -0
- package/src/database/drivers/sqlite/index.web.mjs +64 -0
- package/src/database/drivers/sqlite/options.mjs +17 -0
- package/src/database/drivers/sqlite/query-parser.mjs +25 -0
- package/src/database/drivers/sqlite/query.native.mjs +9 -0
- package/src/database/drivers/sqlite/query.web.mjs +9 -0
- package/src/database/drivers/sqlite/sql/create-table.mjs +4 -0
- package/src/database/drivers/sqlite/sql/delete.mjs +19 -0
- package/src/database/drivers/sqlite/sql/insert.mjs +29 -0
- package/src/database/drivers/sqlite/sql/update.mjs +31 -0
- package/src/database/handler.mjs +0 -4
- package/src/database/migrate-from-require-context.mjs +53 -0
- package/src/database/migration/index.mjs +15 -2
- package/src/database/pool/async-tracked-multi-connection.mjs +81 -0
- package/src/database/pool/base.mjs +47 -0
- package/src/database/pool/single-multi-use.mjs +40 -0
- package/src/database/query/base.mjs +11 -0
- package/src/database/query/create-database-base.mjs +22 -0
- package/src/database/query/create-table-base.mjs +69 -0
- package/src/database/query/delete-base.mjs +4 -10
- package/src/database/query/from-plain.mjs +3 -5
- package/src/database/query/from-table.mjs +2 -2
- package/src/database/record/index.mjs +2 -2
- package/src/database/table-data/index.mjs +83 -0
- package/src/http-server/worker-handler/index.mjs +2 -1
- package/src/http-server/worker-handler/worker-thread.mjs +17 -9
- package/src/routes/app-routes.mjs +10 -0
- package/src/routes/resolver.mjs +4 -2
- package/src/spec/index.mjs +5 -0
- package/src/templates/configuration.mjs +19 -0
- package/src/templates/generate-migration.mjs +11 -0
- package/src/templates/generate-model.mjs +4 -0
- package/src/templates/routes.mjs +11 -0
- package/src/utils/file-exists.mjs +13 -0
- package/spec/cli/generate/migration-spec.mjs +0 -9
- package/spec/dummy/src/config/database.example.mjs +0 -15
- package/spec/dummy/src/config/database.peakflow.mjs +0 -15
- package/spec/dummy/src/database/migrations/001-create-tasks.mjs +0 -12
- package/src/database/pool/index.mjs +0 -43
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import Base from "../base.mjs"
|
|
2
|
+
import CreateTable from "../sqlite/sql/create-table.mjs"
|
|
3
|
+
import Delete from "../sqlite/sql/delete.mjs"
|
|
4
|
+
import {digg} from "diggerize"
|
|
5
|
+
import Insert from "../sqlite/sql/insert.mjs"
|
|
6
|
+
import Options from "../sqlite/options.mjs"
|
|
7
|
+
import query from "./query.mjs"
|
|
8
|
+
import QueryParser from "../sqlite/query-parser.mjs"
|
|
9
|
+
import * as SQLite from "expo-sqlite"
|
|
10
|
+
import Update from "../sqlite/sql/update.mjs"
|
|
11
|
+
|
|
12
|
+
export default class VelociousDatabaseDriversSqliteNative extends Base{
|
|
13
|
+
async connect() {
|
|
14
|
+
const connection = await SQLite.openDatabaseAsync(digg(this.connectArgs(), "name"))
|
|
15
|
+
|
|
16
|
+
this.connection = connection
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
disconnect() {
|
|
20
|
+
this.connection.end()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
connectArgs() {
|
|
24
|
+
const args = this.getArgs()
|
|
25
|
+
const connectArgs = []
|
|
26
|
+
const forward = ["database", "host", "password"]
|
|
27
|
+
|
|
28
|
+
for (const forwardValue of forward) {
|
|
29
|
+
if (forwardValue in args) connectArgs[forwardValue] = digg(args, forwardValue)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if ("username" in args) connectArgs["user"] = args["username"]
|
|
33
|
+
|
|
34
|
+
return connectArgs
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async close() {
|
|
38
|
+
await this.connection.end()
|
|
39
|
+
this.connection = undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
createTableSql(tableData) {
|
|
43
|
+
const createArgs = Object.assign({tableData, driver: this})
|
|
44
|
+
const createTable = new CreateTable(createArgs)
|
|
45
|
+
|
|
46
|
+
return createTable.toSql()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async query(sql) {
|
|
50
|
+
return await query(this.connection, sql)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
queryToSql(query) {
|
|
54
|
+
return new QueryParser({query}).toSql()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
quote(string) {
|
|
58
|
+
if (!this.connection) throw new Error("Can't escape before connected")
|
|
59
|
+
|
|
60
|
+
return this.connection.escape(string)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
quoteColumn(string) {
|
|
64
|
+
return `\`${string}\``
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
deleteSql({tableName, conditions}) {
|
|
68
|
+
const deleteInstruction = new Delete({conditions, driver: this, tableName})
|
|
69
|
+
|
|
70
|
+
return deleteInstruction.toSql()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
insertSql({tableName, data}) {
|
|
74
|
+
const insert = new Insert({driver: this, tableName, data})
|
|
75
|
+
|
|
76
|
+
return insert.toSql()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
options() {
|
|
80
|
+
if (!this._options) {
|
|
81
|
+
this._options = new Options({driver: this})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return this._options
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
updateSql({conditions, data, tableName}) {
|
|
88
|
+
const update = new Update({conditions, data, driver: this, tableName})
|
|
89
|
+
|
|
90
|
+
return update.toSql()
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import Base from "../base.mjs"
|
|
2
|
+
import CreateTable from "../sqlite/sql/create-table.mjs"
|
|
3
|
+
import Delete from "../sqlite/sql/delete.mjs"
|
|
4
|
+
import {digg} from "diggerize"
|
|
5
|
+
import Insert from "../sqlite/sql/insert.mjs"
|
|
6
|
+
import Options from "../sqlite/options.mjs"
|
|
7
|
+
import query from "./query"
|
|
8
|
+
import QueryParser from "../sqlite/query-parser.mjs"
|
|
9
|
+
import Update from "../sqlite/sql/update.mjs"
|
|
10
|
+
|
|
11
|
+
import initSqlJs from "sql.js"
|
|
12
|
+
|
|
13
|
+
export default class VelociousDatabaseDriversSqliteWeb extends Base{
|
|
14
|
+
async connect() {
|
|
15
|
+
const SQL = await initSqlJs({
|
|
16
|
+
// Required to load the wasm binary asynchronously. Of course, you can host it wherever you want you can omit locateFile completely when running in Node.
|
|
17
|
+
locateFile: (file) => `https://sql.js.org/dist/${file}`
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const databaseContent = localStorage.getItem(this.localStorageName())
|
|
21
|
+
|
|
22
|
+
this.connection = new SQL.Database(databaseContent)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
localStorageName = () => `VelociousDatabaseDriversSqliteWeb---${digg(this.getArgs(), "name")}`
|
|
26
|
+
disconnect = () => this.saveDatabase()
|
|
27
|
+
saveDatabase = () => localStorage.setItem(this.localStorageName(), this.connection.export())
|
|
28
|
+
|
|
29
|
+
async close() {
|
|
30
|
+
this.saveDatabase()
|
|
31
|
+
await this.connection.end()
|
|
32
|
+
this.connection = undefined
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
createTableSql(tableData) {
|
|
36
|
+
const createArgs = Object.assign({tableData, driver: this})
|
|
37
|
+
const createTable = new CreateTable(createArgs)
|
|
38
|
+
|
|
39
|
+
return createTable.toSql()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
query = async (sql) => await query(this.connection, sql)
|
|
43
|
+
queryToSql = (query) => new QueryParser({query}).toSql()
|
|
44
|
+
|
|
45
|
+
quote(string) {
|
|
46
|
+
if (!this.connection) throw new Error("Can't escape before connected")
|
|
47
|
+
|
|
48
|
+
return this.connection.escape(string)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
quoteColumn = (string) => `\`${string}\``
|
|
52
|
+
deleteSql = ({tableName, conditions}) => new Delete({conditions, driver: this, tableName}).toSql()
|
|
53
|
+
insertSql = ({tableName, data}) => new Insert({driver: this, tableName, data}).toSql()
|
|
54
|
+
|
|
55
|
+
options() {
|
|
56
|
+
if (!this._options) {
|
|
57
|
+
this._options = new Options({driver: this})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return this._options
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
updateSql = ({conditions, data, tableName}) => new Update({conditions, data, driver: this, tableName}).toSql()
|
|
64
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import QueryParserOptions from "../../query-parser/options.mjs"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseDriversMysqlOptions extends QueryParserOptions {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
options.columnQuote = "`"
|
|
6
|
+
options.stringQuote = "'"
|
|
7
|
+
options.tableQuote = "`"
|
|
8
|
+
|
|
9
|
+
super(options)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
quote(string) {
|
|
13
|
+
if (!this.driver) throw new Error("Driver not set")
|
|
14
|
+
|
|
15
|
+
return this.driver.quote(string)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
import FromParser from "../../query-parser/from-parser.mjs"
|
|
3
|
+
import JoinsParser from "../../query-parser/joins-parser.mjs"
|
|
4
|
+
import SelectParser from "../../query-parser/select-parser.mjs"
|
|
5
|
+
|
|
6
|
+
export default class VelociousDatabaseConnectionDriversMysqlQueryParser {
|
|
7
|
+
constructor({pretty, query}) {
|
|
8
|
+
if (!query) throw new Error("No query given")
|
|
9
|
+
|
|
10
|
+
this.pretty = pretty
|
|
11
|
+
this.query = query
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
toSql() {
|
|
15
|
+
const {pretty, query} = digs(this, "pretty", "query")
|
|
16
|
+
|
|
17
|
+
let sql = ""
|
|
18
|
+
|
|
19
|
+
sql += new SelectParser({pretty, query}).toSql()
|
|
20
|
+
sql += new FromParser({pretty, query}).toSql()
|
|
21
|
+
sql += new JoinsParser({pretty, query}).toSql()
|
|
22
|
+
|
|
23
|
+
return sql
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import DeleteBase from "../../../query/delete-base.mjs"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseConnectionDriversMysqlSqlDelete extends DeleteBase {
|
|
4
|
+
toSql() {
|
|
5
|
+
let sql = `DELETE FROM ${this.getOptions().quoteTableName(this.tableName)} WHERE `
|
|
6
|
+
let count = 0
|
|
7
|
+
|
|
8
|
+
for (let columnName in this.conditions) {
|
|
9
|
+
if (count > 0) sql += " AND "
|
|
10
|
+
|
|
11
|
+
sql += this.getOptions().quoteColumnName(columnName)
|
|
12
|
+
sql += " = "
|
|
13
|
+
sql += this.getOptions().quote(this.conditions[columnName])
|
|
14
|
+
count++
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return sql
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import InsertBase from "../../../query/insert-base.mjs"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseConnectionDriversMysqlSqlInsert extends InsertBase {
|
|
4
|
+
toSql() {
|
|
5
|
+
let sql = `INSERT INTO ${this.getOptions().quoteTableName(this.tableName)} (`
|
|
6
|
+
let count = 0
|
|
7
|
+
|
|
8
|
+
for (let columnName in this.data) {
|
|
9
|
+
if (count > 0) sql += ", "
|
|
10
|
+
|
|
11
|
+
sql += this.getOptions().quoteColumnName(columnName)
|
|
12
|
+
count++
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
sql += ") VALUES ("
|
|
16
|
+
count = 0
|
|
17
|
+
|
|
18
|
+
for (let columnName in this.data) {
|
|
19
|
+
if (count > 0) sql += ", "
|
|
20
|
+
|
|
21
|
+
sql += this.getOptions().quote(this.data[columnName])
|
|
22
|
+
count++
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
sql += ")"
|
|
26
|
+
|
|
27
|
+
return sql
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import UpdateBase from "../../../query/update-base.mjs"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseConnectionDriversMysqlSqlUpdate extends UpdateBase {
|
|
4
|
+
toSql() {
|
|
5
|
+
let sql = `UPDATE ${this.getOptions().quoteTableName(this.tableName)} SET `
|
|
6
|
+
let count = 0
|
|
7
|
+
|
|
8
|
+
for (let columnName in this.data) {
|
|
9
|
+
if (count > 0) sql += ", "
|
|
10
|
+
|
|
11
|
+
sql += this.getOptions().quoteColumnName(columnName)
|
|
12
|
+
sql += " = "
|
|
13
|
+
sql += this.getOptions().quote(this.data[columnName])
|
|
14
|
+
count++
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
sql += " WHERE "
|
|
18
|
+
count = 0
|
|
19
|
+
|
|
20
|
+
for (let columnName in this.conditions) {
|
|
21
|
+
if (count > 0) sql += " AND "
|
|
22
|
+
|
|
23
|
+
sql += this.getOptions().quoteColumnName(columnName)
|
|
24
|
+
sql += " = "
|
|
25
|
+
sql += this.getOptions().quote(this.conditions[columnName])
|
|
26
|
+
count++
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return sql
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/database/handler.mjs
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import Configuration from "../configuration.mjs"
|
|
2
|
+
import * as inflection from "inflection"
|
|
3
|
+
|
|
4
|
+
export default class VelociousDatabaseMigrateFromRequireContext {
|
|
5
|
+
constructor(configuration) {
|
|
6
|
+
this.configuration = configuration || Configuration.current()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async execute(requireContext) {
|
|
10
|
+
const files = requireContext.keys()
|
|
11
|
+
.map((file) => {
|
|
12
|
+
const match = file.match(/^\.\/(\d{14})-(.+)\.mjs$/)
|
|
13
|
+
|
|
14
|
+
if (!match) return null
|
|
15
|
+
|
|
16
|
+
const date = parseInt(match[1])
|
|
17
|
+
const migrationName = match[2]
|
|
18
|
+
const migrationClassName = inflection.camelize(migrationName)
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
file,
|
|
22
|
+
date,
|
|
23
|
+
migrationClassName
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
.filter((migration) => Boolean(migration))
|
|
27
|
+
.sort((migration1, migration2) => migration1.date - migration2.date)
|
|
28
|
+
|
|
29
|
+
for (const migration of files) {
|
|
30
|
+
await this.runMigrationFile(migration, requireContext)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async runMigrationFile(migration, requireContext) {
|
|
35
|
+
if (!this.configuration) throw new Error("No configuration set")
|
|
36
|
+
if (!this.configuration.isDatabasePoolInitialized()) await this.configuration.initializeDatabasePool()
|
|
37
|
+
|
|
38
|
+
await this.configuration.getDatabasePool().withConnection(async () => {
|
|
39
|
+
const MigrationClass = requireContext(migration.file).default
|
|
40
|
+
const migrationInstance = new MigrationClass({
|
|
41
|
+
configuration: this.configuration
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
if (migrationInstance.change) {
|
|
45
|
+
await migrationInstance.change()
|
|
46
|
+
} else if (migrationInstance.up) {
|
|
47
|
+
await migrationInstance.up()
|
|
48
|
+
} else {
|
|
49
|
+
throw new Error(`'change' or 'up' didn't exist on migration: ${migration.file}`)
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
import TableData from "../table-data/index.mjs"
|
|
2
|
+
|
|
1
3
|
export default class VelociousDatabaseMigration {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
+
constructor({configuration}) {
|
|
5
|
+
this.configuration = configuration
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async createTable(tableName, callback) {
|
|
9
|
+
const tableData = new TableData(tableName)
|
|
10
|
+
|
|
11
|
+
callback(tableData)
|
|
12
|
+
|
|
13
|
+
const databasePool = this.configuration.getDatabasePool()
|
|
14
|
+
const sql = databasePool.createTableSql(tableData)
|
|
15
|
+
|
|
16
|
+
await databasePool.query(sql)
|
|
4
17
|
}
|
|
5
18
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {AsyncLocalStorage} from "async_hooks"
|
|
2
|
+
import BasePool from "./base.mjs"
|
|
3
|
+
|
|
4
|
+
let idSeq = 0
|
|
5
|
+
|
|
6
|
+
export default class VelociousDatabasePoolAsyncTrackedMultiConnection extends BasePool {
|
|
7
|
+
static current() {
|
|
8
|
+
if (!this.velociousDatabasePoolAsyncTrackedMultiConnection) {
|
|
9
|
+
this.velociousDatabasePoolAsyncTrackedMultiConnection = new VelociousDatabasePoolAsyncTrackedMultiConnection()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return this.velociousDatabasePoolAsyncTrackedMultiConnection
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
constructor(args = {}) {
|
|
16
|
+
super(args)
|
|
17
|
+
this.connections = []
|
|
18
|
+
this.connectionsInUse = {}
|
|
19
|
+
this.asyncLocalStorage = new AsyncLocalStorage()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
checkin = (connection) => {
|
|
23
|
+
const id = connection.getIdSeq()
|
|
24
|
+
|
|
25
|
+
if (id in this.connectionsInUse) {
|
|
26
|
+
delete this.connectionsInUse[id]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
connection.setIdSeq(undefined)
|
|
30
|
+
|
|
31
|
+
this.connections.push(connection)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async checkout() {
|
|
35
|
+
let connection = this.connections.shift()
|
|
36
|
+
|
|
37
|
+
if (!connection) {
|
|
38
|
+
connection = await this.spawnConnection()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (connection.getIdSeq() !== undefined) throw new Error(`Connection already has an ID-seq - is it in use? ${connection.getIdSeq()}`)
|
|
42
|
+
|
|
43
|
+
const id = idSeq++
|
|
44
|
+
|
|
45
|
+
connection.setIdSeq(id)
|
|
46
|
+
this.connectionsInUse[id] = connection
|
|
47
|
+
|
|
48
|
+
return connection
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setCurrent() {
|
|
52
|
+
this.constructor.velociousDatabasePoolAsyncTrackedMultiConnection = this
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async withConnection(callback) {
|
|
56
|
+
const connection = await this.checkout()
|
|
57
|
+
const id = connection.getIdSeq()
|
|
58
|
+
|
|
59
|
+
await this.asyncLocalStorage.run(id, async () => {
|
|
60
|
+
try {
|
|
61
|
+
await callback()
|
|
62
|
+
} finally {
|
|
63
|
+
this.checkin(connection)
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getCurrentConnection() {
|
|
69
|
+
const id = this.asyncLocalStorage.getStore()
|
|
70
|
+
|
|
71
|
+
if (id === undefined) {
|
|
72
|
+
throw new Error("ID hasn't been set for this async context")
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!(id in this.connectionsInUse)) {
|
|
76
|
+
throw new Error(`Connection ${id} doesn't exist any more - has it been checked in again?`)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return this.connectionsInUse[id]
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import Configuration from "../../configuration.mjs"
|
|
2
|
+
import {digg} from "diggerize"
|
|
3
|
+
|
|
4
|
+
class VelociousDatabasePoolBase {
|
|
5
|
+
constructor(args = {}) {
|
|
6
|
+
this.configuration = args.configuration || Configuration.current()
|
|
7
|
+
this.connections = []
|
|
8
|
+
this.connectionsInUse = {}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
getConfiguration = () => digg(this, "configuration", "database", "default", "master")
|
|
12
|
+
|
|
13
|
+
setDriverClass(driverClass) {
|
|
14
|
+
this.driverClass = driverClass
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async spawnConnection() {
|
|
18
|
+
const defaultConfig = this.getConfiguration()
|
|
19
|
+
const connection = await this.spawnConnectionWithConfiguration(defaultConfig)
|
|
20
|
+
|
|
21
|
+
return connection
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async spawnConnectionWithConfiguration(config) {
|
|
25
|
+
const DriverClass = config.driver || this.driverClass
|
|
26
|
+
|
|
27
|
+
if (!DriverClass) throw new Error("No driver class set in database pool or in given config")
|
|
28
|
+
|
|
29
|
+
const connection = new DriverClass(config)
|
|
30
|
+
|
|
31
|
+
await connection.connect()
|
|
32
|
+
|
|
33
|
+
return connection
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const forwardMethods = ["createTableSql", "deleteSql", "insertSql", "query", "quote", "updateSql"]
|
|
38
|
+
|
|
39
|
+
for (const forwardMethod of forwardMethods) {
|
|
40
|
+
VelociousDatabasePoolBase.prototype[forwardMethod] = function(...args) {
|
|
41
|
+
const connection = this.getCurrentConnection()
|
|
42
|
+
|
|
43
|
+
return connection[forwardMethod](...args)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default VelociousDatabasePoolBase
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import BasePool from "./base.mjs"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabasePoolSingleMultiUser extends BasePool {
|
|
4
|
+
static current() {
|
|
5
|
+
if (!this.velociousDatabasePoolSingleMultiUser) {
|
|
6
|
+
this.velociousDatabasePoolSingleMultiUser = new VelociousDatabasePoolSingleMultiUser()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return this.velociousDatabasePoolSingleMultiUser
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
checkin = (connection) => {
|
|
13
|
+
// Do nothing
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async checkout() {
|
|
17
|
+
if (!this.connection) {
|
|
18
|
+
this.connection = await this.spawnConnection()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return this.connection
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
setCurrent() {
|
|
25
|
+
this.constructor.velociousDatabasePoolSingleMultiUser = this
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async withConnection(callback) {
|
|
29
|
+
await this.checkout() // Ensure a connection is present
|
|
30
|
+
await callback()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getCurrentConnection() {
|
|
34
|
+
if (!this.connection) {
|
|
35
|
+
throw new Error("A connection hasn't been made yet")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return this.connection
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
import QueryBase from "./base.mjs"
|
|
3
|
+
|
|
4
|
+
export default class VelociousDatabaseQueryCreateDatabaseBase extends QueryBase {
|
|
5
|
+
constructor({driver, databaseName, ifNotExists}) {
|
|
6
|
+
super({driver})
|
|
7
|
+
this.databaseName = databaseName
|
|
8
|
+
this.ifNotExists = ifNotExists
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
toSql() {
|
|
12
|
+
const {databaseName} = this
|
|
13
|
+
const {tableQuote} = digs(this.getOptions(), "tableQuote")
|
|
14
|
+
let sql = "CREATE DATABASE"
|
|
15
|
+
|
|
16
|
+
if (this.ifNotExists) sql += " IF NOT EXISTS"
|
|
17
|
+
|
|
18
|
+
sql += ` ${tableQuote}${databaseName}${tableQuote}`
|
|
19
|
+
|
|
20
|
+
return sql
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import QueryBase from "./base.mjs"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseQueryCreateTableBase extends QueryBase {
|
|
4
|
+
constructor({driver, ifNotExists, tableData}) {
|
|
5
|
+
super({driver})
|
|
6
|
+
this.ifNotExists = ifNotExists
|
|
7
|
+
this.tableData = tableData
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
toSql() {
|
|
11
|
+
const {tableData} = this
|
|
12
|
+
let sql = "CREATE TABLE"
|
|
13
|
+
|
|
14
|
+
if (this.ifNotExists || tableData.getIfNotExists()) sql += " IF NOT EXISTS"
|
|
15
|
+
|
|
16
|
+
sql += ` ${tableData.getName()} (`
|
|
17
|
+
|
|
18
|
+
let columnCount = 0
|
|
19
|
+
|
|
20
|
+
for (const column of tableData.getColumns()) {
|
|
21
|
+
columnCount++
|
|
22
|
+
|
|
23
|
+
let maxlength = column.args.maxlength
|
|
24
|
+
let type = column.args.type
|
|
25
|
+
|
|
26
|
+
if (type == "string") {
|
|
27
|
+
type = "varchar"
|
|
28
|
+
maxlength ||= 255
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (columnCount > 1) sql += ", "
|
|
32
|
+
|
|
33
|
+
sql += `${this.driver.quoteColumn(column.name)} ${type}`
|
|
34
|
+
|
|
35
|
+
if (maxlength !== undefined) sql += `(${maxlength})`
|
|
36
|
+
|
|
37
|
+
if (column.args.autoIncrement) sql += " AUTO_INCREMENT"
|
|
38
|
+
if (column.args.primaryKey) sql += " PRIMARY KEY"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const index of tableData.getIndexes()) {
|
|
42
|
+
sql += ","
|
|
43
|
+
|
|
44
|
+
if (index.getUnique()) {
|
|
45
|
+
sql += " UNIQUE"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
sql += " INDEX"
|
|
49
|
+
|
|
50
|
+
if (index.getName()) {
|
|
51
|
+
sql += ` ${index.getName()}`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
sql += " ("
|
|
55
|
+
|
|
56
|
+
index.getColumns().forEach((column, columnIndex) => {
|
|
57
|
+
if (columnIndex > 0) sql += ", "
|
|
58
|
+
|
|
59
|
+
sql += this.driver.quoteColumn(column.name)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
sql += ")"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
sql += ")"
|
|
66
|
+
|
|
67
|
+
return sql
|
|
68
|
+
}
|
|
69
|
+
}
|