velocious 1.0.8 → 1.0.10

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.8",
6
+ "version": "1.0.10",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "test": "jasmine",
@@ -69,6 +69,31 @@ export default class VelociousDatabaseDriversBase {
69
69
  this.idSeq = id
70
70
  }
71
71
 
72
+ async tableExists(tableName) {
73
+ const tables = await this.getTables()
74
+ const table = tables.find((table) => table.getName() == tableName)
75
+
76
+ if (table) return true
77
+
78
+ return false
79
+ }
80
+
81
+ async transaction(callback) {
82
+ await this.query("BEGIN TRANSACTION")
83
+
84
+ let result
85
+
86
+ try {
87
+ result = await callback()
88
+ await this.query("COMMIT")
89
+ } catch (error) {
90
+ this.query("ROLLBACK")
91
+ throw error
92
+ }
93
+
94
+ return result
95
+ }
96
+
72
97
  async update(...args) {
73
98
  const sql = this.updateSql(...args)
74
99
 
@@ -93,8 +93,9 @@ export default class VelociousDatabaseDriversMysql extends Base{
93
93
  return deleteInstruction.toSql()
94
94
  }
95
95
 
96
- insertSql({tableName, data}) {
97
- const insert = new Insert({driver: this, tableName, data})
96
+ insertSql(args) {
97
+ const insertArgs = Object.assign({driver: this}, args)
98
+ const insert = new Insert(insertArgs)
98
99
 
99
100
  return insert.toSql()
100
101
  }
@@ -1,29 +1,4 @@
1
1
  import InsertBase from "../../../query/insert-base.js"
2
2
 
3
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
4
  }
@@ -34,8 +34,8 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
34
34
  return createTable.toSql()
35
35
  }
36
36
 
37
- deleteSql = ({tableName, conditions}) => new Delete({conditions, driver: this, tableName}).toSql()
38
- insertSql = ({tableName, data}) => new Insert({driver: this, tableName, data}).toSql()
37
+ deleteSql = (args) => new Delete(Object.assign({driver: this}, args)).toSql()
38
+ insertSql = (args) => new Insert(Object.assign({driver: this}, args)).toSql()
39
39
 
40
40
  async getTableByName(tableName) {
41
41
  const result = await this.query(`SELECT name FROM sqlite_master WHERE type = 'table' AND name = ${this.quote(tableName)} LIMIT 1`)
@@ -64,6 +64,53 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
64
64
  return tables
65
65
  }
66
66
 
