velocious 1.0.15 → 1.0.17
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/destroy-spec.js +15 -0
- package/src/database/drivers/sqlite/base.js +6 -0
- package/src/database/drivers/sqlite/column.js +7 -3
- package/src/database/drivers/sqlite/connection-remote.js +5 -0
- package/src/database/drivers/sqlite/connection-sql-js.js +37 -0
- package/src/database/drivers/sqlite/index.js +7 -2
- package/src/database/drivers/sqlite/index.native.js +4 -1
- package/src/database/drivers/sqlite/index.web.js +28 -34
- package/src/database/drivers/sqlite/table.js +7 -2
- package/src/database/query/index.js +8 -0
- package/src/database/record/index.js +45 -0
- package/src/database/record/relationships/base.js +3 -1
- package/src/logger.js +5 -1
package/package.json
CHANGED
|
@@ -14,4 +14,19 @@ describe("Record - destroy", () => {
|
|
|
14
14
|
expect(foundTask).toEqual(undefined)
|
|
15
15
|
})
|
|
16
16
|
})
|
|
17
|
+
|
|
18
|
+
it("destroys all records in a collection", async () => {
|
|
19
|
+
await Dummy.run(async () => {
|
|
20
|
+
const task1 = await Task.create({name: "Test task 1"})
|
|
21
|
+
const task2 = await Task.create({name: "Test task 2"})
|
|
22
|
+
|
|
23
|
+
await Task.where({id: task1.id()}).destroyAll()
|
|
24
|
+
|
|
25
|
+
const foundTask1 = await Task.where({id: task1.id()}).first()
|
|
26
|
+
const foundTask2 = await Task.where({id: task2.id()}).first()
|
|
27
|
+
|
|
28
|
+
expect(foundTask1).toEqual(undefined)
|
|
29
|
+
expect(foundTask2).toBeDefined()
|
|
30
|
+
})
|
|
31
|
+
})
|
|
17
32
|
})
|
|
@@ -66,6 +66,8 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
async insertMultiple(...args) {
|
|
69
|
+
await this.registerVersion()
|
|
70
|
+
|
|
69
71
|
if (this.supportsMultipleInsertValues()) {
|
|
70
72
|
return await this.insertMultipleWithSingleInsert(...args)
|
|
71
73
|
} else {
|
|
@@ -130,6 +132,10 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
|
|
|
130
132
|
queryToSql = (query) => new QueryParser({query}).toSql()
|
|
131
133
|
|
|
132
134
|
async registerVersion() {
|
|
135
|
+
if (this.versionMajor || this.versionMinor) {
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
133
139
|
const versionResult = await this.query("SELECT sqlite_version() AS version")
|
|
134
140
|
|
|
135
141
|
this.version = versionResult[0].version
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import {digg} from "diggerize"
|
|
2
|
-
|
|
3
1
|
export default class VelociousDatabaseDriversSqliteColumn {
|
|
4
2
|
constructor({column, driver}) {
|
|
5
3
|
this.column = column
|
|
6
4
|
this.driver = driver
|
|
7
5
|
}
|
|
8
6
|
|
|
9
|
-
getName
|
|
7
|
+
getName() {
|
|
8
|
+
if (!this.column.name) {
|
|
9
|
+
throw new Error("No name given for SQLite column")
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return this.column.name
|
|
13
|
+
}
|
|
10
14
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import debounce from "debounce"
|
|
2
|
+
import query from "./query"
|
|
3
|
+
|
|
4
|
+
export default class VelociousDatabaseDriversSqliteConnectionSqlJs {
|
|
5
|
+
constructor(driver, connection) {
|
|
6
|
+
this.connection = connection
|
|
7
|
+
this.driver = driver
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async close() {
|
|
11
|
+
await this.saveDatabase()
|
|
12
|
+
await this.connection.end()
|
|
13
|
+
this.connection = undefined
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
disconnect = () => this.saveDatabase()
|
|
17
|
+
|
|
18
|
+
async query(sql) {
|
|
19
|
+
const result = await query(this.connection, sql)
|
|
20
|
+
const downcasedSQL = sql.toLowerCase().trim()
|
|
21
|
+
|
|
22
|
+
// Auto-save database in local storage in case we can find manipulating instructions in the SQL
|
|
23
|
+
if (downcasedSQL.startsWith("delete ") || downcasedSQL.startsWith("insert into ") || downcasedSQL.startsWith("update ")) {
|
|
24
|
+
this.saveDatabaseDebounce()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return result
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
saveDatabase = async () => {
|
|
31
|
+
const localStorageContent = this.connection.export()
|
|
32
|
+
|
|
33
|
+
await this.driver.betterLocalStorage.set(this.driver.localStorageName(), localStorageContent)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
saveDatabaseDebounce = debounce(this.saveDatabase, 500)
|
|
37
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {digg} from "diggerize"
|
|
2
1
|
import fs from "fs/promises"
|
|
3
2
|
import query from "./query.js"
|
|
4
3
|
import sqlite3 from "sqlite3"
|
|
@@ -22,7 +21,13 @@ export default class VelociousDatabaseDriversSqliteNode extends Base {
|
|
|
22
21
|
await this.registerVersion()
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
localStorageName
|
|
24
|
+
localStorageName() {
|
|
25
|
+
const args = this.getArgs()
|
|
26
|
+
|
|
27
|
+
if (!args.name) throw new Error("No name given for SQLite Node")
|
|
28
|
+
|
|
29
|
+
return `VelociousDatabaseDriversSqlite---${args.name}`
|
|
30
|
+
}
|
|
26
31
|
|
|
27
32
|
async close() {
|
|
28
33
|
await this.connection.close()
|
|
@@ -7,7 +7,10 @@ import Base from "./base"
|
|
|
7
7
|
export default class VelociousDatabaseDriversSqliteNative extends Base {
|
|
8
8
|
async connect() {
|
|
9
9
|
const args = this.getArgs()
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
if (!args.name) throw new Error("No name given for SQLite Native")
|
|
12
|
+
|
|
13
|
+
const databaseName = args.name
|
|
11
14
|
|
|
12
15
|
if (args.reset) {
|
|
13
16
|
try {
|
|
@@ -1,56 +1,50 @@
|
|
|
1
1
|
import BetterLocalStorage from "better-localstorage"
|
|
2
|
-
import
|
|
2
|
+
import ConnectionSqlJs from "./connection-sql-js"
|
|
3
3
|
import {digg} from "diggerize"
|
|
4
4
|
import initSqlJs from "sql.js"
|
|
5
|
-
import query from "./query"
|
|
6
5
|
|
|
7
6
|
import Base from "./base.js"
|
|
8
7
|
|
|
9
8
|
export default class VelociousDatabaseDriversSqliteWeb extends Base {
|
|
10
9
|
async connect() {
|
|
11
|
-
this.
|
|
10
|
+
this.args = this.getArgs()
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
if (!this.args.getConnection) {
|
|
13
|
+
this.betterLocalStorage ||= new BetterLocalStorage()
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const SQL = await initSqlJs({
|
|
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.
|
|
21
|
-
locateFile: (file) => `https://sql.js.org/dist/${file}`
|
|
22
|
-
})
|
|
15
|
+
if (this.args.reset) {
|
|
16
|
+
await this.betterLocalStorage.delete(this.localStorageName())
|
|
17
|
+
}
|
|
23
18
|
|
|
24
|
-
|
|
19
|
+
const SQL = await initSqlJs({
|
|
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.
|
|
21
|
+
locateFile: (file) => `https://sql.js.org/dist/${file}`
|
|
22
|
+
})
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
24
|
+
const databaseContent = await this.betterLocalStorage.get(this.localStorageName())
|
|
25
|
+
const connectionSqlJs = new ConnectionSqlJs(this, new SQL.Database(databaseContent))
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
saveDatabase = async () => {
|
|
33
|
-
const localStorageContent = this.connection.export()
|
|
34
|
-
await this.betterLocaleStorage.set(this.localStorageName(), localStorageContent)
|
|
27
|
+
this._connection = connectionSqlJs
|
|
28
|
+
}
|
|
35
29
|
}
|
|
36
30
|
|
|
37
|
-
|
|
31
|
+
close = async () => await this.getConnection().close()
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
getConnection() {
|
|
34
|
+
if (this.args.getConnection) {
|
|
35
|
+
return this.args.getConnection()
|
|
36
|
+
} else {
|
|
37
|
+
return this._connection
|
|
38
|
+
}
|
|
43
39
|
}
|
|
44
40
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// Auto-save database in local storage in case we can find manipulating instructions in the SQL
|
|
50
|
-
if (downcasedSQL.startsWith("delete ") || downcasedSQL.startsWith("insert into ") || downcasedSQL.startsWith("update ")) {
|
|
51
|
-
this.saveDatabaseDebounce()
|
|
41
|
+
localStorageName() {
|
|
42
|
+
if (!this.args.name) {
|
|
43
|
+
throw new Error("No name given in arguments for SQLite Web database")
|
|
52
44
|
}
|
|
53
45
|
|
|
54
|
-
return
|
|
46
|
+
return `VelociousDatabaseDriversSqliteWeb---${this.args.name}`
|
|
55
47
|
}
|
|
48
|
+
|
|
49
|
+
query = async (sql) => await this.getConnection().query(sql)
|
|
56
50
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import Column from "./column.js"
|
|
2
|
-
import {digg} from "diggerize"
|
|
3
2
|
import ForeignKey from "./foreign-key.js"
|
|
4
3
|
|
|
5
4
|
export default class VelociousDatabaseDriversSqliteTable {
|
|
@@ -34,5 +33,11 @@ export default class VelociousDatabaseDriversSqliteTable {
|
|
|
34
33
|
return foreignKeys
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
getName
|
|
36
|
+
getName() {
|
|
37
|
+
if (!this.row.name) {
|
|
38
|
+
throw new Error("No name given for SQLite table")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return this.row.name
|
|
42
|
+
}
|
|
38
43
|
}
|
|
@@ -47,6 +47,14 @@ export default class VelociousDatabaseQuery {
|
|
|
47
47
|
|
|
48
48
|
getOptions = () => this.driver.options()
|
|
49
49
|
|
|
50
|
+
async destroyAll() {
|
|
51
|
+
const records = await this.toArray()
|
|
52
|
+
|
|
53
|
+
for (const record of records) {
|
|
54
|
+
await record.destroy()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
50
58
|
async find(recordId) {
|
|
51
59
|
const conditions = {}
|
|
52
60
|
|
|
@@ -457,6 +457,10 @@ export default class VelociousDatabaseRecord {
|
|
|
457
457
|
return this._newQuery()
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
+
static async destroyAll(...args) {
|
|
461
|
+
return this._newQuery().destroyAll(...args)
|
|
462
|
+
}
|
|
463
|
+
|
|
460
464
|
static async find(...args) {
|
|
461
465
|
return this._newQuery().find(...args)
|
|
462
466
|
}
|
|
@@ -477,6 +481,14 @@ export default class VelociousDatabaseRecord {
|
|
|
477
481
|
return this._newQuery().joins(...args)
|
|
478
482
|
}
|
|
479
483
|
|
|
484
|
+
static limit(...args) {
|
|
485
|
+
return this._newQuery().limit(...args)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
static order(...args) {
|
|
489
|
+
return this._newQuery().order(...args)
|
|
490
|
+
}
|
|
491
|
+
|
|
480
492
|
static preload(...args) {
|
|
481
493
|
return this._newQuery().preload(...args)
|
|
482
494
|
}
|
|
@@ -518,6 +530,39 @@ export default class VelociousDatabaseRecord {
|
|
|
518
530
|
}
|
|
519
531
|
|
|
520
532
|
async destroy() {
|
|
533
|
+
for (const relationship of this.constructor.getRelationships()) {
|
|
534
|
+
if (relationship.getDependent() != "destroy") {
|
|
535
|
+
continue
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const instanceRelationship = this.getRelationshipByName(relationship.getRelationshipName())
|
|
539
|
+
let models
|
|
540
|
+
|
|
541
|
+
if (instanceRelationship.getType() == "belongsTo") {
|
|
542
|
+
if (!instanceRelationship.isLoaded()) {
|
|
543
|
+
await instanceRelationship.load()
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const model = instanceRelationship.loaded()
|
|
547
|
+
|
|
548
|
+
models = [model]
|
|
549
|
+
} else if (instanceRelationship.getType() == "hasMany") {
|
|
550
|
+
if (!instanceRelationship.isLoaded()) {
|
|
551
|
+
await instanceRelationship.load()
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
models = instanceRelationship.loaded()
|
|
555
|
+
} else {
|
|
556
|
+
throw new Error(`Unhandled relationship type: ${instanceRelationship.getType()}`)
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
for (const model of models) {
|
|
560
|
+
if (model.isPersisted()) {
|
|
561
|
+
await model.destroy()
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
521
566
|
const conditions = {}
|
|
522
567
|
|
|
523
568
|
conditions[this.constructor.primaryKey()] = this.id()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default class VelociousDatabaseRecordBaseRelationship {
|
|
2
|
-
constructor({className, configuration, foreignKey, klass, modelClass, relationshipName, through, type, ...restArgs}) {
|
|
2
|
+
constructor({className, configuration, dependent, foreignKey, klass, modelClass, relationshipName, through, type, ...restArgs}) {
|
|
3
3
|
const restArgsKeys = Object.keys(restArgs)
|
|
4
4
|
|
|
5
5
|
if (restArgsKeys.length > 0) throw new Error(`Unknown args given: ${restArgsKeys.join(", ")}`)
|
|
@@ -8,6 +8,7 @@ export default class VelociousDatabaseRecordBaseRelationship {
|
|
|
8
8
|
|
|
9
9
|
this.className = className
|
|
10
10
|
this.configuration = configuration
|
|
11
|
+
this._dependent = dependent
|
|
11
12
|
this.foreignKey = foreignKey
|
|
12
13
|
this.klass = klass
|
|
13
14
|
this.modelClass = modelClass
|
|
@@ -16,6 +17,7 @@ export default class VelociousDatabaseRecordBaseRelationship {
|
|
|
16
17
|
this.type = type
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
getDependent = () => this._dependent
|
|
19
21
|
getRelationshipName = () => this.relationshipName
|
|
20
22
|
getPrimaryKey = () => "id" // TODO: Support custom given primary key
|
|
21
23
|
getType = () => this.type
|
package/src/logger.js
CHANGED
|
@@ -4,7 +4,11 @@ export default function log(object, ...messages) {
|
|
|
4
4
|
if (!object.configuration) console.error(`No configuration on ${object.constructor.name}`)
|
|
5
5
|
|
|
6
6
|
if (object.configuration?.debug) {
|
|
7
|
-
|
|
7
|
+
if (!object.constructor.name) {
|
|
8
|
+
throw new Error(`No constructor name for object`)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const className = object.constructor.name
|
|
8
12
|
|
|
9
13
|
console.log(className, ...messages)
|
|
10
14
|
}
|