velocious 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.mjs +1 -19
- package/package.json +6 -3
- package/spec/cli/commands/db/create-spec.mjs +1 -1
- package/spec/cli/commands/db/migrate-spec.mjs +2 -0
- package/spec/database/connection/drivers/mysql/query-parser-spec.mjs +6 -5
- package/spec/database/drivers/mysql/connection-spec.mjs +2 -3
- package/spec/database/record/create-spec.mjs +9 -0
- package/spec/database/record/find-spec.mjs +0 -1
- package/spec/database/record/query-spec.mjs +37 -0
- package/spec/dummy/index.mjs +14 -2
- package/spec/dummy/src/config/configuration.example.mjs +16 -1
- package/spec/dummy/src/config/configuration.peakflow.mjs +16 -1
- package/spec/dummy/src/database/migrations/20230728075328-create-projects.mjs +0 -1
- package/spec/dummy/src/database/migrations/20230728075329-create-tasks.mjs +0 -1
- package/spec/dummy/src/database/migrations/20250605133926-create-project-translations.mjs +16 -0
- package/spec/dummy/src/models/project.mjs +9 -0
- package/spec/dummy/src/models/task.mjs +6 -2
- package/src/big-brother.mjs +37 -0
- package/src/cli/commands/db/create.mjs +8 -6
- package/src/cli/commands/db/migrate.mjs +1 -2
- package/src/cli/commands/generate/migration.mjs +1 -1
- package/src/cli/commands/generate/model.mjs +1 -1
- package/src/configuration.mjs +39 -3
- package/src/database/drivers/base.mjs +60 -0
- package/src/database/drivers/mysql/column.mjs +8 -0
- package/src/database/drivers/mysql/index.mjs +34 -2
- package/src/database/drivers/mysql/options.mjs +1 -0
- package/src/database/drivers/mysql/query-parser.mjs +2 -23
- package/src/database/drivers/mysql/table.mjs +25 -0
- package/src/database/drivers/sqlite/base.mjs +108 -0
- package/src/database/drivers/sqlite/column.mjs +10 -0
- package/src/database/drivers/sqlite/index.native.mjs +22 -63
- package/src/database/drivers/sqlite/index.web.mjs +28 -37
- package/src/database/drivers/sqlite/options.mjs +2 -1
- package/src/database/drivers/sqlite/query-parser.mjs +2 -23
- package/src/database/drivers/sqlite/query.native.mjs +16 -1
- package/src/database/drivers/sqlite/query.web.mjs +27 -2
- package/src/database/drivers/sqlite/sql/create-index.mjs +4 -0
- package/src/database/drivers/sqlite/table.mjs +24 -0
- package/src/database/initializer-from-require-context.mjs +21 -0
- package/src/database/migrate-from-require-context.mjs +11 -2
- package/src/database/migration/index.mjs +34 -2
- package/src/database/migrator.mjs +75 -0
- package/src/database/pool/async-tracked-multi-connection.mjs +1 -1
- package/src/database/pool/base.mjs +19 -1
- package/src/database/pool/single-multi-use.mjs +1 -1
- package/src/database/query/base.mjs +2 -1
- package/src/database/query/create-index-base.mjs +50 -0
- package/src/database/query/create-table-base.mjs +40 -17
- package/src/database/query/index.mjs +83 -21
- package/src/database/query/insert-base.mjs +4 -0
- package/src/database/query/preloader/belongs-to.mjs +52 -0
- package/src/database/query/preloader/has-many.mjs +55 -0
- package/src/database/query/preloader.mjs +41 -0
- package/src/database/query/where-base.mjs +9 -0
- package/src/database/query/where-hash.mjs +35 -0
- package/src/database/query/where-plain.mjs +13 -0
- package/src/database/query-parser/base-query-parser.mjs +33 -0
- package/src/database/query-parser/group-parser.mjs +40 -0
- package/src/database/query-parser/joins-parser.mjs +48 -7
- package/src/database/query-parser/limit-parser.mjs +40 -0
- package/src/database/query-parser/options.mjs +4 -3
- package/src/database/query-parser/order-parser.mjs +39 -0
- package/src/database/query-parser/select-parser.mjs +5 -1
- package/src/database/query-parser/where-parser.mjs +39 -0
- package/src/database/record/index.mjs +464 -29
- package/src/database/record/instance-relationships/base.mjs +28 -0
- package/src/database/record/instance-relationships/belongs-to.mjs +20 -0
- package/src/database/record/instance-relationships/has-many.mjs +47 -0
- package/src/database/record/relationships/base.mjs +32 -0
- package/src/database/record/relationships/belongs-to.mjs +12 -0
- package/src/database/record/relationships/has-many.mjs +12 -0
- package/src/database/table-data/index.mjs +15 -25
- package/src/http-server/worker-handler/worker-thread.mjs +7 -4
- package/src/templates/generate-model.mjs +3 -1
- package/src/utils/rest-args-error.mjs +9 -0
- package/src/database/drivers/index.mjs +0 -5
- package/src/database/index.mjs +0 -15
- package/src/database/migrator/index.mjs +0 -15
|
@@ -3,6 +3,7 @@ import QueryParserOptions from "../../query-parser/options.mjs"
|
|
|
3
3
|
export default class VelociousDatabaseDriversMysqlOptions extends QueryParserOptions {
|
|
4
4
|
constructor(options) {
|
|
5
5
|
options.columnQuote = "`"
|
|
6
|
+
options.indexQuote = "`"
|
|
6
7
|
options.stringQuote = "'"
|
|
7
8
|
options.tableQuote = "`"
|
|
8
9
|
|
|
@@ -1,25 +1,4 @@
|
|
|
1
|
-
import
|
|
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"
|
|
1
|
+
import BaseQueryParser from "../../query-parser/base-query-parser.mjs"
|
|
5
2
|
|
|
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
|
-
}
|
|
3
|
+
export default class VelociousDatabaseConnectionDriversMysqlQueryParser extends BaseQueryParser {
|
|
25
4
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import Column from "./column.mjs"
|
|
2
|
+
|
|
3
|
+
export default class VelociousDatabaseDriversMysqlTable {
|
|
4
|
+
constructor(driver, data) {
|
|
5
|
+
this.data = data
|
|
6
|
+
this.driver = driver
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async getColumns() {
|
|
10
|
+
const result = await this.driver.query(`SHOW FULL COLUMNS FROM \`${this.getName()}\``)
|
|
11
|
+
const columns = []
|
|
12
|
+
|
|
13
|
+
for (const data of result) {
|
|
14
|
+
const column = new Column(this, data)
|
|
15
|
+
|
|
16
|
+
columns.push(column)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return columns
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getName() {
|
|
23
|
+
return Object.values(this.data)[0]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
|
|
3
|
+
import Base from "../base.mjs"
|
|
4
|
+
import CreateIndex from "../sqlite/sql/create-index.mjs"
|
|
5
|
+
import CreateTable from "../sqlite/sql/create-table.mjs"
|
|
6
|
+
import Delete from "../sqlite/sql/delete.mjs"
|
|
7
|
+
import escapeString from "sql-string-escape"
|
|
8
|
+
import Insert from "../sqlite/sql/insert.mjs"
|
|
9
|
+
import Options from "../sqlite/options.mjs"
|
|
10
|
+
import QueryParser from "../sqlite/query-parser.mjs"
|
|
11
|
+
import Table from "./table"
|
|
12
|
+
import Update from "../sqlite/sql/update.mjs"
|
|
13
|
+
|
|
14
|
+
export default class VelociousDatabaseDriversSqliteBase extends Base {
|
|
15
|
+
createIndexSql(indexData) {
|
|
16
|
+
const createArgs = Object.assign({driver: this}, indexData)
|
|
17
|
+
const createIndex = new CreateIndex(createArgs)
|
|
18
|
+
|
|
19
|
+
return createIndex.toSql()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
createTableSql(tableData) {
|
|
23
|
+
const createArgs = Object.assign({tableData, driver: this, indexInCreateTable: false})
|
|
24
|
+
const createTable = new CreateTable(createArgs)
|
|
25
|
+
|
|
26
|
+
return createTable.toSql()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
deleteSql = ({tableName, conditions}) => new Delete({conditions, driver: this, tableName}).toSql()
|
|
30
|
+
insertSql = ({tableName, data}) => new Insert({driver: this, tableName, data}).toSql()
|
|
31
|
+
|
|
32
|
+
async getTableByName(tableName) {
|
|
33
|
+
const result = await this.query(`SELECT name FROM sqlite_master WHERE type = 'table' AND name = ${this.quote(tableName)} LIMIT 1`)
|
|
34
|
+
const row = result[0]
|
|
35
|
+
|
|
36
|
+
if (!row) {
|
|
37
|
+
const tables = await this.getTables()
|
|
38
|
+
const tableNames = tables.map((table) => table.getName())
|
|
39
|
+
|
|
40
|
+
throw new Error(`No table by that name: ${tableName} in ${tableNames.join(", ")}`)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return new Table({driver: this, row})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async getTables() {
|
|
47
|
+
const result = await this.query("SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name")
|
|
48
|
+
const tables = []
|
|
49
|
+
|
|
50
|
+
for (const row of result) {
|
|
51
|
+
const table = new Table({driver: this, row})
|
|
52
|
+
|
|
53
|
+
tables.push(table)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return tables
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async lastInsertID() {
|
|
60
|
+
const result = await this.query("SELECT LAST_INSERT_ROWID() AS last_insert_id")
|
|
61
|
+
|
|
62
|
+
return digg(result, 0, "last_insert_id")
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
options() {
|
|
66
|
+
if (!this._options) {
|
|
67
|
+
this._options = new Options({driver: this})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return this._options
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
queryToSql = (query) => new QueryParser({query}).toSql()
|
|
74
|
+
|
|
75
|
+
escape(value) {
|
|
76
|
+
const type = typeof value
|
|
77
|
+
|
|
78
|
+
if (type != "string") value = `${value}`
|
|
79
|
+
|
|
80
|
+
const resultWithQuotes = escapeString(value)
|
|
81
|
+
const result = resultWithQuotes.substring(1, resultWithQuotes.length - 1)
|
|
82
|
+
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
quote(value) {
|
|
87
|
+
const type = typeof value
|
|
88
|
+
|
|
89
|
+
if (type == "number") return value
|
|
90
|
+
if (type != "string") value = `${value}`
|
|
91
|
+
|
|
92
|
+
return escapeString(value)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
quoteColumn = (string) => {
|
|
96
|
+
if (string.includes("`")) throw new Error(`Possible SQL injection in column name: ${string}`)
|
|
97
|
+
|
|
98
|
+
return `\`${string}\``
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
quoteTable = (string) => {
|
|
102
|
+
if (string.includes("`")) throw new Error(`Possible SQL injection in table name: ${string}`)
|
|
103
|
+
|
|
104
|
+
return `\`${string}\``
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
updateSql = ({conditions, data, tableName}) => new Update({conditions, data, driver: this, tableName}).toSql()
|
|
108
|
+
}
|
|
@@ -1,23 +1,31 @@
|
|
|
1
|
-
import Base from "../base.mjs"
|
|
2
|
-
import CreateTable from "../sqlite/sql/create-table.mjs"
|
|
3
|
-
import Delete from "../sqlite/sql/delete.mjs"
|
|
4
1
|
import {digg} from "diggerize"
|
|
5
|
-
import
|
|
6
|
-
import Options from "../sqlite/options.mjs"
|
|
7
|
-
import query from "./query.mjs"
|
|
8
|
-
import QueryParser from "../sqlite/query-parser.mjs"
|
|
2
|
+
import query from "./query"
|
|
9
3
|
import * as SQLite from "expo-sqlite"
|
|
10
|
-
import Update from "../sqlite/sql/update.mjs"
|
|
11
4
|
|
|
12
|
-
|
|
5
|
+
import Base from "./base"
|
|
6
|
+
|
|
7
|
+
export default class VelociousDatabaseDriversSqliteNative extends Base {
|
|
13
8
|
async connect() {
|
|
14
|
-
const
|
|
9
|
+
const args = this.getArgs()
|
|
10
|
+
const databaseName = digg(args, "name")
|
|
11
|
+
|
|
12
|
+
if (args.reset) {
|
|
13
|
+
try {
|
|
14
|
+
await SQLite.deleteDatabaseAsync(databaseName)
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error.message.match(/Database '(.+)' not found/)) {
|
|
17
|
+
// Ignore not found
|
|
18
|
+
} else {
|
|
19
|
+
throw error
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
15
23
|
|
|
16
|
-
this.connection =
|
|
24
|
+
this.connection = await SQLite.openDatabaseAsync(databaseName)
|
|
17
25
|
}
|
|
18
26
|
|
|
19
|
-
disconnect() {
|
|
20
|
-
this.connection.
|
|
27
|
+
async disconnect() {
|
|
28
|
+
await this.connection.closeAsync()
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
connectArgs() {
|
|
@@ -39,54 +47,5 @@ export default class VelociousDatabaseDriversSqliteNative extends Base{
|
|
|
39
47
|
this.connection = undefined
|
|
40
48
|
}
|
|
41
49
|
|
|
42
|
-
|
|
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
|
-
}
|
|
50
|
+
query = async (sql) => await query(this.connection, sql)
|
|
92
51
|
}
|
|
@@ -1,64 +1,55 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import Delete from "../sqlite/sql/delete.mjs"
|
|
1
|
+
import BetterLocalStorage from "better-localstorage"
|
|
2
|
+
import debounce from "debounce"
|
|
4
3
|
import {digg} from "diggerize"
|
|
5
|
-
import
|
|
6
|
-
import Options from "../sqlite/options.mjs"
|
|
4
|
+
import initSqlJs from "sql.js"
|
|
7
5
|
import query from "./query"
|
|
8
|
-
import QueryParser from "../sqlite/query-parser.mjs"
|
|
9
|
-
import Update from "../sqlite/sql/update.mjs"
|
|
10
6
|
|
|
11
|
-
import
|
|
7
|
+
import Base from "./base.mjs"
|
|
12
8
|
|
|
13
|
-
export default class VelociousDatabaseDriversSqliteWeb extends Base{
|
|
9
|
+
export default class VelociousDatabaseDriversSqliteWeb extends Base {
|
|
14
10
|
async connect() {
|
|
11
|
+
this.betterLocaleStorage ||= new BetterLocalStorage()
|
|
12
|
+
|
|
13
|
+
const args = this.getArgs()
|
|
14
|
+
|
|
15
|
+
if (args.reset) {
|
|
16
|
+
await this.betterLocaleStorage.delete(this.localStorageName())
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
const SQL = await initSqlJs({
|
|
16
20
|
// 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
21
|
locateFile: (file) => `https://sql.js.org/dist/${file}`
|
|
18
22
|
})
|
|
19
23
|
|
|
20
|
-
const databaseContent =
|
|
24
|
+
const databaseContent = await this.betterLocaleStorage.get(this.localStorageName())
|
|
21
25
|
|
|
22
26
|
this.connection = new SQL.Database(databaseContent)
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
localStorageName = () => `VelociousDatabaseDriversSqliteWeb---${digg(this.getArgs(), "name")}`
|
|
26
30
|
disconnect = () => this.saveDatabase()
|
|
27
|
-
saveDatabase = () =>
|
|
31
|
+
saveDatabase = async () => {
|
|
32
|
+
const localStorageContent = this.connection.export()
|
|
33
|
+
await this.betterLocaleStorage.set(this.localStorageName(), localStorageContent)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
saveDatabaseDebounce = debounce(this.saveDatabase, 500)
|
|
28
37
|
|
|
29
38
|
async close() {
|
|
30
|
-
this.saveDatabase()
|
|
39
|
+
await this.saveDatabase()
|
|
31
40
|
await this.connection.end()
|
|
32
41
|
this.connection = undefined
|
|
33
42
|
}
|
|
34
43
|
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
const
|
|
44
|
+
query = async (sql) => {
|
|
45
|
+
const result = await query(this.connection, sql)
|
|
46
|
+
const downcasedSQL = sql.toLowerCase().trim()
|
|
38
47
|
|
|
39
|
-
|
|
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})
|
|
48
|
+
// Auto-save database in local storage in case we can find manipulating instructions in the SQL
|
|
49
|
+
if (downcasedSQL.startsWith("delete ") || downcasedSQL.startsWith("insert into ") || downcasedSQL.startsWith("update ")) {
|
|
50
|
+
this.saveDatabaseDebounce()
|
|
58
51
|
}
|
|
59
52
|
|
|
60
|
-
return
|
|
53
|
+
return result
|
|
61
54
|
}
|
|
62
|
-
|
|
63
|
-
updateSql = ({conditions, data, tableName}) => new Update({conditions, data, driver: this, tableName}).toSql()
|
|
64
55
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import QueryParserOptions from "../../query-parser/options.mjs"
|
|
2
2
|
|
|
3
|
-
export default class
|
|
3
|
+
export default class VelociousDatabaseDriversSqliteOptions extends QueryParserOptions {
|
|
4
4
|
constructor(options) {
|
|
5
5
|
options.columnQuote = "`"
|
|
6
|
+
options.indexQuote = "`"
|
|
6
7
|
options.stringQuote = "'"
|
|
7
8
|
options.tableQuote = "`"
|
|
8
9
|
|
|
@@ -1,25 +1,4 @@
|
|
|
1
|
-
import
|
|
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"
|
|
1
|
+
import BaseQueryParser from "../../query-parser/base-query-parser.mjs"
|
|
5
2
|
|
|
6
|
-
export default class
|
|
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
|
-
}
|
|
3
|
+
export default class VelociousDatabaseConnectionDriversSqliteQueryParser extends BaseQueryParser {
|
|
25
4
|
}
|
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
export default async function query(connection, sql) {
|
|
2
2
|
const rows = []
|
|
3
|
+
let result
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
try {
|
|
6
|
+
result = await connection.getAllAsync(sql)
|
|
7
|
+
} catch (error) {
|
|
8
|
+
let sqlInErrorMessage = `${sql}`
|
|
9
|
+
|
|
10
|
+
if (sqlInErrorMessage.length >= 4096) {
|
|
11
|
+
sqlInErrorMessage = `${sqlInErrorMessage.substring(0, 4096)}...`
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
error.message += `\n\n${sqlInErrorMessage}`
|
|
15
|
+
|
|
16
|
+
throw error
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for await (const entry of result) {
|
|
5
20
|
rows.push(entry)
|
|
6
21
|
}
|
|
7
22
|
|
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
export default async function query(connection, sql) {
|
|
2
2
|
const rows = []
|
|
3
|
+
let result
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
try {
|
|
6
|
+
result = connection.exec(sql)
|
|
7
|
+
} catch (error) {
|
|
8
|
+
let sqlInErrorMessage = `${sql}`
|
|
9
|
+
|
|
10
|
+
if (sqlInErrorMessage.length >= 4096) {
|
|
11
|
+
sqlInErrorMessage = `${sqlInErrorMessage.substring(0, 4096)}...`
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
error.message += `\n\n${sqlInErrorMessage}`
|
|
15
|
+
|
|
16
|
+
throw error
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (result[0]) {
|
|
20
|
+
const columns = result[0].columns
|
|
21
|
+
|
|
22
|
+
for (const rowValues of result[0].values) {
|
|
23
|
+
const row = {}
|
|
24
|
+
|
|
25
|
+
for (const columnIndex in columns) {
|
|
26
|
+
row[columns[columnIndex]] = rowValues[columnIndex]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
rows.push(row)
|
|
30
|
+
}
|
|
6
31
|
}
|
|
7
32
|
|
|
8
33
|
return rows
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Column from "./column.mjs"
|
|
2
|
+
import {digg} from "diggerize"
|
|
3
|
+
|
|
4
|
+
export default class VelociousDatabaseDriversSqliteTable {
|
|
5
|
+
constructor({driver, row}) {
|
|
6
|
+
this.driver = driver
|
|
7
|
+
this.row = row
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
getColumns = async () => {
|
|
11
|
+
const result = await this.driver.query(`PRAGMA table_info('${this.getName()}')`)
|
|
12
|
+
const columns = []
|
|
13
|
+
|
|
14
|
+
for (const columnData of result) {
|
|
15
|
+
const column = new Column({column: columnData, driver: this.driver, table: this})
|
|
16
|
+
|
|
17
|
+
columns.push(column)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return columns
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getName = () => digg(this, "row", "name")
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default class VelociousDatabaseInitializerFromRequireContext {
|
|
2
|
+
constructor({requireContext, ...restProps}) {
|
|
3
|
+
const restPropsKeys = Object.keys(restProps)
|
|
4
|
+
|
|
5
|
+
if (restPropsKeys.length > 0) throw new Error(`Unknown arguments: ${restPropsKeys.join(", ")}`)
|
|
6
|
+
|
|
7
|
+
this.requireContext = requireContext
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async initialize({configuration}) {
|
|
11
|
+
for (const fileName of this.requireContext.keys()) {
|
|
12
|
+
const modelClass = this.requireContext(fileName).default
|
|
13
|
+
|
|
14
|
+
await modelClass.initializeRecord({configuration})
|
|
15
|
+
|
|
16
|
+
if (await modelClass.hasTranslationsTable()) {
|
|
17
|
+
await modelClass.getTranslationClass().initializeRecord({configuration})
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Configuration from "../configuration.mjs"
|
|
2
2
|
import * as inflection from "inflection"
|
|
3
|
+
import Migrator from "./migrator"
|
|
3
4
|
|
|
4
5
|
export default class VelociousDatabaseMigrateFromRequireContext {
|
|
5
6
|
constructor(configuration) {
|
|
@@ -7,6 +8,10 @@ export default class VelociousDatabaseMigrateFromRequireContext {
|
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
async execute(requireContext) {
|
|
11
|
+
const migrator = new Migrator({configuration: this.configuration})
|
|
12
|
+
|
|
13
|
+
await migrator.prepare()
|
|
14
|
+
|
|
10
15
|
const files = requireContext.keys()
|
|
11
16
|
.map((file) => {
|
|
12
17
|
const match = file.match(/^\.\/(\d{14})-(.+)\.mjs$/)
|
|
@@ -27,7 +32,9 @@ export default class VelociousDatabaseMigrateFromRequireContext {
|
|
|
27
32
|
.sort((migration1, migration2) => migration1.date - migration2.date)
|
|
28
33
|
|
|
29
34
|
for (const migration of files) {
|
|
30
|
-
|
|
35
|
+
if (!migrator.hasRunMigrationVersion(migration.date)) {
|
|
36
|
+
await this.runMigrationFile(migration, requireContext)
|
|
37
|
+
}
|
|
31
38
|
}
|
|
32
39
|
}
|
|
33
40
|
|
|
@@ -35,7 +42,7 @@ export default class VelociousDatabaseMigrateFromRequireContext {
|
|
|
35
42
|
if (!this.configuration) throw new Error("No configuration set")
|
|
36
43
|
if (!this.configuration.isDatabasePoolInitialized()) await this.configuration.initializeDatabasePool()
|
|
37
44
|
|
|
38
|
-
await this.configuration.getDatabasePool().withConnection(async () => {
|
|
45
|
+
await this.configuration.getDatabasePool().withConnection(async (db) => {
|
|
39
46
|
const MigrationClass = requireContext(migration.file).default
|
|
40
47
|
const migrationInstance = new MigrationClass({
|
|
41
48
|
configuration: this.configuration
|
|
@@ -48,6 +55,8 @@ export default class VelociousDatabaseMigrateFromRequireContext {
|
|
|
48
55
|
} else {
|
|
49
56
|
throw new Error(`'change' or 'up' didn't exist on migration: ${migration.file}`)
|
|
50
57
|
}
|
|
58
|
+
|
|
59
|
+
await db.insert({tableName: "schema_migrations", data: {version: migration.date}})
|
|
51
60
|
})
|
|
52
61
|
}
|
|
53
62
|
}
|
|
@@ -5,14 +5,46 @@ export default class VelociousDatabaseMigration {
|
|
|
5
5
|
this.configuration = configuration
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
async addIndex(tableName, columns, args) {
|
|
9
|
+
const databasePool = this.configuration.getDatabasePool()
|
|
10
|
+
const createIndexArgs = Object.assign(
|
|
11
|
+
{
|
|
12
|
+
columns,
|
|
13
|
+
tableName
|
|
14
|
+
},
|
|
15
|
+
args
|
|
16
|
+
)
|
|
17
|
+
const sql = databasePool.createIndexSql(createIndexArgs)
|
|
18
|
+
|
|
19
|
+
await databasePool.query(sql)
|
|
20
|
+
}
|
|
21
|
+
|
|
8
22
|
async createTable(tableName, callback) {
|
|
9
23
|
const tableData = new TableData(tableName)
|
|
10
24
|
|
|
25
|
+
tableData.integer("id", {null: false, primaryKey: true})
|
|
26
|
+
|
|
11
27
|
callback(tableData)
|
|
12
28
|
|
|
13
29
|
const databasePool = this.configuration.getDatabasePool()
|
|
14
|
-
const
|
|
30
|
+
const sqls = databasePool.createTableSql(tableData)
|
|
15
31
|
|
|
16
|
-
|
|
32
|
+
for (const sql of sqls) {
|
|
33
|
+
await databasePool.query(sql)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getConnection() {
|
|
38
|
+
const connection = this.configuration.getDatabasePool().getCurrentConnection()
|
|
39
|
+
|
|
40
|
+
if (!connection) throw new Error("Couldn't get current connection")
|
|
41
|
+
|
|
42
|
+
return connection
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async tableExists(tableName) {
|
|
46
|
+
const exists = await this.getConnection().tableExists(tableName)
|
|
47
|
+
|
|
48
|
+
return exists
|
|
17
49
|
}
|
|
18
50
|
}
|