velocious 1.0.1 → 1.0.2

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 (120) hide show
  1. package/README.md +26 -0
  2. package/bin/velocious.mjs +8 -0
  3. package/index.mjs +17 -0
  4. package/package.json +13 -6
  5. package/peak_flow.yml +9 -5
  6. package/spec/cli/generate/migration-spec.mjs +9 -0
  7. package/spec/database/connection/drivers/mysql/{query-parser-spec.cjs → query-parser-spec.mjs} +12 -8
  8. package/spec/database/drivers/mysql/connection-spec.mjs +21 -0
  9. package/spec/database/record/create-spec.mjs +14 -0
  10. package/spec/database/record/destroy-spec.mjs +17 -0
  11. package/spec/database/record/find-spec.mjs +29 -0
  12. package/spec/database/record/update-spec.mjs +15 -0
  13. package/spec/dummy/index.mjs +69 -0
  14. package/spec/dummy/src/config/database.example.mjs +15 -0
  15. package/spec/dummy/src/config/database.peakflow.mjs +15 -0
  16. package/spec/dummy/src/{routes.cjs → config/routes.mjs} +3 -2
  17. package/spec/dummy/src/database/migrations/001-create-tasks.mjs +12 -0
  18. package/spec/dummy/src/models/task.mjs +4 -0
  19. package/spec/dummy/src/routes/tasks/controller.mjs +26 -0
  20. package/spec/http-server/{client-spec.cjs → client-spec.mjs} +12 -5
  21. package/spec/http-server/{get-spec.cjs → get-spec.mjs} +2 -2
  22. package/spec/http-server/post-spec.mjs +72 -0
  23. package/spec/support/jasmine.json +4 -3
  24. package/src/application.mjs +56 -0
  25. package/src/cli/commands/db/create.mjs +14 -0
  26. package/src/cli/commands/generate/migration.mjs +12 -0
  27. package/src/cli/index.mjs +39 -0
  28. package/src/configuration.mjs +27 -0
  29. package/src/{controller.cjs → controller.mjs} +21 -4
  30. package/src/database/drivers/base.mjs +9 -0
  31. package/src/database/drivers/index.mjs +5 -0
  32. package/src/database/drivers/mysql/connect-connection.mjs +12 -0
  33. package/src/database/drivers/mysql/index.mjs +77 -0
  34. package/src/database/drivers/mysql/options.mjs +17 -0
  35. package/src/database/drivers/mysql/query-parser.mjs +25 -0
  36. package/src/database/drivers/mysql/query.mjs +26 -0
  37. package/src/database/drivers/mysql/sql/delete.mjs +19 -0
  38. package/src/database/drivers/mysql/sql/insert.mjs +29 -0
  39. package/src/database/drivers/mysql/sql/update.mjs +31 -0
  40. package/src/database/handler.mjs +11 -0
  41. package/src/database/index.mjs +15 -0
  42. package/src/database/migration/index.mjs +5 -0
  43. package/src/database/migrator/index.mjs +15 -0
  44. package/src/database/pool/index.mjs +43 -0
  45. package/src/database/query/delete-base.mjs +15 -0
  46. package/src/database/query/from-base.mjs +9 -0
  47. package/src/database/query/from-plain.mjs +12 -0
  48. package/src/database/query/{from-table.cjs → from-table.mjs} +2 -2
  49. package/src/database/query/index.mjs +144 -0
  50. package/src/database/query/insert-base.mjs +15 -0
  51. package/src/database/query/join-base.mjs +9 -0
  52. package/src/database/query/join-plain.mjs +12 -0
  53. package/src/database/query/order-base.mjs +9 -0
  54. package/src/database/query/order-plain.mjs +21 -0
  55. package/src/database/query/select-base.mjs +9 -0
  56. package/src/database/query/select-plain.mjs +12 -0
  57. package/src/database/query/{select-table-and-column.cjs → select-table-and-column.mjs} +4 -4
  58. package/src/database/query/update-base.mjs +16 -0
  59. package/src/database/query-parser/{from-parser.cjs → from-parser.mjs} +3 -6
  60. package/src/database/query-parser/{joins-parser.cjs → joins-parser.mjs} +3 -6
  61. package/src/database/query-parser/{options.cjs → options.mjs} +13 -2
  62. package/src/database/query-parser/{select-parser.cjs → select-parser.mjs} +7 -6
  63. package/src/database/record/index.mjs +187 -0
  64. package/src/database/record/record-not-found-error.mjs +1 -0
  65. package/src/{error-logger.js → error-logger.mjs} +1 -1
  66. package/src/http-server/client/{index.cjs → index.mjs} +10 -11
  67. package/src/http-server/client/params-to-object.mjs +68 -0
  68. package/src/http-server/client/request-buffer/form-data-part.mjs +42 -0
  69. package/src/http-server/client/request-buffer/header.mjs +7 -0
  70. package/src/http-server/client/request-buffer/index.mjs +229 -0
  71. package/src/http-server/client/request-parser.mjs +47 -0
  72. package/src/http-server/client/{request-runner.cjs → request-runner.mjs} +5 -5
  73. package/src/http-server/client/request.mjs +15 -0
  74. package/src/http-server/client/{response.cjs → response.mjs} +1 -1
  75. package/src/http-server/index.mjs +137 -0
  76. package/src/http-server/server-client.mjs +47 -0
  77. package/src/http-server/worker-handler/index.mjs +79 -0
  78. package/src/http-server/worker-handler/worker-script.mjs +4 -0
  79. package/src/http-server/worker-handler/{worker-thread.cjs → worker-thread.mjs} +18 -11
  80. package/src/{logger.cjs → logger.mjs} +2 -2
  81. package/src/routes/base-route.mjs +34 -0
  82. package/src/routes/{get-route.cjs → get-route.mjs} +5 -3
  83. package/src/routes/index.mjs +9 -0
  84. package/src/routes/{resolver.cjs → resolver.mjs} +15 -9
  85. package/src/routes/{resource-route.cjs → resource-route.mjs} +9 -5
  86. package/src/routes/root-route.mjs +6 -0
  87. package/bin/velocious +0 -14
  88. package/index.cjs +0 -13
  89. package/spec/dummy/config/databases.example.json +0 -10
  90. package/spec/dummy/config/databases.json +0 -0
  91. package/spec/dummy/config/databases.peakflow.json +0 -11
  92. package/spec/dummy/index.cjs +0 -40
  93. package/spec/dummy/src/models/task.cjs +0 -4
  94. package/spec/dummy/src/routes/tasks/controller.cjs +0 -18
  95. package/src/application.cjs +0 -36
  96. package/src/configuration.cjs +0 -14
  97. package/src/database/connection/drivers/mysql/index.cjs +0 -5
  98. package/src/database/connection/drivers/mysql/options.cjs +0 -7
  99. package/src/database/connection/drivers/mysql/query-parser.cjs +0 -26
  100. package/src/database/connection/index.cjs +0 -2
  101. package/src/database/handler.cjs +0 -5
  102. package/src/database/index.cjs +0 -9
  103. package/src/database/pool/index.cjs +0 -2
  104. package/src/database/query/from-base.cjs +0 -15
  105. package/src/database/query/from-plain.cjs +0 -12
  106. package/src/database/query/index.cjs +0 -59
  107. package/src/database/query/join-base.cjs +0 -15
  108. package/src/database/query/join-plain.cjs +0 -12
  109. package/src/database/query/select-base.cjs +0 -15
  110. package/src/database/query/select-plain.cjs +0 -12
  111. package/src/database/record/index.cjs +0 -5
  112. package/src/http-server/client/request-parser.cjs +0 -92
  113. package/src/http-server/client/request.cjs +0 -25
  114. package/src/http-server/index.cjs +0 -78
  115. package/src/http-server/worker-handler/index.cjs +0 -78
  116. package/src/http-server/worker-handler/socket-handler.cjs +0 -35
  117. package/src/http-server/worker-handler/worker-script.cjs +0 -4
  118. package/src/routes/base-route.cjs +0 -25
  119. package/src/routes/index.cjs +0 -9
  120. package/src/routes/root-route.cjs +0 -4
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # README
2
+
3
+ This is still work in progress.
4
+
5
+ * Concurrent multi threadded web server
6
+ * Database framework ala Rails
7
+ * Database models ala Rails
8
+ * Database models that work almost the same in frontend and backend
9
+ * Migrations ala Rails
10
+ * Controllers and views ala Rails
11
+
12
+ ## Migrations
13
+
14
+ ```bash
15
+ npx velocious db:g:migration create_tasks
16
+ ```
17
+
18
+ ```bash
19
+ npx velocious db:migrate
20
+ ```
21
+
22
+ ## Testing
23
+
24
+ ```bash
25
+ npm test
26
+ ```
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/node
2
+
3
+ import Cli from "../src/cli/index.mjs"
4
+
5
+ const cli = new Cli()
6
+ const args = process.argv.slice(2)
7
+
8
+ cli.execute({args})
package/index.mjs ADDED
@@ -0,0 +1,17 @@
1
+ import Application from "./src/application.mjs"
2
+ import Cli from "./src/cli/index.mjs"
3
+ import Controller from "./src/controller.mjs"
4
+ import Database from "./src/database/index.mjs"
5
+ import DatabasePool from "./src/database/pool/index.mjs"
6
+ import HttpServer from "./src/http-server/index.mjs"
7
+ import Routes from "./src/routes/index.mjs"
8
+
9
+ export {
10
+ Application,
11
+ Cli,
12
+ Controller,
13
+ Database,
14
+ DatabasePool,
15
+ HttpServer,
16
+ Routes
17
+ }
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
+ "bin": {
3
+ "velocious": "bin/velocious.mjs"
4
+ },
2
5
  "name": "velocious",
