velocious 1.0.2 → 1.0.3
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/README.md +12 -2
- package/bin/velocious.mjs +3 -3
- package/index.mjs +5 -1
- package/package.json +4 -3
- package/peak_flow.yml +5 -2
- package/spec/cli/commands/db/create-spec.mjs +25 -0
- package/spec/cli/commands/db/migrate-spec.mjs +37 -0
- package/spec/cli/commands/destroy/migration-spec.mjs +15 -0
- package/spec/cli/commands/generate/migration-spec.mjs +18 -0
- package/spec/cli/commands/init-spec.mjs +19 -0
- package/spec/cli/commands/test/test-files-finder-spec.mjs +12 -0
- package/spec/database/drivers/mysql/connection-spec.mjs +2 -2
- package/spec/dummy/dummy-directory.mjs +11 -0
- package/spec/dummy/index.mjs +18 -24
- package/spec/dummy/src/config/configuration.example.mjs +19 -0
- package/spec/dummy/src/config/configuration.peakflow.mjs +20 -0
- package/spec/dummy/src/database/migrations/20230728075328-create-projects.mjs +11 -0
- package/spec/dummy/src/database/migrations/20230728075329-create-tasks.mjs +13 -0
- package/spec/http-server/client-spec.mjs +3 -13
- package/src/application.mjs +6 -12
- package/src/cli/base-command.mjs +11 -0
- package/src/cli/commands/db/create.mjs +44 -8
- package/src/cli/commands/db/migrate.mjs +58 -0
- package/src/cli/commands/destroy/migration.mjs +35 -0
- package/src/cli/commands/generate/migration.mjs +31 -7
- package/src/cli/commands/init.mjs +60 -0
- package/src/cli/commands/test/index.mjs +14 -0
- package/src/cli/commands/test/test-files-finder.mjs +99 -0
- package/src/cli/commands/test/test-runner.mjs +19 -0
- package/src/cli/index.mjs +36 -16
- package/src/configuration-resolver.mjs +26 -0
- package/src/configuration.mjs +24 -2
- package/src/database/drivers/base.mjs +8 -0
- package/src/database/drivers/mysql/index.mjs +25 -0
- package/src/database/drivers/mysql/sql/create-database.mjs +4 -0
- package/src/database/drivers/mysql/sql/create-table.mjs +4 -0
- package/src/database/drivers/sqlite/options.mjs +17 -0
- package/src/database/drivers/sqlite/query-parser.mjs +25 -0
- package/src/database/drivers/sqlite/sql/create-database.mjs +4 -0
- package/src/database/drivers/sqlite/sql/create-table.mjs +4 -0
- package/src/database/drivers/sqlite/sql/delete.mjs +19 -0
- package/src/database/drivers/sqlite/sql/insert.mjs +29 -0
- package/src/database/drivers/sqlite/sql/update.mjs +31 -0
- package/src/database/drivers/sqlite-expo/index.mjs +100 -0
- package/src/database/drivers/sqlite-expo/query.mjs +9 -0
- package/src/database/handler.mjs +0 -4
- package/src/database/migration/index.mjs +15 -2
- package/src/database/pool/index.mjs +87 -18
- package/src/database/query/base.mjs +11 -0
- package/src/database/query/create-database-base.mjs +20 -0
- package/src/database/query/create-table-base.mjs +69 -0
- package/src/database/query/delete-base.mjs +4 -10
- package/src/database/query/from-plain.mjs +3 -5
- package/src/database/query/from-table.mjs +2 -2
- package/src/database/record/index.mjs +1 -1
- package/src/database/table-data/index.mjs +83 -0
- package/src/http-server/worker-handler/worker-thread.mjs +17 -8
- package/src/routes/resolver.mjs +3 -1
- package/src/spec/index.mjs +5 -0
- package/src/templates/configuration.mjs +17 -0
- package/src/templates/generate-migration.mjs +11 -0
- package/src/templates/routes.mjs +11 -0
- package/src/utils/file-exists.mjs +13 -0
- package/spec/cli/generate/migration-spec.mjs +0 -9
- package/spec/dummy/src/config/database.example.mjs +0 -15
- package/spec/dummy/src/config/database.peakflow.mjs +0 -15
- package/spec/dummy/src/database/migrations/001-create-tasks.mjs +0 -12
package/README.md
CHANGED
|
@@ -9,7 +9,17 @@ This is still work in progress.
|
|
|
9
9
|
* Migrations ala Rails
|
|
10
10
|
* Controllers and views ala Rails
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# Setup
|
|
13
|
+
|
|
14
|
+
Make a new NPM project.
|
|
15
|
+
```bash
|
|
16
|
+
mkdir project
|
|
17
|
+
cd project
|
|
18
|
+
npm install velocious
|
|
19
|
+
npx velocious init
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
# Migrations
|
|
13
23
|
|
|
14
24
|
```bash
|
|
15
25
|
npx velocious db:g:migration create_tasks
|
|
@@ -19,7 +29,7 @@ npx velocious db:g:migration create_tasks
|
|
|
19
29
|
npx velocious db:migrate
|
|
20
30
|
```
|
|
21
31
|
|
|
22
|
-
|
|
32
|
+
# Testing
|
|
23
33
|
|
|
24
34
|
```bash
|
|
25
35
|
npm test
|
package/bin/velocious.mjs
CHANGED
package/index.mjs
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import Application from "./src/application.mjs"
|
|
2
2
|
import Cli from "./src/cli/index.mjs"
|
|
3
|
+
import Configuration from "./src/configuration.mjs"
|
|
3
4
|
import Controller from "./src/controller.mjs"
|
|
4
5
|
import Database from "./src/database/index.mjs"
|
|
5
6
|
import DatabasePool from "./src/database/pool/index.mjs"
|
|
6
7
|
import HttpServer from "./src/http-server/index.mjs"
|
|
7
8
|
import Routes from "./src/routes/index.mjs"
|
|
9
|
+
import Spec from "./src/spec/index.mjs"
|
|
8
10
|
|
|
9
11
|
export {
|
|
10
12
|
Application,
|
|
11
13
|
Cli,
|
|
14
|
+
Configuration,
|
|
12
15
|
Controller,
|
|
13
16
|
Database,
|
|
14
17
|
DatabasePool,
|
|
15
18
|
HttpServer,
|
|
16
|
-
Routes
|
|
19
|
+
Routes,
|
|
20
|
+
Spec
|
|
17
21
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"velocious": "bin/velocious.mjs"
|
|
4
4
|
},
|
|
5
5
|
"name": "velocious",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.3",
|
|
7
7
|
"main": "index.mjs",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"test": "jasmine",
|
|
@@ -27,10 +27,11 @@
|
|
|
27
27
|
"node-fetch": "^3.3.1"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"diggerize": "^1.0.
|
|
30
|
+
"diggerize": "^1.0.5",
|
|
31
31
|
"ejs": "^3.1.6",
|
|
32
32
|
"escape-string-regexp": "^1.0.5",
|
|
33
33
|
"incorporator": "^1.0.2",
|
|
34
|
-
"inflection": "^
|
|
34
|
+
"inflection": "^3.0.0",
|
|
35
|
+
"strftime": "^0.10.2"
|
|
35
36
|
}
|
|
36
37
|
}
|
package/peak_flow.yml
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
before_install:
|
|
2
|
-
-
|
|
2
|
+
- sudo mkdir -p /etc/apt/keyrings
|
|
3
|
+
- curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
|
4
|
+
- echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
|
|
5
|
+
- sudo apt-get update
|
|
3
6
|
- sudo apt-get install -y nodejs
|
|
4
7
|
before_script:
|
|
5
|
-
- cp spec/dummy/src/config/
|
|
8
|
+
- cp spec/dummy/src/config/configuration.peakflow.mjs spec/dummy/src/config/configuration.mjs
|
|
6
9
|
- npm install
|
|
7
10
|
- wait-for-it mariadb:3306
|
|
8
11
|
services:
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import Cli from "../../../../src/cli/index.mjs"
|
|
2
|
+
import dummyDirectory from "../../../dummy/dummy-directory.mjs"
|
|
3
|
+
|
|
4
|
+
describe("Cli - Commands - db:create", () => {
|
|
5
|
+
it("generates SQL to create a new database", async () => {
|
|
6
|
+
const cli = new Cli({
|
|
7
|
+
directory: dummyDirectory(),
|
|
8
|
+
processArgs: ["db:create"],
|
|
9
|
+
testing: true
|
|
10
|
+
})
|
|
11
|
+
const result = await cli.execute()
|
|
12
|
+
|
|
13
|
+
expect(result).toEqual(
|
|
14
|
+
[
|
|
15
|
+
{
|
|
16
|
+
databaseName: 'velocious_test',
|
|
17
|
+
sql: 'CREATE DATABASE IF NOT EXISTS velocious_test'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
createSchemaMigrationsTableSql: 'CREATE TABLE IF NOT EXISTS schema_migrations (`version` varchar(255) PRIMARY KEY)'
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Cli from "../../../../src/cli/index.mjs"
|
|
2
|
+
import dummyDirectory from "../../../dummy/dummy-directory.mjs"
|
|
3
|
+
|
|
4
|
+
describe("Cli - Commands - db:migrate", () => {
|
|
5
|
+
it("runs migrations", async () => {
|
|
6
|
+
const directory = dummyDirectory()
|
|
7
|
+
const cli = new Cli({
|
|
8
|
+
directory,
|
|
9
|
+
processArgs: ["db:migrate"],
|
|
10
|
+
testing: true
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
await cli.loadConfiguration()
|
|
14
|
+
|
|
15
|
+
const db = cli.configuration.getDatabasePool()
|
|
16
|
+
|
|
17
|
+
await db.withConnection(async () => {
|
|
18
|
+
await db.query("DROP TABLE IF EXISTS tasks")
|
|
19
|
+
await db.query("DROP TABLE IF EXISTS projects")
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
await cli.execute()
|
|
23
|
+
|
|
24
|
+
let tablesResult
|
|
25
|
+
|
|
26
|
+
await db.withConnection(async () => {
|
|
27
|
+
tablesResult = await db.query("SHOW TABLES")
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
expect(tablesResult).toEqual(
|
|
31
|
+
[
|
|
32
|
+
{Tables_in_velocious_test: "projects"},
|
|
33
|
+
{Tables_in_velocious_test: "tasks"}
|
|
34
|
+
]
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Cli from "../../../../src/cli/index.mjs"
|
|
2
|
+
import dummyDirectory from "../../../dummy/dummy-directory.mjs"
|
|
3
|
+
|
|
4
|
+
describe("Cli - destroy - migration", () => {
|
|
5
|
+
it("destroys an existing migration", async () => {
|
|
6
|
+
const cli = new Cli({
|
|
7
|
+
directory: dummyDirectory(),
|
|
8
|
+
processArgs: ["d:migration", "create-tasks"],
|
|
9
|
+
testing: true
|
|
10
|
+
})
|
|
11
|
+
const result = await cli.execute()
|
|
12
|
+
|
|
13
|
+
expect(result.destroyed).toEqual(["create-tasks"])
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Cli from "../../../../src/cli/index.mjs"
|
|
2
|
+
import dummyDirectory from "../../../dummy/dummy-directory.mjs"
|
|
3
|
+
|
|
4
|
+
describe("Cli - generate - migration", () => {
|
|
5
|
+
it("generates a new migration", async () => {
|
|
6
|
+
const cli = new Cli({
|
|
7
|
+
directory: dummyDirectory(),
|
|
8
|
+
processArgs: ["g:migration", "create-tasks"],
|
|
9
|
+
testing: true
|
|
10
|
+
})
|
|
11
|
+
const result = await cli.execute()
|
|
12
|
+
|
|
13
|
+
expect(result.migrationName).toEqual("create-tasks")
|
|
14
|
+
expect(result.migrationNameCamelized).toEqual("CreateTasks")
|
|
15
|
+
expect(result.migrationNumber).toMatch(/^\d+$/)
|
|
16
|
+
expect(result.migrationPath).toMatch(/-create-tasks\.mjs$/)
|
|
17
|
+
})
|
|
18
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Cli from "../../../src/cli/index.mjs"
|
|
2
|
+
import dummyDirectory from "../../dummy/dummy-directory.mjs"
|
|
3
|
+
|
|
4
|
+
describe("Cli - Commands - init", () => {
|
|
5
|
+
it("inits files and dirs", async () => {
|
|
6
|
+
const cli = new Cli({
|
|
7
|
+
directory: dummyDirectory(),
|
|
8
|
+
processArgs: ["init"],
|
|
9
|
+
testing: true
|
|
10
|
+
})
|
|
11
|
+
const result = await cli.execute()
|
|
12
|
+
|
|
13
|
+
expect(result.fileMappings.length).toEqual(2)
|
|
14
|
+
expect(result.fileMappings[0].source).toContain("/src/templates/configuration.mjs")
|
|
15
|
+
expect(result.fileMappings[0].target).toContain("/spec/dummy/src/config/configuration.mjs")
|
|
16
|
+
expect(result.fileMappings[1].source).toContain("/src/templates/routes.mjs")
|
|
17
|
+
expect(result.fileMappings[1].target).toContain("/spec/dummy/src/config/routes.mjs")
|
|
18
|
+
})
|
|
19
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import TestFilesFinder from "../../../../src/cli/commands/test/test-files-finder.mjs"
|
|
2
|
+
|
|
3
|
+
describe("Cli - Commands - test - TestFilesFinder", () => {
|
|
4
|
+
it("finds the correct test files", async () => {
|
|
5
|
+
const testFilesFinder = new TestFilesFinder({directory: process.cwd(), processArgs: ["test"]})
|
|
6
|
+
const testFiles = await testFilesFinder.findTestFiles()
|
|
7
|
+
|
|
8
|
+
const sampleTestFilePath = `${process.cwd()}/spec/cli/commands/destroy/migration-spec.mjs`
|
|
9
|
+
|
|
10
|
+
expect(testFiles.includes(sampleTestFilePath)).toBe(true)
|
|
11
|
+
})
|
|
12
|
+
})
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import Database from "../../../../src/database/index.mjs"
|
|
2
|
-
import
|
|
2
|
+
import configuration from "../../../dummy/src/config/configuration.mjs"
|
|
3
3
|
import {digg} from "diggerize"
|
|
4
4
|
|
|
5
|
-
const mysqlConfig = digg(
|
|
5
|
+
const mysqlConfig = digg(configuration, "database", "default", "master")
|
|
6
6
|
const Mysql = Database.Drivers.Mysql
|
|
7
7
|
|
|
8
8
|
describe("Database - Drivers - Mysql - Connection", () => {
|
package/spec/dummy/index.mjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import Application from "../../src/application.mjs"
|
|
2
|
-
import
|
|
3
|
-
import {dirname} from "path"
|
|
4
|
-
import {fileURLToPath} from "url"
|
|
2
|
+
import dummyConfiguration from "./src/config/configuration.mjs"
|
|
5
3
|
|
|
6
4
|
export default class Dummy {
|
|
7
5
|
static current() {
|
|
@@ -13,10 +11,12 @@ export default class Dummy {
|
|
|
13
11
|
}
|
|
14
12
|
|
|
15
13
|
static async prepare() {
|
|
16
|
-
const
|
|
14
|
+
const db = dummyConfiguration.getDatabasePool()
|
|
17
15
|
|
|
18
|
-
await
|
|
19
|
-
|
|
16
|
+
await db.withConnection(async () => {
|
|
17
|
+
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))")
|
|
19
|
+
})
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
static async run(callback) {
|
|
@@ -24,21 +24,23 @@ export default class Dummy {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async run(callback) {
|
|
27
|
-
await
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
await dummyConfiguration.getDatabasePool().withConnection(async () => {
|
|
28
|
+
await this.start()
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
await Dummy.prepare()
|
|
32
|
+
await callback()
|
|
33
|
+
} finally {
|
|
34
|
+
await this.stop()
|
|
35
|
+
}
|
|
36
|
+
})
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
async start() {
|
|
38
|
-
|
|
39
|
-
const __dirname = dirname(__filename)
|
|
40
|
+
if (!dummyConfiguration.isDatabasePoolInitialized()) await dummyConfiguration.initializeDatabasePool()
|
|
40
41
|
|
|
41
42
|
this.application = new Application({
|
|
43
|
+
configuration: dummyConfiguration,
|
|
42
44
|
databases: {
|
|
43
45
|
default: {
|
|
44
46
|
host: "mysql",
|
|
@@ -46,19 +48,11 @@ export default class Dummy {
|
|
|
46
48
|
password: ""
|
|
47
49
|
}
|
|
48
50
|
},
|
|
49
|
-
debug: false,
|
|
50
|
-
directory: __dirname,
|
|
51
51
|
httpServer: {port: 3006}
|
|
52
52
|
})
|
|
53
53
|
|
|
54
54
|
await this.application.initialize()
|
|
55
55
|
await this.application.startHttpServer()
|
|
56
|
-
|
|
57
|
-
const databasePool = DatabasePool.current()
|
|
58
|
-
|
|
59
|
-
if (!databasePool.isConnected()) {
|
|
60
|
-
await databasePool.connect()
|
|
61
|
-
}
|
|
62
56
|
}
|
|
63
57
|
|
|
64
58
|
async stop() {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Configuration from "../../../../src/configuration.mjs"
|
|
2
|
+
import dummyDirectory from "../../dummy-directory.mjs"
|
|
3
|
+
|
|
4
|
+
const configuration = new Configuration({
|
|
5
|
+
database: {
|
|
6
|
+
default: {
|
|
7
|
+
master: {
|
|
8
|
+
type: "mysql",
|
|
9
|
+
host: "mariadb",
|
|
10
|
+
username: "username",
|
|
11
|
+
password: "password",
|
|
12
|
+
database: "velocious_test"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
directory: dummyDirectory()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export default configuration
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Configuration from "../../../../src/configuration.mjs"
|
|
2
|
+
import dummyDirectory from "../../dummy-directory.mjs"
|
|
3
|
+
|
|
4
|
+
const configuration = new Configuration({
|
|
5
|
+
database: {
|
|
6
|
+
default: {
|
|
7
|
+
master: {
|
|
8
|
+
type: "mysql",
|
|
9
|
+
host: "mariadb",
|
|
10
|
+
username: "peakflow",
|
|
11
|
+
password: "password",
|
|
12
|
+
database: "velocious_test",
|
|
13
|
+
useDatabase: "velocious_test"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
directory: dummyDirectory()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
export default configuration
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Migration from "../../../../../src/database/migration/index.mjs"
|
|
2
|
+
|
|
3
|
+
export default class CreateProjects extends Migration {
|
|
4
|
+
async change() {
|
|
5
|
+
await this.createTable("projects", (table) => {
|
|
6
|
+
table.bigint("id", {autoIncrement: true, primaryKey: true})
|
|
7
|
+
table.string("name", {maxLength: 100, null: false})
|
|
8
|
+
table.timestamps()
|
|
9
|
+
})
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Migration from "../../../../../src/database/migration/index.mjs"
|
|
2
|
+
|
|
3
|
+
export default class CreateTasks extends Migration {
|
|
4
|
+
async change() {
|
|
5
|
+
await this.createTable("tasks", (table) => {
|
|
6
|
+
table.bigint("id", {autoIncrement: true, primaryKey: true})
|
|
7
|
+
table.references("project")
|
|
8
|
+
table.string("name")
|
|
9
|
+
table.text("description")
|
|
10
|
+
table.timestamps()
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,24 +1,14 @@
|
|
|
1
1
|
import Client from "../../src/http-server/client/index.mjs"
|
|
2
|
-
import Configuration from "../../src/configuration.mjs"
|
|
3
2
|
import {digg} from "diggerize"
|
|
4
|
-
import
|
|
5
|
-
import {fileURLToPath} from "url"
|
|
6
|
-
import path from "path"
|
|
3
|
+
import dummyConfiguration from "../dummy/src/config/configuration.mjs"
|
|
7
4
|
|
|
8
5
|
describe("http server - client", () => {
|
|
9
6
|
it("spawns a request for each that it is fed", async () => {
|
|
10
|
-
|
|
11
|
-
const __dirname = dirname(__filename)
|
|
12
|
-
const dummyDirectory = path.join(__dirname, "../dummy")
|
|
13
|
-
const configuration = new Configuration({
|
|
14
|
-
directory: dummyDirectory
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
await configuration.initialize()
|
|
7
|
+
await dummyConfiguration.initialize()
|
|
18
8
|
|
|
19
9
|
const client = new Client({
|
|
20
10
|
clientCount: 0,
|
|
21
|
-
configuration
|
|
11
|
+
configuration: dummyConfiguration
|
|
22
12
|
})
|
|
23
13
|
|
|
24
14
|
const strings = [
|
package/src/application.mjs
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import {digs} from "diggerize"
|
|
2
|
-
import Configuration from "./configuration.mjs"
|
|
3
2
|
import logger from "./logger.mjs"
|
|
4
3
|
import HttpServer from "./http-server/index.mjs"
|
|
5
4
|
|
|
6
5
|
export default class VelociousApplication {
|
|
7
|
-
constructor({
|
|
8
|
-
this.configuration =
|
|
6
|
+
constructor({configuration, httpServer}) {
|
|
7
|
+
this.configuration = configuration
|
|
9
8
|
this.httpServerConfiguration = httpServer ?? {}
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
async initialize() {
|
|
13
|
-
if (global.velociousApplication) throw new Error("A Velocious application is already running")
|
|
14
|
-
if (global.velociousConfiguration) throw new Error("A Velocious configuration has already been set")
|
|
15
|
-
|
|
16
|
-
global.velociousApplication = this
|
|
17
|
-
global.velociousConfiguration = this.configuration
|
|
18
|
-
|
|
19
12
|
await this.configuration.initialize()
|
|
13
|
+
|
|
14
|
+
if (!this.configuration.isDatabasePoolInitialized()) {
|
|
15
|
+
await this.configuration.initializeDatabasePool()
|
|
16
|
+
}
|
|
20
17
|
}
|
|
21
18
|
|
|
22
19
|
isActive() {
|
|
@@ -49,8 +46,5 @@ export default class VelociousApplication {
|
|
|
49
46
|
logger(this, "Stopping server")
|
|
50
47
|
|
|
51
48
|
await this.httpServer.stop()
|
|
52
|
-
|
|
53
|
-
global.velociousApplication = undefined
|
|
54
|
-
global.velociousConfiguration = undefined
|
|
55
49
|
}
|
|
56
50
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
|
|
3
|
+
export default class VelociousCliBaseCommand {
|
|
4
|
+
constructor(args) {
|
|
5
|
+
this.args = args
|
|
6
|
+
this.configuration = this.args.configuration
|
|
7
|
+
this.processArgs = args.processArgs
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
directory = () => digg(this, "configuration", "directory")
|
|
11
|
+
}
|
|
@@ -1,14 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import BaseCommand from "../../base-command.mjs"
|
|
2
|
+
import {digg} from "diggerize"
|
|
3
|
+
import TableData from "../../../database/table-data/index.mjs"
|
|
4
|
+
|
|
5
|
+
export default class DbCreate extends BaseCommand{
|
|
6
|
+
async execute() {
|
|
7
|
+
this.databasePool = this.configuration.getDatabasePool()
|
|
8
|
+
this.newConfiguration = Object.assign({}, this.databasePool.getConfiguration())
|
|
9
|
+
|
|
10
|
+
if (this.args.testing) this.result = []
|
|
11
|
+
|
|
12
|
+
// Use a database known to exist. Since we are creating the database, it shouldn't actually exist which would make connecting fail.
|
|
13
|
+
this.newConfiguration.database = this.newConfiguration.useDatabase || "mysql"
|
|
14
|
+
|
|
15
|
+
this.databaseConnection = await this.databasePool.spawnConnectionWithConfiguration(this.newConfiguration)
|
|
16
|
+
await this.databaseConnection.connect()
|
|
17
|
+
|
|
18
|
+
this.createDatabase()
|
|
19
|
+
await this.createSchemaMigrationsTable()
|
|
20
|
+
|
|
21
|
+
await this.databaseConnection.close()
|
|
22
|
+
|
|
23
|
+
if (this.args.testing) return this.result
|
|
4
24
|
}
|
|
5
25
|
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
26
|
+
async createDatabase() {
|
|
27
|
+
const databaseName = digg(this.databasePool.getConfiguration(), "database")
|
|
28
|
+
const sql = this.databaseConnection.createDatabaseSql(databaseName, {ifNotExists: true})
|
|
29
|
+
|
|
30
|
+
if (this.args.testing) {
|
|
31
|
+
this.result.push({databaseName, sql})
|
|
32
|
+
} else {
|
|
33
|
+
await this.databaseConnection.query(sql)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async createSchemaMigrationsTable() {
|
|
38
|
+
const schemaMigrationsTable = new TableData("schema_migrations", {ifNotExists: true})
|
|
39
|
+
|
|
40
|
+
schemaMigrationsTable.string("version", {null: false, primaryKey: true})
|
|
9
41
|
|
|
10
|
-
|
|
42
|
+
const createSchemaMigrationsTableSql = this.databaseConnection.createTableSql(schemaMigrationsTable)
|
|
11
43
|
|
|
12
|
-
|
|
44
|
+
if (this.args.testing) {
|
|
45
|
+
this.result.push({createSchemaMigrationsTableSql})
|
|
46
|
+
} else {
|
|
47
|
+
await this.databaseConnection.query(createSchemaMigrationsTableSql)
|
|
48
|
+
}
|
|
13
49
|
}
|
|
14
50
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import BaseCommand from "../../base-command.mjs"
|
|
2
|
+
import {digg} from "diggerize"
|
|
3
|
+
import fs from "node:fs/promises"
|
|
4
|
+
import inflection from "inflection"
|
|
5
|
+
|
|
6
|
+
export default class DbMigrate extends BaseCommand {
|
|
7
|
+
async execute() {
|
|
8
|
+
const projectPath = digg(this.configuration, "directory")
|
|
9
|
+
const migrationsPath = `${projectPath}/src/database/migrations`
|
|
10
|
+
let files = await fs.readdir(migrationsPath)
|
|
11
|
+
|
|
12
|
+
files = files
|
|
13
|
+
.map((file) => {
|
|
14
|
+
const match = file.match(/^(\d{14})-(.+)\.mjs$/)
|
|
15
|
+
|
|
16
|
+
if (!match) return null
|
|
17
|
+
|
|
18
|
+
const date = parseInt(match[1])
|
|
19
|
+
const migrationName = match[2]
|
|
20
|
+
const migrationClassName = inflection.camelize(migrationName)
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
file,
|
|
24
|
+
fullPath: `${migrationsPath}/${file}`,
|
|
25
|
+
date,
|
|
26
|
+
migrationClassName
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
.filter((migration) => Boolean(migration))
|
|
30
|
+
.sort((migration1, migration2) => migration1.date - migration2.date)
|
|
31
|
+
|
|
32
|
+
for (const migration of files) {
|
|
33
|
+
await this.runMigrationFile(migration)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async runMigrationFile(migration) {
|
|
38
|
+
if (!this.configuration.isDatabasePoolInitialized()) {
|
|
39
|
+
await this.configuration.initializeDatabasePool()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
await this.configuration.databasePool.withConnection(async () => {
|
|
43
|
+
const migrationImport = await import(migration.fullPath)
|
|
44
|
+
const MigrationClass = migrationImport.default
|
|
45
|
+
const migrationInstance = new MigrationClass({
|
|
46
|
+
configuration: this.configuration
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
if (migrationInstance.change) {
|
|
50
|
+
await migrationInstance.change()
|
|
51
|
+
} else if (migrationInstance.up) {
|
|
52
|
+
await migrationInstance.up()
|
|
53
|
+
} else {
|
|
54
|
+
throw new Error(`'change' or 'up' didn't exist on migration: ${migration.file}`)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import BaseCommand from "../../base-command.mjs"
|
|
2
|
+
import fs from "node:fs/promises"
|
|
3
|
+
|
|
4
|
+
export default class DbDestroyMigration extends BaseCommand {
|
|
5
|
+
async execute() {
|
|
6
|
+
const migrationName = this.processArgs[1]
|
|
7
|
+
const migrationDir = `${this.configuration.directory}/src/database/migrations`
|
|
8
|
+
const migrationFiles = await fs.readdir(migrationDir)
|
|
9
|
+
const destroyed = []
|
|
10
|
+
|
|
11
|
+
for (const migrationFile of migrationFiles) {
|
|
12
|
+
const match = migrationFile.match(/^(\d{14})-(.+)\.mjs$/)
|
|
13
|
+
|
|
14
|
+
if (!match) {
|
|
15
|
+
continue
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const fileName = match[2]
|
|
19
|
+
|
|
20
|
+
if (fileName != migrationName) continue
|
|
21
|
+
|
|
22
|
+
const fullFilePath = `${migrationDir}/${migrationFile}`
|
|
23
|
+
destroyed.push(fileName)
|
|
24
|
+
|
|
25
|
+
if (!this.args.testing) {
|
|
26
|
+
console.log(`Destroy src/database/migrations/${migrationFile}`)
|
|
27
|
+
await fs.unlink(fullFilePath)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (this.args.testing) {
|
|
32
|
+
return {destroyed}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|