velocious 1.0.10 → 1.0.12

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.10",
6
+ "version": "1.0.12",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "test": "jasmine",
@@ -0,0 +1,24 @@
1
+ import Dummy from "../../dummy/index.js"
2
+ import Task from "../../dummy/src/models/task.js"
3
+
4
+ describe("Record - create", () => {
5
+ it("creates a new simple record", async () => {
6
+ await Dummy.run(async () => {
7
+ const task = new Task({name: "Test task"})
8
+ const project = task.buildProject({nameDe: "Test projekt"})
9
+
10
+ expect(project.name()).toEqual("Test projekt")
11
+ expect(project.nameEn()).toEqual(undefined)
12
+ expect(project.nameDe()).toEqual("Test projekt")
13
+
14
+ await task.save()
15
+
16
+ const sameTask = await Task.preload({project: {translations: true}}).find(task.id())
17
+ const sameProject = sameTask.project()
18
+
19
+ expect(sameProject.name()).toEqual("Test projekt")
20
+ expect(sameProject.nameEn()).toEqual(undefined)
21
+ expect(sameProject.nameDe()).toEqual("Test projekt")
22
+ })
23
+ })
24
+ })
@@ -32,5 +32,9 @@ export default new Configuration({
32
32
  })
33
33
  },
34
34
  locale: () => "en",
35
+ localeFallbacks: {
36
+ de: ["de", "en"],
37
+ en: ["en", "de"]
38
+ },
35
39
  locales: ["de", "en"]
36
40
  })
@@ -33,5 +33,9 @@ export default new Configuration({
33
33
  })
34
34
  },
35
35
  locale: () => "en",
36
+ localeFallbacks: {
37
+ de: ["de", "en"],
38
+ en: ["en", "de"]
39
+ },
36
40
  locales: ["de", "en"]
37
41
  })
@@ -8,7 +8,7 @@ export default class VelociousConfiguration {
8
8
  return this.velociousConfiguration
9
9
  }
10
10
 