3
- "version": "1.0.1",
4
- "main": "index.cjs",
6
+ "version": "1.0.2",
7
+ "main": "index.mjs",
5
8
  "scripts": {
6
- "test": "jasmine"
9
+ "test": "jasmine",
10
+ "velocious": "asd"
7
11
  },
12
+ "type": "module",
8
13
  "repository": {
9
14
  "type": "git",
10
15
  "url": "git+https://github.com/kaspernj/velocious.git"
@@ -17,13 +22,15 @@
17
22
  "homepage": "https://github.com/kaspernj/velocious#readme",
18
23
  "description": "",
19
24
  "devDependencies": {
20
- "jasmine": "^4.0.2",
21
- "node-fetch": "^2.6.1"
25
+ "jasmine": "^5.0.2",
26
+ "mysql": "^2.18.1",
27
+ "node-fetch": "^3.3.1"
22
28
  },
23
29
  "dependencies": {
24
30
  "diggerize": "^1.0.3",
25
31
  "ejs": "^3.1.6",
26
32
  "escape-string-regexp": "^1.0.5",
27
- "inflection": "^1.13.2"
33
+ "incorporator": "^1.0.2",
34
+ "inflection": "^2.0.0"
28
35
  }
29
36
  }
package/peak_flow.yml CHANGED
@@ -1,17 +1,21 @@
1
+ before_install:
2
+ - curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
3
+ - sudo apt-get install -y nodejs
1
4
  before_script:
