velocious 1.0.5 → 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.
Files changed (69) hide show
  1. package/package.json +5 -3
  2. package/spec/cli/commands/db/create-spec.mjs +1 -1
  3. package/spec/cli/commands/db/migrate-spec.mjs +2 -0
  4. package/spec/database/record/create-spec.mjs +9 -0
  5. package/spec/database/record/find-spec.mjs +0 -1
  6. package/spec/database/record/query-spec.mjs +37 -0
  7. package/spec/dummy/index.mjs +14 -2
  8. package/spec/dummy/src/config/configuration.example.mjs +16 -1
  9. package/spec/dummy/src/config/configuration.peakflow.mjs +16 -1
  10. package/spec/dummy/src/database/migrations/20230728075328-create-projects.mjs +0 -1
  11. package/spec/dummy/src/database/migrations/20230728075329-create-tasks.mjs +0 -1
  12. package/spec/dummy/src/database/migrations/20250605133926-create-project-translations.mjs +16 -0
  13. package/spec/dummy/src/models/project.mjs +9 -0
  14. package/spec/dummy/src/models/task.mjs +5 -1
  15. package/src/big-brother.mjs +37 -0
  16. package/src/cli/commands/db/create.mjs +8 -6
  17. package/src/cli/commands/db/migrate.mjs +1 -2
  18. package/src/cli/commands/generate/migration.mjs +1 -1
  19. package/src/cli/commands/generate/model.mjs +1 -1
  20. package/src/configuration.mjs +39 -3
  21. package/src/database/drivers/base.mjs +21 -2
  22. package/src/database/drivers/mysql/column.mjs +8 -0
  23. package/src/database/drivers/mysql/index.mjs +34 -2
  24. package/src/database/drivers/mysql/options.mjs +1 -0
  25. package/src/database/drivers/mysql/query-parser.mjs +2 -23
  26. package/src/database/drivers/mysql/table.mjs +25 -0
  27. package/src/database/drivers/sqlite/base.mjs +76 -4
  28. package/src/database/drivers/sqlite/column.mjs +10 -0
  29. package/src/database/drivers/sqlite/index.native.mjs +19 -22
  30. package/src/database/drivers/sqlite/index.web.mjs +27 -17
  31. package/src/database/drivers/sqlite/options.mjs +2 -1
  32. package/src/database/drivers/sqlite/query-parser.mjs +2 -23
  33. package/src/database/drivers/sqlite/query.native.mjs +16 -1
  34. package/src/database/drivers/sqlite/query.web.mjs +27 -2
  35. package/src/database/drivers/sqlite/sql/create-index.mjs +4 -0
  36. package/src/database/drivers/sqlite/table.mjs +16 -1
  37. package/src/database/initializer-from-require-context.mjs +21 -0
  38. package/src/database/migration/index.mjs +34 -2
  39. package/src/database/migrator.mjs +4 -2
  40. package/src/database/pool/base.mjs +5 -0
  41. package/src/database/query/base.mjs +2 -1
  42. package/src/database/query/create-index-base.mjs +50 -0
  43. package/src/database/query/create-table-base.mjs +40 -17
  44. package/src/database/query/index.mjs +83 -21
  45. package/src/database/query/preloader/belongs-to.mjs +52 -0
  46. package/src/database/query/preloader/has-many.mjs +55 -0
  47. package/src/database/query/preloader.mjs +41 -0
  48. package/src/database/query/where-base.mjs +9 -0
  49. package/src/database/query/where-hash.mjs +35 -0
  50. package/src/database/query/where-plain.mjs +13 -0
  51. package/src/database/query-parser/base-query-parser.mjs +33 -0
  52. package/src/database/query-parser/group-parser.mjs +40 -0
  53. package/src/database/query-parser/joins-parser.mjs +48 -7
  54. package/src/database/query-parser/limit-parser.mjs +40 -0
  55. package/src/database/query-parser/options.mjs +2 -1
  56. package/src/database/query-parser/order-parser.mjs +39 -0
  57. package/src/database/query-parser/select-parser.mjs +5 -1
  58. package/src/database/query-parser/where-parser.mjs +39 -0
  59. package/src/database/record/index.mjs +464 -29
  60. package/src/database/record/instance-relationships/base.mjs +28 -0
  61. package/src/database/record/instance-relationships/belongs-to.mjs +20 -0
  62. package/src/database/record/instance-relationships/has-many.mjs +47 -0
  63. package/src/database/record/relationships/base.mjs +32 -0
  64. package/src/database/record/relationships/belongs-to.mjs +12 -0
  65. package/src/database/record/relationships/has-many.mjs +12 -0
  66. package/src/database/table-data/index.mjs +15 -25
  67. package/src/http-server/worker-handler/worker-thread.mjs +7 -4
  68. package/src/templates/generate-model.mjs +3 -1
  69. package/src/utils/rest-args-error.mjs +9 -0
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "bin/velocious.mjs"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.5",
6
+ "version": "1.0.6",
7
7
  "main": "index.mjs",