11
- constructor({database, debug, directory, initializeModels, locale, locales, ...restArgs}) {
11
+ constructor({database, debug, directory, initializeModels, locale, localeFallbacks, locales, ...restArgs}) {
12
12
  restArgsError(restArgs)
13
13
 
14
14
  if (!initializeModels) throw new Error("initializeModels wasn't given")
@@ -19,6 +19,7 @@ export default class VelociousConfiguration {
19
19
  this._initializeModels = initializeModels
20
20
  this._isInitialized = false
21
21
  this.locale = locale
22
+ this.localeFallbacks = localeFallbacks
22
23
  this.locales = locales
23
24
  this.modelClasses = {}
24
25
  }
@@ -31,7 +32,7 @@ export default class VelociousConfiguration {
31
32
  return this.databasePool
32
33
  }
33
34
 
34
- getDatabasePoolType = () => {
35
+ getDatabasePoolType() {
35
36
  const poolTypeClass = digg(this, "database", "default", "master", "poolType")
36
37
 
37
38
  if (!poolTypeClass) {
@@ -41,7 +42,7 @@ export default class VelociousConfiguration {
41
42
  return poolTypeClass
42
43
  }
43
44
 
44
- getDirectory = () => {
45
+ getDirectory() {
45
46
  if (!this._directory) {
46
47
  this._directory = process.cwd()
47
48
  }
@@ -49,6 +50,11 @@ export default class VelociousConfiguration {
49
50
  return this._directory
50
51
  }
51
52
 
53
+ getLocaleFallbacks = () => this.localeFallbacks
54
+ setLocaleFallbacks(newLocaleFallbacks) {
55
+ this.localeFallbacks = newLocaleFallbacks
56
+ }
57
+
52
58
  getLocale() {
53
59
  if (typeof this.locale == "function") {
54
60
  return this.locale()
@@ -9,7 +9,7 @@ import escapeString from "sql-string-escape"
9
9
  import Insert from "../sqlite/sql/insert.js"
10
10
  import Options from "../sqlite/options.js"
11
11
  import QueryParser from "../sqlite/query-parser.js"
12
- import Table from "./table"
12
+ import Table from "./table.js"
13
13
  import Update from "../sqlite/sql/update.js"
14
14
 
15
15
  export default class VelociousDatabaseDriversSqliteBase extends Base {
@@ -0,0 +1,52 @@
1
+ import debounce from "debounce"
2
+ import {digg} from "diggerize"
3
+ import fs from "fs/promises"
4
+ import query from "./query.js"
5
+ import sqlite3 from "sqlite3"
6
+ import {open} from "sqlite"
7
+
8
+ import Base from "./base.js"
9
+
10
+ export default class VelociousDatabaseDriversSqliteNode extends Base {
11
+ async connect() {
12
+ const args = this.getArgs()
13
+ const databasePath = `db/${this.localStorageName()}.sqlite`
14
+
15
+ if (args.reset) {
16
+ await fs.unlink(databasePath)
17
+ }
18
+
19
+ this.connection = await open({
20
+ filename: databasePath,
21
+ driver: sqlite3.Database
22
+ })
23
+ await this.registerVersion()
24
+ }
25
+
26
+ localStorageName = () => `VelociousDatabaseDriversSqlite---${digg(this.getArgs(), "name")}`
27
+ disconnect = () => this.saveDatabase()
28
+ saveDatabase = async () => {
29
+ const localStorageContent = this.connection.export()
30
+ await this.betterLocaleStorage.set(this.localStorageName(), localStorageContent)
31
+ }
32
+
33
+ saveDatabaseDebounce = debounce(this.saveDatabase, 500)
34
+
35
+ async close() {
36
+ await this.saveDatabase()
37
+ await this.connection.end()
38
+ this.connection = undefined
39
+ }
40
+
41
+ query = async (sql) => {
42
+ const result = await query(this.connection, sql)
43
+ const downcasedSQL = sql.toLowerCase().trim()
44
+
45
+ // Auto-save database in local storage in case we can find manipulating instructions in the SQL
46
+ if (downcasedSQL.startsWith("delete ") || downcasedSQL.startsWith("insert into ") || downcasedSQL.startsWith("update ")) {
47
+ this.saveDatabaseDebounce()
48
+ }
49
+
50
+ return result
51
+ }
52
+ }
@@ -0,0 +1,20 @@
1
+ export default async function query(connection, sql) {
2
+ const rows = []
3
+ let result
4
+
5
+ try {
6
+ result = await connection.all(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
+ return result
20
+ }
@@ -1,6 +1,6 @@
1
1
  import Configuration from "../configuration.js"
2
2
  import * as inflection from "inflection"
3
- import Migrator from "./migrator"
3
+ import Migrator from "./migrator.js"
4
4
 
5
5
  export default class VelociousDatabaseMigrateFromRequireContext {
6
6
  constructor(configuration) {
@@ -13,7 +13,7 @@ export default class VelociousDatabaseMigrateFromRequireContext {
13
13
 
14
14
  const files = requireContext.keys()
15
15
  .map((file) => {
16
- const match = file.match(/^\.\/(\d{14})-(.+)\.js$/)
16
+ const match = file.match(/(\d{14})-(.+)\.js$/)
17
17
 
18
18
  if (!match) return null
19
19
 
@@ -1,5 +1,5 @@
1
1
  import {digg} from "diggerize"
2
- import TableData from "./table-data/index"
2
+ import TableData from "./table-data/index.js"
3
3
 
4
4
  export default class VelociousDatabaseMigrator {
5
5
  constructor({configuration}) {
@@ -4,6 +4,7 @@ import * as inflection from "inflection"
4
4
  import JoinPlain from "./join-plain.js"
5
5
  import OrderPlain from "./order-plain.js"
6
6
  import Preloader from "./preloader.js"
7
+ import RecordNotFoundError from "../record/record-not-found-error.js"
7
8
  import SelectPlain from "./select-plain.js"
8
9
  import WhereHash from "./where-hash.js"
9
10
  import WherePlain from "./where-plain.js"
@@ -46,6 +47,21 @@ export default class VelociousDatabaseQuery {
46
47
 
47
48
  getOptions = () => this.driver.options()
48
49
 
50
+ async find(recordId) {
51
+ const conditions = {}
52
+
53
+ conditions[this.modelClass.primaryKey()] = recordId
54
+
55
+ const query = this.clone().where(conditions)
56
+ const record = await query.first()
57
+
58
+ if (!record) {
59
+ throw new RecordNotFoundError(`Couldn't find ${this.modelClass.name} with '${this.modelClass.primaryKey()}'=${recordId}`)
60
+ }
61
+
62
+ return record
63
+ }
64
+
49
65
  async findBy(conditions) {
50
66
  const newConditions = {}
51
67
 
@@ -7,7 +7,6 @@ import HasManyRelationship from "./relationships/has-many.js"
7
7
  import HasManyInstanceRelationship from "./instance-relationships/has-many.js"
8
8
  import * as inflection from "inflection"
9
9
  import Query from "../query/index.js"
10
- import RecordNotFoundError from "./record-not-found-error.js"
11
10
 
12
11
  export default class VelociousDatabaseRecord {
13
12
  static _relationshipExists(relationshipName) {
@@ -125,21 +124,6 @@ export default class VelociousDatabaseRecord {
125
124
  return record
126
125
  }
127
126
 
128
- static async find(recordId) {
129
- const conditions = {}
130
-
131
- conditions[this.primaryKey()] = recordId
132
-
133
- const query = this.where(conditions)
134
- const record = await query.first()
135
-
136
- if (!record) {
137
- throw new RecordNotFoundError(`Couldn't find ${this.name} with '${this.primaryKey()}'=${recordId}`)
138
- }
139
-
140
- return record
141
- }
142
-
143
127
  static _getConfiguration() {
144
128
  if (!this._configuration) {
145
129
  this._configuration = Configuration.current()
@@ -161,7 +145,7 @@ export default class VelociousDatabaseRecord {
161
145
  }
162
146
 
163
147
  static async initializeRecord({configuration}) {
164
- if (!configuration) throw new Error("No configuration given")
148
+ if (!configuration) throw new Error(`No configuration given for ${this.name}`)
165
149
 
166
150
  this._configuration = configuration
167
151
  this._configuration.registerModelClass(this)
@@ -211,7 +195,7 @@ export default class VelociousDatabaseRecord {
211
195
  this.prototype[name] = function () {
212
196
  const locale = this._getConfiguration().getLocale()
213
197
 
214
- return this._getTranslatedAttribute(name, locale)
198
+ return this._getTranslatedAttributeWithFallback(name, locale)
215
199
  }
216
200
 
217
201
  this.prototype[setterMethodName] = function (newValue) {
@@ -419,6 +403,25 @@ export default class VelociousDatabaseRecord {
419
403
  }
420
404
  }
421
405
 
406
+ _getTranslatedAttributeWithFallback(name, locale) {
407
+ let localesInOrder
408
+ const fallbacks = this._getConfiguration().getLocaleFallbacks()
409
+
410
+ if (fallbacks && locale in fallbacks) {
411
+ localesInOrder = fallbacks[locale]
412
+ } else {
413
+ localesInOrder = [locale]
414
+ }
415
+
416
+ for (const fallbackLocale of localesInOrder) {
417
+ const result = this._getTranslatedAttribute(name, fallbackLocale)
418
+
419
+ if (result && result.trim() != "") {
420
+ return result
421
+ }
422
+ }
423
+ }
424
+
422
425
  _setTranslatedAttribute(name, locale, newValue) {
423
426
  let translation = this.translations().loaded()?.find((translation) => translation.locale() == locale)
424
427
 
@@ -454,6 +457,10 @@ export default class VelociousDatabaseRecord {
454
457
  return this._newQuery()
455
458
  }
456
459
 
460
+ static async find(...args) {
461
+ return this._newQuery().find(...args)
462
+ }
463
+
457
464
  static async findBy(...args) {
458
465
  return this._newQuery().findBy(...args)
459
466
  }
@@ -15,5 +15,9 @@ export default new Configuration({
15
15
  database: "database"
16
16
  }
17
17
  }
18
+ },
19
+ localeFallbacks: {
20
+ de: ["de", "en"],
21
+ en: ["en", "de"]
18
22
  }
19
23
  })