2
- - cp spec/dummy/config/databases.peakflow.json spec/dummy/config/databases.json
5
+ - cp spec/dummy/src/config/database.peakflow.mjs spec/dummy/src/config/database.mjs
3
6
  - npm install
4
- - wait-for-it mysql:3306
7
+ - wait-for-it mariadb:3306
5
8
  services:
6
- mysql:
9
+ mariadb:
7
10
  environment:
8
11
  MYSQL_USER: peakflow
9
12
  MYSQL_PASSWORD: password
10
13
  MYSQL_ROOT_PASSWORD: password
11
14
  MYSQL_DATABASE: velocious_test
12
- image: mysql:8.0.22
15
+ image: mariadb:latest
13
16
  expose:
14
17
  - 3306
15
- mem_limit: 2048m
18
+ mem_limit: 4096m
19
+ restart_policy: on-failure
16
20
  script:
17
21
  - npm test
@@ -0,0 +1,9 @@
1
+ import Cli from "../../../src/cli/index.mjs"
2
+
3
+ describe("Cli - generate - migration", () => {
4
+ it("generates a new migration", async () => {
5
+ const cli = new Cli()
6
+
7
+ await cli.execute({args: ["g:migration", "create_tasks"]})
8
+ })
9
+ })
@@ -1,13 +1,17 @@
1
- const {Database: {Handler, Query}} = require("../../../../../index.cjs")
2
- const MysqlQueryParser = require("../../../../../src/database/connection/drivers/mysql/query-parser.cjs")
1
+ import Database from "../../../../../src/database/index.mjs"
2
+ import MysqlQueryParser from "../../../../../src/database/drivers/mysql/query-parser.mjs"
3
3
 