67
+ async insertMultiple(...args) {
68
+ if (this.supportsMultipleInsertValues()) {
69
+ return await this.insertMultipleWithSingleInsert(...args)
70
+ } else {
71
+ return await this.insertMultipleWithTransaction(...args)
72
+ }
73
+ }
74
+
75
+ supportsMultipleInsertValues() {
76
+ if (this.versionMajor >= 4) return true
77
+ if (this.versionMajor == 3 && this.versionMinor >= 8) return true
78
+ if (this.versionMajor == 3 && this.versionMinor == 7 && this.versionPatch >= 11) return true
79
+
80
+ return false
81
+ }
82
+
83
+ async insertMultipleWithSingleInsert(tableName, columns, rows) {
84
+ const sql = new Insert({columns, driver: this, rows, tableName}).toSql()
85
+
86
+ return await this.query(sql)
87
+ }
88
+
89
+ async insertMultipleWithTransaction(tableName, columns, rows) {
90
+ const sqls = []
91
+
92
+ for (const row of rows) {
93
+ const data = []
94
+
95
+ for (const columnIndex in columns) {
96
+ const columnName = columns[columnIndex]
97
+ const value = row[columnIndex]
98
+
99
+ data[columnName] = value
100
+ }
101
+
102
+ const insertSql = this.insertSql({tableName, data})
103
+
104
+ sqls.push(insertSql)
105
+ }
106
+
107
+ await this.transaction(async () => {
108
+ for (const sql of sqls) {
109
+ await this.query(sql)
110
+ }
111
+ })
112
+ }
113
+
67
114
  async lastInsertID() {
68
115
  const result = await this.query("SELECT LAST_INSERT_ROWID() AS last_insert_id")
69
116
 
@@ -80,6 +127,18 @@ export default class VelociousDatabaseDriversSqliteBase extends Base {
80
127
 
81
128
  queryToSql = (query) => new QueryParser({query}).toSql()
82
129
 
130
+ async registerVersion() {
131
+ const versionResult = await this.query("SELECT sqlite_version() AS version")
132
+
133
+ this.version = versionResult[0].version
134
+
135
+ const versionParts = this.version.split(".")
136
+
137
+ this.versionMajor = versionParts[0]
138
+ this.versionMinor = versionParts[1]
139
+ this.versionPatch = versionParts[2]
140
+ }
141
+
83
142
  escape(value) {
84
143
  const type = typeof value
85
144
 
@@ -22,6 +22,7 @@ export default class VelociousDatabaseDriversSqliteNative extends Base {
22
22
  }
23
23
 
24
24
  this.connection = await SQLite.openDatabaseAsync(databaseName)
25
+ await this.registerVersion()
25
26
  }
26
27
 
27
28
  async disconnect() {
@@ -24,6 +24,7 @@ export default class VelociousDatabaseDriversSqliteWeb extends Base {
24
24
  const databaseContent = await this.betterLocaleStorage.get(this.localStorageName())
25
25
 
26
26
  this.connection = new SQL.Database(databaseContent)
27
+ await this.registerVersion()
27
28
  }
28
29
 
29
30
  localStorageName = () => `VelociousDatabaseDriversSqliteWeb---${digg(this.getArgs(), "name")}`
@@ -1,29 +1,4 @@
1
1
  import InsertBase from "../../../query/insert-base.js"
2
2
 
3
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
4
  }
@@ -5,12 +5,11 @@ import Migrator from "./migrator"
5
5
  export default class VelociousDatabaseMigrateFromRequireContext {
6
6
  constructor(configuration) {
7
7
  this.configuration = configuration || Configuration.current()
8
+ this.migrator = new Migrator({configuration: this.configuration})
8
9
  }
9
10
 
10
11
  async execute(requireContext) {
11
- const migrator = new Migrator({configuration: this.configuration})
12
-
13
- await migrator.prepare()
12
+ await this.migrator.prepare()
14
13
 
15
14
  const files = requireContext.keys()
16
15
  .map((file) => {
@@ -32,7 +31,7 @@ export default class VelociousDatabaseMigrateFromRequireContext {
32
31
  .sort((migration1, migration2) => migration1.date - migration2.date)
33
32
 
34
33
  for (const migration of files) {
35
- if (!migrator.hasRunMigrationVersion(migration.date)) {
34
+ if (!this.migrator.hasRunMigrationVersion(migration.date)) {
36
35
  await this.runMigrationFile(migration, requireContext)
37
36
  }
38
37
  }
@@ -1,11 +1,17 @@
1
+ import restArgsError from "../../utils/rest-args-error.js"
2
+
1
3
  export default class VelociousDatabaseQueryInsertBase {
2
- constructor({driver, tableName, data}) {
4
+ constructor({columns, data, driver, multiple, tableName, rows, ...restArgs}) {
3
5
  if (!driver) throw new Error("No driver given to insert base")
4
6
  if (!tableName) throw new Error(`Invalid table name given to insert base: ${tableName}`)
5
- if (!data) throw new Error("No data given to insert base")
6
7
 
8
+ restArgsError(restArgs)
9
+
10
+ this.columns = columns
7
11
  this.data = data
8
12
  this.driver = driver
13
+ this.multiple = multiple
14
+ this.rows = rows
9
15
  this.tableName = tableName
10
16
  }
11
17
 
@@ -14,6 +20,56 @@ export default class VelociousDatabaseQueryInsertBase {
14
20
  }
15
21
 
16
22
  toSql() {
17
- throw new Error("'toSql' wasn't implemented")
23
+ let sql = `INSERT INTO ${this.getOptions().quoteTableName(this.tableName)} (`
24
+ let count = 0
25
+ let columns
26
+
27
+ if (this.columns && this.rows) {
28
+ columns = this.columns
29
+ } else if (this.data) {
30
+ columns = Object.keys(this.data)
31
+ } else {
32
+ throw new Error("Neither 'column' and 'rows' or data was given")
33
+ }
34
+
35
+ for (const columnName of columns) {
36
+ if (count > 0) sql += ", "
37
+
38
+ sql += this.getOptions().quoteColumnName(columnName)
39
+ count++
40
+ }
41
+
42
+ sql += ") VALUES "
43
+
44
+ if (this.columns && this.rows) {
45
+ let count = 0
46
+
47
+ for (const row of this.rows) {
48
+ if (count >= 1) sql += ", "
49
+
50
+ count++
51
+ sql += this._valuesSql(row)
52
+ }
53
+ } else {
54
+ sql += this._valuesSql(Object.values(this.data))
55
+ }
56
+
57
+ return sql
58
+ }
59
+
60
+ _valuesSql(data) {
61
+ let count = 0
62
+ let sql = "("
63
+
64
+ for (const value of data) {
65
+ if (count > 0) sql += ", "
66
+
67
+ sql += this.getOptions().quote(value)
68
+ count++
69
+ }
70
+
71
+ sql += ")"
72
+
73
+ return sql
18
74
  }
19
75
  }
@@ -19,6 +19,7 @@ export default class VelociousDatabaseRecord {
19
19
  }
20
20
 
21
21
  static _defineRelationship(relationshipName, data) {
22
+ if (!relationshipName) throw new Error(`Invalid relationship name given: ${relationshipName}`)
22
23
  if (!this._relationships) this._relationships = {}
23
24
  if (this._relationshipExists(relationshipName)) throw new Error(`Relationship ${relationshipName} already exists`)
24
25
 
@@ -77,6 +78,12 @@ export default class VelociousDatabaseRecord {
77
78
  return relationship
78
79
  }
79
80
 
81
+ static getRelationships() {
82
+ if (this._relationships) return Object.values(this._relationships)
83
+
84
+ return []
85
+ }
86
+
80
87
  getRelationshipByName(relationshipName) {
81
88
  if (!this._instanceRelationships) this._instanceRelationships = {}
82
89
 
@@ -269,6 +276,10 @@ export default class VelociousDatabaseRecord {
269
276
  return this._table
270
277
  }
271
278
 
279
+ static async insertMultiple(columns, rows) {
280
+ return await this.connection().insertMultiple(this.tableName(), columns, rows)
281
+ }
282
+
272
283
  static async last() {
273
284
  const query = this._newQuery().order(this.primaryKey())
274
285
  const record = await query.last()
@@ -308,7 +319,7 @@ export default class VelociousDatabaseRecord {
308
319
 
309
320
  const model = instanceRelationship.loaded()
310
321
 
311
- if (model.isChanged()) {
322
+ if (model?.isChanged()) {
312
323
  await model.save()
313
324
 
314
325
  const foreignKey = instanceRelationship.getForeignKey()
@@ -409,9 +420,11 @@ export default class VelociousDatabaseRecord {
409
420
  }
410
421
 
411
422
  _setTranslatedAttribute(name, locale, newValue) {
412
- let translation = this.translations().loaded()?.find((translation) =>translation.locale() == locale)
423
+ let translation = this.translations().loaded()?.find((translation) => translation.locale() == locale)
413
424
 
414
- if (!translation) translation = this.translations().build({locale})
425
+ if (!translation) {
426
+ translation = this.translations().build({locale})
427
+ }
415
428
 
416
429
  const assignments = {}
417
430
 
@@ -513,7 +526,7 @@ export default class VelociousDatabaseRecord {
513
526
  _hasChanges = () => Object.keys(this._changes).length > 0
514
527
 
515
528
  isChanged() {
516
- if (this.isNewRecord() || this._hasChanges()) {
529
+ if (this.isNewRecord() || this._hasChanges()){
517
530
  return true
518
531
  }
519
532
 
@@ -537,6 +550,18 @@ export default class VelociousDatabaseRecord {
537
550
  return false
538
551
  }
539
552
 
553
+ changes() {
554
+ const changes = {}
555
+
556
+ for (const changeKey in this._changes) {
557
+ const changeValue = this._changes[changeKey]
558
+
559
+ changes[changeKey] = [this._attributes[changeKey], changeValue]
560
+ }
561
+
562
+ return changes
563
+ }
564
+
540
565
  _tableName() {
541
566
  if (this.__tableName) return this.__tableName
542
567
 
@@ -569,6 +594,13 @@ export default class VelociousDatabaseRecord {
569
594
 
570
595
  await this._reloadWithId(id)
571
596
  this.setIsNewRecord(false)
597
+
598
+ // Mark all relationships as preloaded, since we don't expect anything to have magically appeared since we created the record.
599
+ for (const relationship of this.constructor.getRelationships()) {
600
+ const instanceRelationship = this.getRelationshipByName(relationship.getRelationshipName())
601
+
602
+ instanceRelationship.setPreloaded(true)
603
+ }
572
604
  }
573
605
 
574
606
  async _updateRecordWithChanges() {
@@ -39,9 +39,5 @@ export default class VelociousDatabaseRecordHasManyInstanceRelationship extends
39
39
  this._loaded = models
40
40
  }
41
41
 
42
- setPreloaded(preloadedValue) {
43
- this._preloaded = preloadedValue
44
- }
45
-
46
42
  getTargetModelClass = () => this.relationship.getTargetModelClass()
47
43
  }