8
8
  "scripts": {
9
9
  "test": "jasmine",
@@ -14,7 +14,7 @@
14
14
  "type": "git",
15
15
  "url": "git+https://github.com/kaspernj/velocious.git"
16
16
  },
17
- "author": "k@spernj.org",
17
+ "author": "kasper@diestoeckels.de",
18
18
  "license": "ISC",
19
19
  "bugs": {
20
20
  "url": "https://github.com/kaspernj/velocious/issues"
@@ -24,9 +24,11 @@
24
24
  "devDependencies": {
25
25
  "jasmine": "^5.0.2",
26
26
  "mysql": "^2.18.1",
27
- "node-fetch": "^3.3.1"
27
+ "node-fetch": "^3.3.1",
28
+ "require-context": "^1.1.0"
28
29
  },
29
30
  "dependencies": {
31
+ "better-localstorage": "^1.0.7",
30
32
  "diggerize": "^1.0.5",
31
33
  "ejs": "^3.1.6",
32
34
  "escape-string-regexp": "^1.0.5",
@@ -17,7 +17,7 @@ describe("Cli - Commands - db:create", () => {
17
17
  sql: 'CREATE DATABASE IF NOT EXISTS `velocious_test`'
18
18
  },
19
19
  {
20
- createSchemaMigrationsTableSql: 'CREATE TABLE IF NOT EXISTS schema_migrations (`version` varchar(255) PRIMARY KEY)'
20
+ createSchemaMigrationsTableSql: 'CREATE TABLE IF NOT EXISTS schema_migrations (`version` varchar(255) PRIMARY KEY NOT NULL)'
21
21
  }
22
22
  ]
23
23
  )
@@ -17,6 +17,7 @@ describe("Cli - Commands - db:migrate", () => {
17
17
  await db.withConnection(async () => {
18
18
  await db.query("DROP TABLE IF EXISTS tasks")
19
19
  await db.query("DROP TABLE IF EXISTS projects")
20
+ await db.query("DROP TABLE IF EXISTS project_translations")
20
21
  })
21
22
 
22
23
  await cli.execute()
@@ -29,6 +30,7 @@ describe("Cli - Commands - db:migrate", () => {
29
30
 
30
31
  expect(tablesResult).toEqual(
31
32
  [
33
+ {Tables_in_velocious_test: "project_translations"},
32
34
  {Tables_in_velocious_test: "projects"},
33
35
  {Tables_in_velocious_test: "tasks"}
34
36
  ]
@@ -5,10 +5,19 @@ describe("Record - create", () => {
5
5
  it("creates a new simple record", async () => {
6
6
  await Dummy.run(async () => {
7
7
  const task = new Task({name: "Test task"})
8
+ const project = task.buildProject({nameEn: "Test project", nameDe: "Test projekt"})
8
9
 
9
10
  await task.save()
10
11
 
11
12
  expect(task.id()).not.toBeUndefined()
13
+ expect(task.name()).toEqual("Test task")
14
+ expect(task.project().id()).toEqual(project.id())
15
+ expect(task.project()).toEqual(project)
16
+
17
+ expect(project.id()).not.toBeUndefined()
18
+ expect(project.name()).toEqual("Test project")
19
+ expect(project.nameDe()).toEqual("Test projekt")
20
+ expect(project.nameEn()).toEqual("Test project")
12
21
  })
13
22
  })
14
23
  })
@@ -1,5 +1,4 @@
1
1
  import Dummy from "../../dummy/index.mjs"
2
- import RecordNotFoundError from "../../../src/database/record/record-not-found-error.mjs"
3
2
  import Task from "../../dummy/src/models/task.mjs"
4
3
 
5
4
  describe("Record - find", () => {
@@ -0,0 +1,37 @@
1
+ import Dummy from "../../dummy/index.mjs"
2
+ import Task from "../../dummy/src/models/task.mjs"
3
+
4
+ describe("Record - query", () => {
5
+ it("queries for records", async () => {
6
+ await Dummy.run(async () => {
7
+ const task = new Task({name: "Test task"})
8
+ const project = task.buildProject({nameEn: "Test project", nameDe: "Test projekt"})
9
+
10
+ await task.save()
11
+
12
+ expect(task.id()).not.toBeUndefined()
13
+ expect(task.name()).toEqual("Test task")
14
+ expect(task.project().id()).toEqual(project.id())
15
+ expect(task.project()).toEqual(project)
16
+
17
+ expect(project.id()).not.toBeUndefined()
18
+ expect(project.name()).toEqual("Test project")
19
+ expect(project.nameDe()).toEqual("Test projekt")
20
+ expect(project.nameEn()).toEqual("Test project")
21
+
22
+ const tasks = await Task.preload({project: {translations: true}}).toArray()
23
+ const newTask = tasks[0]
24
+ const newProject = newTask.project()
25
+
26
+ expect(newTask.id()).not.toBeUndefined()
27
+ expect(newTask.name()).toEqual("Test task")
28
+ expect(task.project().id()).toEqual(newProject.id())
29
+ expect(newTask.project()).toEqual(newProject)
30
+
31
+ expect(newProject.id()).not.toBeUndefined()
32
+ expect(newProject.name()).toEqual("Test project")
33
+ expect(newProject.nameDe()).toEqual("Test projekt")
34
+ expect(newProject.nameEn()).toEqual("Test project")
35
+ })
36
+ })
37
+ })
@@ -11,11 +11,23 @@ export default class Dummy {
11
11
  }
12
12
 
13
13
  static async prepare() {
14
+ dummyConfiguration.setCurrent()
15
+
14
16
  const db = dummyConfiguration.getDatabasePool()
15
17
 
16
18
  await db.withConnection(async () => {
17
19
  await db.query("DROP TABLE IF EXISTS tasks")
18
- await db.query("CREATE TABLE tasks (id MEDIUMINT NOT NULL AUTO_INCREMENT, name VARCHAR(255), description TEXT, PRIMARY KEY (id))")
20
+ await db.query("DROP TABLE IF EXISTS projects")
21
+ await db.query("DROP TABLE IF EXISTS project_translations")
22
+
23
+ await db.query("CREATE TABLE tasks (id MEDIUMINT NOT NULL AUTO_INCREMENT, project_id MEDIUMINT, name VARCHAR(255), description TEXT, PRIMARY KEY (id))")
24
+ await db.query("CREATE TABLE projects (id MEDIUMINT NOT NULL AUTO_INCREMENT, PRIMARY KEY (id))")
25
+ await db.query("CREATE TABLE project_translations (id MEDIUMINT NOT NULL AUTO_INCREMENT, project_id MEDIUMINT, locale VARCHAR(255), name VARCHAR(255), PRIMARY KEY (id))")
26
+ await db.query("CREATE UNIQUE INDEX unique_project_translation ON project_translations (project_id, locale)")
27
+
28
+ if (!dummyConfiguration.isInitialized()) {
29
+ await dummyConfiguration.initialize()
30
+ }
19
31
  })
20
32
  }
21
33
 
@@ -25,10 +37,10 @@ export default class Dummy {
25
37
 
26
38
  async run(callback) {
27
39
  await dummyConfiguration.getDatabasePool().withConnection(async () => {
40
+ await Dummy.prepare()
28
41
  await this.start()
29
42
 
30
43
  try {
31
- await Dummy.prepare()
32
44
  await callback()
33
45
  } finally {
34
46
  await this.stop()
@@ -1,7 +1,11 @@
1
1
  import AsyncTrackedMultiConnection from "../../../../src/database/pool/async-tracked-multi-connection.mjs"
2
2
  import Configuration from "../../../../src/configuration.mjs"
3
3
  import dummyDirectory from "../../dummy-directory.mjs"
4
+ import fs from "fs/promises"
5
+ import InitializerFromRequireContext from "../../../../src/database/initializer-from-require-context.mjs"
4
6
  import MysqlDriver from "../../../../src/database/drivers/mysql/index.mjs"
7
+ import path from "path"
8
+ import requireContext from "require-context"
5
9
 
6
10
  export default new Configuration({
7
11
  database: {
@@ -17,5 +21,16 @@ export default new Configuration({
17
21
  }
18
22
  }
19
23
  },
20
- directory: dummyDirectory()
24
+ directory: dummyDirectory(),
25
+ initializeModels: async ({configuration}) => {
26
+ const modelsPath = await fs.realpath(`${path.dirname(import.meta.dirname)}/../src/models`)
27
+ const requireContextModels = requireContext(modelsPath, true, /^(.+)\.mjs$/)
28
+ const initializerFromRequireContext = new InitializerFromRequireContext({requireContext: requireContextModels})
29
+
30
+ await configuration.getDatabasePool().withConnection(async () => {
31
+ await initializerFromRequireContext.initialize({configuration})
32
+ })
33
+ },
34
+ locale: () => "en",
35
+ locales: ["de", "en"]
21
36
  })
@@ -1,7 +1,11 @@
1
1
  import AsyncTrackedMultiConnection from "../../../../src/database/pool/async-tracked-multi-connection.mjs"
2
2
  import Configuration from "../../../../src/configuration.mjs"
3
3
  import dummyDirectory from "../../dummy-directory.mjs"
4
+ import fs from "fs/promises"
5
+ import InitializerFromRequireContext from "../../../../src/database/initializer-from-require-context.mjs"
4
6
  import MysqlDriver from "../../../../src/database/drivers/mysql/index.mjs"
7
+ import path from "path"
8
+ import requireContext from "require-context"
5
9
 
6
10
  export default new Configuration({
7
11
  database: {
@@ -18,5 +22,16 @@ export default new Configuration({
18
22
  }
19
23
  }
20
24
  },
21
- directory: dummyDirectory()
25
+ directory: dummyDirectory(),
26
+ initializeModels: async ({configuration}) => {
27
+ const modelsPath = await fs.realpath(`${path.dirname(import.meta.dirname)}/../src/models`)
28
+ const requireContextModels = requireContext(modelsPath, true, /^(.+)\.mjs$/)
29
+ const initializerFromRequireContext = new InitializerFromRequireContext({requireContext: requireContextModels})
30
+
31
+ await configuration.getDatabasePool().withConnection(async () => {
32
+ await initializerFromRequireContext.initialize({configuration})
33
+ })
34
+ },
35
+ locale: () => "en",
36
+ locales: ["de", "en"]
22
37
  })
@@ -3,7 +3,6 @@ import Migration from "../../../../../src/database/migration/index.mjs"
3
3
  export default class CreateProjects extends Migration {
4
4
  async change() {
5
5
  await this.createTable("projects", (table) => {
6
- table.bigint("id", {autoIncrement: true, primaryKey: true})
7
6
  table.string("name", {maxLength: 100, null: false})
8
7
  table.timestamps()
9
8
  })
@@ -3,7 +3,6 @@ import Migration from "../../../../../src/database/migration/index.mjs"
3
3
  export default class CreateTasks extends Migration {
4
4
  async change() {
5
5
  await this.createTable("tasks", (table) => {
6
- table.bigint("id", {autoIncrement: true, primaryKey: true})
7
6
  table.references("project")
8
7
  table.string("name")
9
8
  table.text("description")
@@ -0,0 +1,16 @@
1
+ import Migration from "../../../../../src/database/migration/index.mjs"
2
+
3
+ export default class CreateProjectTranslations extends Migration {
4
+ async up() {
5
+ await this.createTable("project_translations", (t) => {
6
+ t.references("project", {null: false})
7
+ t.string("locale", {null: false})
8
+ t.string("name")
9
+ t.timestamps()
10
+ })
11
+ }
12
+
13
+ async down() {
14
+ await this.dropTable("project_translations")
15
+ }
16
+ }
@@ -0,0 +1,9 @@
1
+ import DatabaseRecord from "../../../../src/database/record/index.mjs"
2
+
3
+ class Project extends DatabaseRecord {
4
+ }
5
+
6
+ Project.hasMany("tasks")
7
+ Project.translates("name")
8
+
9
+ export default Project
@@ -1,4 +1,8 @@
1
1
  import DatabaseRecord from "../../../../src/database/record/index.mjs"
2
2
 
3
- export default class Task extends DatabaseRecord {
3
+ class Task extends DatabaseRecord {
4
4
  }
5
+
6
+ Task.belongsTo("project")
7
+
8
+ export default Task
@@ -0,0 +1,37 @@
1
+ export default class VelociousBigBrother {
2
+ constructor() {
3
+ this.enabledLoggers = {
4
+ databaseQuery: false
5
+ }
6
+ }
7
+
8
+ checkExists(name) {
9
+ if (!(name in this.enabledLoggers)) throw new Error(`Invalid logger name: ${name}`)
10
+ }
11
+
12
+ isEnabled(name) {
13
+ this.checkExists(name)
14
+
15
+ return this.enabledLoggers[name]
16
+ }
17
+
18
+ async run({after, before, name}, callback) {
19
+ this.checkExists(name)
20
+
21
+ if (!this.enabledLoggers[name]) {
22
+ return await callback()
23
+ }
24
+
25
+ if (before) {
26
+ before()
27
+ }
28
+
29
+ const startTime = new Date()
30
+ const result = await callback()
31
+ const endTime = new Date()
32
+
33
+ if (after) {
34
+ after({result})
35
+ }
36
+ }
37
+ }
@@ -39,12 +39,14 @@ export default class DbCreate extends BaseCommand{
39
39
 
40
40
  schemaMigrationsTable.string("version", {null: false, primaryKey: true})
41
41
 
42
- const createSchemaMigrationsTableSql = this.databaseConnection.createTableSql(schemaMigrationsTable)
43
-
44
- if (this.args.testing) {
45
- this.result.push({createSchemaMigrationsTableSql})
46
- } else {
47
- await this.databaseConnection.query(createSchemaMigrationsTableSql)
42
+ const createSchemaMigrationsTableSqls = this.databaseConnection.createTableSql(schemaMigrationsTable)
43
+
44
+ for (const createSchemaMigrationsTableSql of createSchemaMigrationsTableSqls) {
45
+ if (this.args.testing) {
46
+ this.result.push({createSchemaMigrationsTableSql})
47
+ } else {
48
+ await this.databaseConnection.query(createSchemaMigrationsTableSql)
49
+ }
48
50
  }
49
51
  }
50
52
  }
@@ -1,7 +1,6 @@
1
1
  import BaseCommand from "../../base-command.mjs"
2
- import {digg} from "diggerize"
3
2
  import fs from "node:fs/promises"
4
- import inflection from "inflection"
3
+ import * as inflection from "inflection"
5
4
 
6
5
  export default class DbMigrate extends BaseCommand {
7
6
  async execute() {
@@ -3,7 +3,7 @@ import {dirname} from "path"
3
3
  import {fileURLToPath} from "url"
4
4
  import fileExists from "../../../utils/file-exists.mjs"
5
5
  import fs from "node:fs/promises"
6
- import inflection from "inflection"
6
+ import * as inflection from "inflection"
7
7
  import strftime from "strftime"
8
8
 
9
9
  export default class DbGenerateMigration extends BaseCommand {
@@ -3,7 +3,7 @@ import {dirname} from "path"
3
3
  import {fileURLToPath} from "url"
4
4
  import fileExists from "../../../utils/file-exists.mjs"
5
5
  import fs from "node:fs/promises"
6
- import inflection from "inflection"
6
+ import * as inflection from "inflection"
7
7
 
8
8
  export default class DbGenerateModel extends BaseCommand {
9
9
  async execute() {
@@ -1,4 +1,5 @@
1
1
  import {digg} from "diggerize"
2
+ import restArgsError from "./utils/rest-args-error.mjs"
2
3
 
3
4
  export default class VelociousConfiguration {
4
5
  static current(throwError = true) {
@@ -7,10 +8,19 @@ export default class VelociousConfiguration {
7
8
  return this.velociousConfiguration
8
9
  }
9
10
 
10
- constructor({database, debug, directory}) {
11
+ constructor({database, debug, directory, initializeModels, locale, locales, ...restArgs}) {
12
+ restArgsError(restArgs)
13
+
14
+ if (!initializeModels) throw new Error("initializeModels wasn't given")
15
+
11
16
  this.database = database
12
17
  this.debug = debug
13
18
  this._directory = directory
19
+ this._initializeModels = initializeModels
20
+ this._isInitialized = false
21
+ this.locale = locale
22
+ this.locales = locales
23
+ this.modelClasses = {}
14
24
  }
15
25
 
16
26
  getDatabasePool() {
@@ -39,6 +49,26 @@ export default class VelociousConfiguration {
39
49
  return this._directory
40
50
  }
41
51
 
52
+ getLocale() {
53
+ if (typeof this.locale == "function") {
54
+ return this.locale()
55
+ } else if (this.locale) {
56
+ return this.locale
57
+ } else {
58
+ return this.getLocales()[0]
59
+ }
60
+ }
61
+
62
+ getLocales = () => digg(this, "locales")
63
+
64
+ getModelClass(name) {
65
+ const modelClass = this.modelClasses[name]
66
+
67
+ if (!modelClass) throw new Error(`No such model class ${name} in ${Object.keys(this.modelClasses).join(", ")}}`)
68
+
69
+ return modelClass
70
+ }
71
+
42
72
  initializeDatabasePool() {
43
73
  if (!this.database) throw new Error("No 'database' was given")
44
74
  if (this.databasePool) throw new Error("DatabasePool has already been initialized")
@@ -50,9 +80,15 @@ export default class VelociousConfiguration {
50
80
  }
51
81
 
52
82
  isDatabasePoolInitialized = () => Boolean(this.databasePool)
83
+ isInitialized = () => this._isInitialized
84
+
85
+ async initialize() {
86
+ await this._initializeModels({configuration: this})
87
+ this._isInitialized = true
88
+ }
53
89
 
54
- initialize() {
55
- // Doesn't currently do anything.
90
+ registerModelClass(modelClass) {
91
+ this.modelClasses[modelClass.name] = modelClass
56
92
  }
57
93
 
58
94
  setCurrent() {
@@ -7,9 +7,11 @@ export default class VelociousDatabaseDriversBase {
7
7
  }
8
8
 
9
9
  async createTable(...args) {
10
- const sql = this.createTableSql(...args)
10
+ const sqls = this.createTableSql(...args)
11
11
 
12
- await this.query(sql)
12
+ for (const sql of sqls) {
13
+ await this.query(sql)
14
+ }
13
15
  }
14
16
 
15
17
  async delete(...args) {
@@ -26,12 +28,29 @@ export default class VelociousDatabaseDriversBase {
26
28
  return this.idSeq
27
29
  }
28
30
 
31
+ getTables() {
32
+ throw new Error(`${this.constructor.name}#getTables not implemented`)
33
+ }
34
+
35
+ async getTableByName(name) {
36
+ const tables = await this.getTables()
37
+ const table = tables.find((table) => table.getName() == name)
38
+
39
+ if (!table) throw new Error(`Couldn't find a table by that name: ${name}`)
40
+
41
+ return table
42
+ }
43
+
29
44
  async insert(...args) {
30
45
  const sql = this.insertSql(...args)
31
46
 
32
47
  await this.query(sql)
33
48
  }
34
49
 
50
+ lastInsertID() {
51
+ throw new Error(`${this.constructor.name}#lastInsertID not implemented`)
52
+ }
53
+
35
54
  async select(tableName) {
36
55
  const handler = new Handler()
37
56
  const query = new Query({
@@ -0,0 +1,8 @@
1
+ export default class VelociousDatabaseDriversMysqlColumn {
2
+ constructor(table, data) {
3
+ this.data = data
4
+ this.table = table
5
+ }
6
+
7
+ getName = () => this.data["Field"]
8
+ }
@@ -9,6 +9,7 @@ import Options from "./options.mjs"
9
9
  import mysql from "mysql"
10
10
  import query from "./query.mjs"
11
11
  import QueryParser from "./query-parser.mjs"
12
+ import Table from "./table.mjs"
12
13
  import Update from "./sql/update.mjs"
13
14
 
14
15
  export default class VelociousDatabaseDriversMysql extends Base{
@@ -64,13 +65,25 @@ export default class VelociousDatabaseDriversMysql extends Base{
64
65
  return new QueryParser({query}).toSql()
65
66
  }
66
67
 
67
- quote(string) {
68
+ escape(string) {
68
69
  if (!this.connection) throw new Error("Can't escape before connected")
69
70
 
70
71
  return this.connection.escape(string)
71
72
  }
72
73
 
73
- quoteColumn(string) {
74
+ quote(string) {
75
+ return `${this.escape(string)}`
76
+ }
77
+
78
+ quoteColumn = (string) => {
79
+ if (string.includes("`")) throw new Error(`Possible SQL injection in column name: ${string}`)
80
+
81
+ return `\`${string}\``
82
+ }
83
+
84
+ quoteTable = (string) => {
85
+ if (string.includes("`")) throw new Error(`Possible SQL injection in table name: ${string}`)
86
+
74
87
  return `\`${string}\``
75
88
  }
76
89
 
@@ -86,6 +99,25 @@ export default class VelociousDatabaseDriversMysql extends Base{
86
99
  return insert.toSql()
87
100
  }
88
101
 
102
+ async getTables() {
103
+ const result = await this.query("SHOW FULL TABLES")
104
+ const tables = []
105
+
106
+ for (const row of result) {
107
+ const table = new Table(this, row)
108
+
109
+ tables.push(table)
110
+ }
111
+
112
+ return tables
113
+ }
114
+
115
+ async lastInsertID() {
116
+ const result = await this.query("SELECT LAST_INSERT_ID() AS last_insert_id")
117
+
118
+ return digg(result, 0, "last_insert_id")
119
+ }
120
+
89
121
  options() {
90
122
  if (!this._options) {
91
123
  this._options = new Options({driver: this})
@@ -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 {digs} from "diggerize"
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
+ }