4
- const FromTable = require("../../../../../src/database/query/from-table.cjs")
5
- const SelectTableAndColumn = require("../../../../../src/database/query/select-table-and-column.cjs")
4
+ import FromTable from "../../../../../src/database/query/from-table.mjs"
5
+ import SelectTableAndColumn from "../../../../../src/database/query/select-table-and-column.mjs"
6
+
7
+ import MysqlDriverClass from "../../../../../src/database/drivers/mysql/index.mjs"
8
+
9
+ const mysqlDriver = new MysqlDriverClass()
6
10
 
7
11
  describe("database - connection - drivers - mysql - query parser", () => {
8
12
  it("generates sql with selects, joins and orders", () => {
9
- const handler = new Handler()
10
- const query = new Query({handler})
13
+ const handler = new Database.Handler()
14
+ const query = new Database.Query({driver: mysqlDriver, handler})
11
15
  .select(["tasks.id", "tasks.name"])
12
16
  .from("tasks")
13
17
  .joins("LEFT JOIN projects ON projects.id = tasks.project_id")
@@ -18,8 +22,8 @@ describe("database - connection - drivers - mysql - query parser", () => {
18
22
  })
19
23
 
20
24
  it("generates sql with selects, joins and orders", () => {
21
- const handler = new Handler()
22
- const query = new Query({handler})
25
+ const handler = new Database.Handler()
26
+ const query = new Database.Query({driver: mysqlDriver, handler})
23
27
  .select([
24
28
  new SelectTableAndColumn({tableName: "tasks", columnName: "id"}),
25
29
  new SelectTableAndColumn({tableName: "tasks", columnName: "name"})
@@ -0,0 +1,21 @@
1
+ import Database from "../../../../src/database/index.mjs"
2
+ import {databaseConfiguration} from "../../../dummy/src/config/database.mjs"
3
+ import {digg} from "diggerize"
4
+
5
+ const mysqlConfig = digg(databaseConfiguration(), "default", "master")
6
+ const Mysql = Database.Drivers.Mysql
7
+
8
+ describe("Database - Drivers - Mysql - Connection", () => {
9
+ it("connects", async () => {
10
+ const mysql = new Mysql(mysqlConfig)
11
+
12
+ await mysql.connect()
13
+
14
+ const result = await mysql.query("SELECT \"1\" AS test1, \"2\" AS test2")
15
+
16
+ expect(result).toEqual([{
17
+ test1: "1",
18
+ test2: "2"
19
+ }])
20
+ })
21
+ })
@@ -0,0 +1,14 @@
1
+ import Dummy from "../../dummy/index.mjs"
2
+ import Task from "../../dummy/src/models/task.mjs"
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
+
9
+ await task.save()
10
+
11
+ expect(task.id()).not.toBeUndefined()
12
+ })
13
+ })
14
+ })
@@ -0,0 +1,17 @@
1
+ import Dummy from "../../dummy/index.mjs"
2
+ import Task from "../../dummy/src/models/task.mjs"
3
+
4
+ describe("Record - destroy", () => {
5
+ it("destroys a record", async () => {
6
+ await Dummy.run(async () => {
7
+ const task = new Task({name: "Test task"})
8
+
9
+ await task.save()
10
+ await task.destroy()
11
+
12
+ const foundTask = await Task.where({id: task.id()}).first()
13
+
14
+ expect(foundTask).toEqual(undefined)
15
+ })
16
+ })
17
+ })
@@ -0,0 +1,29 @@
1
+ import Dummy from "../../dummy/index.mjs"
2
+ import RecordNotFoundError from "../../../src/database/record/record-not-found-error.mjs"
3
+ import Task from "../../dummy/src/models/task.mjs"
4
+
5
+ describe("Record - find", () => {
6
+ it("finds an existing record", async () => {
7
+ await Dummy.run(async () => {
8
+ const task = new Task({name: "Test task"})
9
+
10
+ await task.save()
11
+
12
+ const foundTask = await Task.find(task.id())
13
+
14
+ expect(foundTask.readAttribute("name")).toEqual("Test task")
15
+ })
16
+ })
17
+
18
+ it("raises an error when a record isn't found", async () => {
19
+ await Dummy.run(async () => {
20
+ try {
21
+ await Task.find(123)
22
+ throw new Error("Didn't expect to reach this")
23
+ } catch (error) {
24
+ expect(error.message).toEqual("Couldn't find Task with 'id'=123")
25
+ expect(error.constructor.name).toEqual("RecordNotFoundError")
26
+ }
27
+ })
28
+ })
29
+ })
@@ -0,0 +1,15 @@
1
+ import Dummy from "../../dummy/index.mjs"
2
+ import Task from "../../dummy/src/models/task.mjs"
3
+
4
+ describe("Record - update", () => {
5
+ it("updates a record", async () => {
6
+ await Dummy.run(async () => {
7
+ const task = new Task({name: "Test task"})
8
+
9
+ await task.save()
10
+ await task.update({name: "Updated name"})
11
+
12
+ expect(task.readAttribute("name")).toEqual("Updated name")
13
+ })
14
+ })
15
+ })
@@ -0,0 +1,69 @@
1
+ import Application from "../../src/application.mjs"
2
+ import DatabasePool from "../../src/database/pool/index.mjs"
3
+ import {dirname} from "path"
4
+ import {fileURLToPath} from "url"
5
+
6
+ export default class Dummy {
7
+ static current() {
8
+ if (!global.velociousDummy) {
9
+ global.velociousDummy = new Dummy()
10
+ }
11
+
12
+ return global.velociousDummy
13
+ }
14
+
15
+ static async prepare() {
16
+ const connection = DatabasePool.current().singleConnection()
17
+
18
+ await connection.query("DROP TABLE IF EXISTS tasks")
19
+ await connection.query("CREATE TABLE tasks (id MEDIUMINT NOT NULL AUTO_INCREMENT, name VARCHAR(255), description TEXT, PRIMARY KEY (id))")
20
+ }
21
+
22
+ static async run(callback) {
23
+ await this.current().run(callback)
24
+ }
25
+
26
+ async run(callback) {
27
+ await this.start()
28
+
29
+ try {
30
+ await Dummy.prepare()
31
+ await callback()
32
+ } finally {
33
+ await this.stop()
34
+ }
35
+ }
36
+
37
+ async start() {
38
+ const __filename = fileURLToPath(import.meta.url)
39
+ const __dirname = dirname(__filename)
40
+
41
+ this.application = new Application({
42
+ databases: {
43
+ default: {
44
+ host: "mysql",
45
+ username: "user",
46
+ password: ""
47
+ }
48
+ },
49
+ debug: false,
50
+ directory: __dirname,
51
+ httpServer: {port: 3006}
52
+ })
53
+
54
+ await this.application.initialize()
55
+ await this.application.startHttpServer()
56
+
57
+ const databasePool = DatabasePool.current()
58
+
59
+ if (!databasePool.isConnected()) {
60
+ await databasePool.connect()
61
+ }
62
+ }
63
+
64
+ async stop() {
65
+ if (this.application.isActive()) {
66
+ await this.application.stop()
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,15 @@
1
+ const databaseConfiguration = () => {
2
+ return {
3
+ "default": {
4
+ "master": {
5
+ "type": "mysql",
6
+ "host": "mariadb",
7
+ "username": "username",
8
+ "password": "password",
9
+ "database": "velocious_test"
10
+ }
11
+ }
12
+ }
13
+ }
14
+
15
+ export {databaseConfiguration}
@@ -0,0 +1,15 @@
1
+ const databaseConfiguration = () => {
2
+ return {
3
+ "default": {
4
+ "master": {
5
+ "type": "mysql",
6
+ "host": "mariadb",
7
+ "username": "peakflow",
8
+ "password": "password",
9
+ "database": "velocious_test"
10
+ }
11
+ }
12
+ }
13
+ }
14
+
15
+ export {databaseConfiguration}
@@ -1,4 +1,5 @@
1
- const Routes = require("../../../src/routes/index.cjs")
1
+ import Routes from "../../../../src/routes/index.mjs"
2
+
2
3
  const routes = new Routes()
3
4
 
4
5
  routes.draw((route) => {
@@ -7,4 +8,4 @@ routes.draw((route) => {
7
8
  })
8
9
  })
9
10
 
10
- module.exports = {routes}
11
+ export default {routes}
@@ -0,0 +1,12 @@
1
+ import {Database} from "../../../../index.mjs"
2
+
3
+ export default class CreateTasks extends Database.Migration {
4
+ change() {
5
+ this.createTable("tasks", (table) => {
6
+ table.bigint("id", {autoIncrement: true, primaryKey: true})
7
+ table.string("name")
8
+ table.text("description")
9
+ table.timestamps()
10
+ })
11
+ }
12
+ }
@@ -0,0 +1,4 @@
1
+ import Database from "../../../../src/database/index.mjs"
2
+
3
+ export default class Task extends Database.Record {
4
+ }
@@ -0,0 +1,26 @@
1
+ import Controller from "../../../../../src/controller.mjs"
2
+ import {digg} from "diggerize"
3
+ import Task from "../../models/task.mjs"
4
+
5
+ export default class TasksController extends Controller {
6
+ index() {
7
+ this.viewParams.numbers = [1, 2, 3, 4, 5]
8
+ this.render()
9
+ }
10
+
11
+ async show() {
12
+ const taskId = digg(params, "id")
13
+ const task = await Task.find(taskId)
14
+
15
+ this.viewParams.task = task
16
+ this.render()
17
+ }
18
+
19
+ async create() {
20
+ const task = new Task(this.params().task)
21
+
22
+ await task.save()
23
+
24
+ this.render({json: {status: "success"}})
25
+ }
26
+ }
@@ -1,14 +1,21 @@
1
- const Client = require("../../src/http-server/client/index.cjs")
2
- const Configuration = require("../../src/configuration.cjs")
3
- const {digg} = require("diggerize")
4
- const path = require("path")
1
+ import Client from "../../src/http-server/client/index.mjs"
2
+ import Configuration from "../../src/configuration.mjs"
3
+ import {digg} from "diggerize"
4
+ import {dirname} from "path"
5
+ import {fileURLToPath} from "url"
6
+ import path from "path"
5
7
 
6
8
  describe("http server - client", () => {
7
- it("spawns a request for each that it is fed", () => {
9
+ it("spawns a request for each that it is fed", async () => {
10
+ const __filename = fileURLToPath(import.meta.url)
11
+ const __dirname = dirname(__filename)
8
12
  const dummyDirectory = path.join(__dirname, "../dummy")
9
13
  const configuration = new Configuration({
10
14
  directory: dummyDirectory
11
15
  })
16
+
17
+ await configuration.initialize()
18
+
12
19
  const client = new Client({
13
20
  clientCount: 0,
14
21
  configuration
@@ -1,5 +1,5 @@
1
- const fetch = require("node-fetch")
2
- const Dummy = require("../dummy/index.cjs")
1
+ import fetch from "node-fetch"
2
+ import Dummy from "../dummy/index.mjs"
3
3
 
4
4
  describe("HttpServer", () => {
5
5
  it("handles get requests", async () => {
@@ -0,0 +1,72 @@
1
+ import fetch from "node-fetch"
2
+ import Dummy from "../dummy/index.mjs"
3
+ import querystring from "querystring"
4
+ import Task from "../dummy/src/models/task.mjs"
5
+
6
+ describe("HttpServer", () => {
7
+ it("handles post requests", async () => {
8
+ await Dummy.run(async () => {
9
+ const postData = querystring.stringify({"task[name]": "Test create task"})
10
+ const response = await fetch(
11
+ "http://localhost:3006/tasks",
12
+ {
13
+ body: postData,
14
+ headers: {
15
+ "Content-Type": "application/x-www-form-urlencoded",
16
+ "Content-Length": Buffer.byteLength(postData)
17
+ },
18
+ method: "POST"
19
+ }
20
+ )
21
+ const text = await response.text()
22
+ const createdTask = await Task.last()
23
+
24
+ expect(text).toEqual('{"status":"success"}')
25
+ expect(createdTask.readAttribute("name")).toEqual("Test create task")
26
+ })
27
+ })
28
+
29
+ it("handles post json requests", async () => {
30
+ await Dummy.run(async () => {
31
+ const postData = JSON.stringify({task: {name: "Test create task"}})
32
+ const response = await fetch(
33
+ "http://localhost:3006/tasks",
34
+ {
35
+ body: postData,
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ "Content-Length": Buffer.byteLength(postData)
39
+ },
40
+ method: "POST"
41
+ }
42
+ )
43
+ const text = await response.text()
44
+ const createdTask = await Task.last()
45
+
46
+ expect(text).toEqual('{"status":"success"}')
47
+ expect(createdTask.readAttribute("name")).toEqual("Test create task")
48
+ })
49
+ })
50
+
51
+ it("handles post form-data requests", async () => {
52
+ await Dummy.run(async () => {
53
+ const body = new FormData()
54
+
55
+ body.append("task[name]", "Test create task")
56
+ body.append("task[description]", "This is a task")
57
+
58
+ const response = await fetch(
59
+ "http://localhost:3006/tasks",
60
+ {
61
+ body,
62
+ method: "POST"
63
+ }
64
+ )
65
+ const text = await response.text()
66
+ const createdTask = await Task.last()
67
+
68
+ expect(text).toEqual('{"status":"success"}')
69
+ expect(createdTask.readAttribute("name")).toEqual("Test create task")
70
+ })
71
+ })
72
+ })
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "spec_dir": "spec",
3
3
  "spec_files": [
4
- "**/*[sS]pec.cjs"
4
+ "**/*-spec.mjs"
5
5
  ],
6
6
  "helpers": [
7
- "helpers/**/*.cjs"
7
+ "helpers/**/*.mjs"
8
8
  ],
9
9
  "stopSpecOnExpectationFailure": false,
10
- "random": false
10
+ "random": false,
11
+ "jsLoader": "import"
11
12
  }
@@ -0,0 +1,56 @@
1
+ import {digs} from "diggerize"
2
+ import Configuration from "./configuration.mjs"
3
+ import logger from "./logger.mjs"
4
+ import HttpServer from "./http-server/index.mjs"
5
+
6
+ export default class VelociousApplication {
7
+ constructor({debug, directory, httpServer}) {
8
+ this.configuration = new Configuration({debug, directory})
9
+ this.httpServerConfiguration = httpServer ?? {}
10
+ }
11
+
12
+ 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
+ await this.configuration.initialize()
20
+ }
21
+
22
+ isActive() {
23
+ return this.httpServer?.isActive()
24
+ }
25
+
26
+ async run(callback) {
27
+ await this.start()
28
+
29
+ try {
30
+ await callback()
31
+ } finally {
32
+ this.stop()
33
+ }
34
+ }
35
+
36
+ async startHttpServer() {
37
+ const {configuration, httpServerConfiguration} = digs(this, "configuration", "httpServerConfiguration")
38
+
39
+ const port = httpServerConfiguration.port || 3006
40
+
41
+ logger(this, `Starting server on port ${port}`)
42
+
43
+ this.httpServer = new HttpServer({configuration, port})
44
+
45
+ await this.httpServer.start()
46
+ }
47
+
48
+ async stop() {
49
+ logger(this, "Stopping server")
50
+
51
+ await this.httpServer.stop()
52
+
53
+ global.velociousApplication = undefined
54
+ global.velociousConfiguration = undefined
55
+ }
56
+ }
@@ -0,0 +1,14 @@
1
+ export default class DbCreate {
2
+ constructor({args}) {
3
+ this.args = args
4
+ }
5
+
6
+ execute() {
7
+ const migrationName = this.args[2]
8
+ const date = new Date()
9
+
10
+ console.log({ migrationName, date })
11
+
12
+ throw new Error("stub")
13
+ }
14
+ }
@@ -0,0 +1,12 @@
1
+ export default class DbGenerateMigration {
2
+ constructor({args}) {
3
+ this.args = args
4
+ }
5
+
6
+ execute() {
7
+ const migrationName = this.args[1]
8
+ const date = new Date()
9
+
10
+ console.log({ migrationName, date })
11
+ }
12
+ }