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 CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.15",
6
+ "version": "1.0.17",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "test": "jasmine",
@@ -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 = () => digg(this, "column", "name")
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,5 @@
1
+ export default class VelociousDatabaseDriversSqliteConnectionRemote {
2
+ async query(sql) {
3
+ throw new Error("stub")
4
+ }
5
+ }
@@ -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 = () => `VelociousDatabaseDriversSqlite---${digg(this.getArgs(), "name")}`
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
- const databaseName = digg(args, "name")
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 debounce from "debounce"
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.betterLocaleStorage ||= new BetterLocalStorage()
10
+ this.args = this.getArgs()
12
11
 
13
- const args = this.getArgs()
12
+ if (!this.args.getConnection) {
13
+ this.betterLocalStorage ||= new BetterLocalStorage()
14
14
 
15
- if (args.reset) {
16
- await this.betterLocaleStorage.delete(this.localStorageName())
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
- const databaseContent = await this.betterLocaleStorage.get(this.localStorageName())
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
- this.connection = new SQL.Database(databaseContent)
27
- await this.registerVersion()
28
- }
24
+ const databaseContent = await this.betterLocalStorage.get(this.localStorageName())
25
+ const connectionSqlJs = new ConnectionSqlJs(this, new SQL.Database(databaseContent))
29
26
 
30
- localStorageName = () => `VelociousDatabaseDriversSqliteWeb---${digg(this.getArgs(), "name")}`
31
- disconnect = () => this.saveDatabase()
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
- saveDatabaseDebounce = debounce(this.saveDatabase, 500)
31
+ close = async () => await this.getConnection().close()
38
32
 
39
- async close() {
40
- await this.saveDatabase()
41
- await this.connection.end()
42
- this.connection = undefined
33
+ getConnection() {
34
+ if (this.args.getConnection) {
35
+ return this.args.getConnection()
36
+ } else {
37
+ return this._connection
38
+ }
43
39
  }
44
40
 
45
- query = async (sql) => {
46
- const result = await query(this.connection, sql)
47
- const downcasedSQL = sql.toLowerCase().trim()
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 result
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 = () => digg(this, "row", "name")
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
- const className = digg(object, "constructor", "name")
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
  }