velocious 1.0.67 → 1.0.68

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 CHANGED
@@ -62,14 +62,51 @@ await project.loadTasks()
62
62
  const tasks = project.tasks().loaded()
63
63
  ```
64
64
 
65
+ ### Create records
66
+
67
+ ```js
68
+ const task = new Task({identifier: "task-4"})
69
+
70
+ task.assign({name: "New task})
71
+
72
+ await task.save()
73
+ ```
74
+
75
+ ```js
76
+ const task = await Task.create({name: "Task 4"})
77
+ ```
78
+
79
+ ### Find or create records
80
+
81
+ ```js
82
+ const task = await Task.findOrInitializeBy({identifier: "task-5"})
83
+
84
+ if (task.isNewRecord()) {
85
+ console.log("Task didn't already exist")
86
+
87
+ await task.save()
88
+ }
89
+
90
+ if (task.isPersisted()) {
91
+ console.log("Task already exist")
92
+ }
93
+ ```
94
+
95
+ ```js
96
+ const task = await Task.findOrCreateBy({identifier: "task-5"}, (newTask) => {
97
+ newTask.assign({description: "This callback only happens if not already existing"})
98
+ })
99
+ ```
100
+
65
101
  # Migrations
66
102
 
67
- Make a new migration from a template like this:
103
+ ## Make a new migration from a template
68
104
 
69
105
  ```bash
70
106
  npx velocious g:migration create-tasks
71
107
  ```
72
108
 
109
+ ## Write a migration
73
110
  ```js
74
111
  import Migration from "velocious/src/database/migration/index.js"
75
112
 
@@ -96,12 +133,13 @@ export default class CreateEvents extends Migration {
96
133
  }
97
134
  ```
98
135
 
99
- Run migrations from the command line like this:
136
+ ## Run migrations from the command line
137
+
100
138
  ```bash
101
139
  npx velocious db:migrate
102
140
  ```
103
141
 
104
- Run migrations from anywhere if you want to:
142
+ ## Run migrations from anywhere if you want to:
105
143
 
106
144
  ```js
107
145
  const migrationsPath = `/some/dir/migrations`
@@ -122,7 +160,10 @@ import {Task} from "@/src/models/task"
122
160
 
123
161
  const tasks = await Task
124
162
  .preload({project: {account: true}})
163
+ .joins({project: true})
125
164
  .where({projects: {public: true}})
165
+ .joins("JOIN task_details ON task_details.task_id = tasks.id")
166
+ .where("task_details.id IS NOT NULL")
126
167
  .order("name")
127
168
  .limit(5)
128
169
  .toArray()
@@ -138,7 +179,7 @@ npx velocious test
138
179
  If you are developing on Velocious, you can run the tests with:
139
180
 
140
181
  ```bash
141
- npm run test
182
+ ./run-tests.sh
142
183
  ```
143
184
 
144
185
  # Writing a request test
@@ -169,8 +210,63 @@ await describe("accounts - create", {type: "request"}, async () => {
169
210
  })
170
211
  ```
171
212
 
213
+ # Routes
214
+
215
+ Create or edit the file `src/config/routes.js` and do something like this:
216
+
217
+ ```js
218
+ import Routes from "velocious/src/routes/index.js"
219
+
220
+ const routes = new Routes()
221
+
222
+ routes.draw((route) => {
223
+ route.resources("projects")
224
+
225
+ route.resources("tasks", (route) => {
226
+ route.get("users")
227
+ })
228
+
229
+ route.namespace("testing", (route) => {
230
+ route.post("truncate")
231
+ })
232
+
233
+ route.get("ping")
234
+ })
235
+
236
+ export default {routes}
237
+ ```
238
+
239
+ # Controllers
240
+
241
+ Create the file `src/routes/testing/controller.js` and do something like this:
242
+
243
+ ```js
244
+ import Controller from "velocious/src/controller.js"
245
+
246
+ export default class TestingController extends Controller {
247
+ async truncate() {
248
+ await doSomething()
249
+ this.renderJson({status: "database-truncated"})
250
+ }
251
+
252
+ async anotherAction() {
253
+ render("test-view")
254
+ }
255
+ }
256
+ ```
257
+
258
+ # Views
259
+
260
+ Create the file `src/routes/testing/another-action.ejs` and so something like this:
261
+
262
+ ```ejs
263
+ <p>
264
+ View for path: <%= controller.getRequest().path() %>
265
+ </p>
266
+ ```
267
+
172
268
  # Running a server
173
269
 
174
270
  ```bash
175
- npx velocious server
271
+ npx velocious server --host 0.0.0.0 --port 8082
176
272
  ```
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.67",
6
+ "version": "1.0.68",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "test": "VELOCIOUS_TEST_DIR=../ cd spec/dummy && npx velocious test",
@@ -0,0 +1,59 @@
1
+ import Dummy from "../../dummy/index.js"
2
+ import Task from "../../dummy/src/models/task.js"
3
+
4
+ describe("Record - find or create", () => {
5
+ it("doesnt find but then creates a record", async () => {
6
+ await Dummy.run(async () => {
7
+ const task = await Task.findOrCreateBy({name: "Test task"}, (newTask) => {
8
+ const project = newTask.buildProject({nameEn: "Test project", nameDe: "Test projekt"})
9
+
10
+ project.buildProjectDetail({note: "Test note"})
11
+ })
12
+
13
+ const project = task.project()
14
+
15
+ expect(task.isPersisted()).toBeTrue()
16
+ expect(task.isNewRecord()).toBeFalse()
17
+ expect(task.id()).not.toBeUndefined()
18
+ expect(task.name()).toEqual("Test task")
19
+ expect(task.project().id()).toEqual(project.id())
20
+ expect(task.project()).toEqual(project)
21
+
22
+ expect(project.id()).not.toBeUndefined()
23
+ expect(project.name()).toEqual("Test project")
24
+ expect(project.nameDe()).toEqual("Test projekt")
25
+ expect(project.nameEn()).toEqual("Test project")
26
+ expect(project.createdAt()).toBeInstanceOf(Date)
27
+ expect(project.updatedAt()).toBeInstanceOf(Date)
28
+
29
+ // 'name' is not a column but rather a column on the translation data model.
30
+ expect(() => project.readColumn("name")).toThrowError("No such attribute or not selected Project#name")
31
+
32
+
33
+ // It saves a project note through a has one relationship
34
+ const projectDetail = project.projectDetail()
35
+
36
+ expect(projectDetail.isNewRecord()).toBeFalse()
37
+ expect(projectDetail.isPersisted()).toBeTrue()
38
+ expect(projectDetail.note()).toEqual("Test note")
39
+ expect(projectDetail.projectId()).toEqual(project.id())
40
+
41
+
42
+ // It automatically sets the relationship that saved it on a has-one-relationship
43
+ const projectInstanceRelationship = projectDetail.getRelationshipByName("project")
44
+
45
+ expect(projectInstanceRelationship.getPreloaded()).toBeTrue()
46
+ expect(projectDetail.project().id()).toEqual(project.id())
47
+
48
+
49
+ // It automatically sets the relationship that saved it on a has-many-relationship
50
+ const tasksRelationship = project.getRelationshipByName("tasks")
51
+
52
+ expect(tasksRelationship.getPreloaded()).toBeTrue()
53
+
54
+ const projectTasksIDs = project.tasks().loaded().map((task) => task.id())
55
+
56
+ expect(projectTasksIDs).toEqual([task.id()])
57
+ })
58
+ })
59
+ })
@@ -125,7 +125,7 @@ export default class VelociousDatabaseDriversBase {
125
125
  }
126
126
 
127
127
  quoteTable(tableName) {
128
- return this.options().quoteColumnName(tableName)
128
+ return this.options().quoteTableName(tableName)
129
129
  }
130
130
 
131
131
  newQuery() {
@@ -108,8 +108,8 @@ export default class VelociousDatabaseQuery {
108
108
  return await this.clone().where(newConditions).first()
109
109
  }
110
110
 
111
- async findOrCreateBy(conditions) {
112
- const record = await this.findOrInitializeBy(conditions)
111
+ async findOrCreateBy(...args) {
112
+ const record = await this.findOrInitializeBy(...args)
113
113
 
114
114
  if (record.isNewRecord()) {
115
115
  await record.save()
@@ -118,13 +118,17 @@ export default class VelociousDatabaseQuery {
118
118
  return record
119
119
  }
120
120
 
121
- async findOrInitializeBy(conditions) {
121
+ async findOrInitializeBy(conditions, callback) {
122
122
  const record = await this.findBy(conditions)
123
123
 
124
124
  if (record) return record
125
125
 
126
126
  const newRecord = new this.modelClass(conditions)
127
127
 
128
+ if (callback) {
129
+ callback(newRecord)
130
+ }
131
+
128
132
  return newRecord
129
133
  }
130
134
 
@@ -23,7 +23,7 @@ export default class VelocuiousDatabaseQueryParserWhereParser {
23
23
  for (const whereKey in query._wheres) {
24
24
  const where = query._wheres[whereKey]
25
25
 
26
- if (whereKey > 0) sql += " &&"
26
+ if (whereKey > 0) sql += " AND"
27
27
 
28
28
  if (pretty) {
29
29
  sql += "\n "
@@ -3,16 +3,24 @@ import * as inflection from "inflection"
3
3
 
4
4
  export default class VelociousDatabaseRecordValidatorsUniqueness extends Base {
5
5
  async validate({model, attributeName}) {
6
+ const modelClass = model.constructor
7
+ const connection = modelClass.connection()
8
+ const tableName = modelClass._getTable().getName()
6
9
  const attributeValue = model.readAttribute(attributeName)
7
10
  const attributeNameUnderscore = inflection.underscore(attributeName)
8
11
  const whereArgs = {}
9
12
 
10
13
  whereArgs[attributeNameUnderscore] = attributeValue
11
14
 
12
- const existingRecord = await model.constructor
13
- .select(model.constructor.primaryKey())
15
+ let existingRecordQuery = model.constructor
16
+ .select(modelClass.primaryKey())
14
17
  .where(whereArgs)
15
- .first()
18
+
19
+ if (model.isPersisted()) {
20
+ existingRecordQuery.where(`${connection.quoteTable(tableName)}.${connection.quoteColumn(modelClass.primaryKey())} != ${connection.quote(model.id())}`)
21
+ }
22
+
23
+ const existingRecord = await existingRecordQuery.first()
16
24
 
17
25
  if (existingRecord) {
18
26
  if (!(attributeName in model._validationErrors)) model._validationErrors[attributeName] = []
@@ -92,7 +92,9 @@ export default class VeoliciousHttpServerClient {
92
92
  response.addHeader("Connection", "Close")
93
93
  }
94
94
 
95
- response.addHeader("Content-Length", response.body.length)
95
+ const textEncoded = new TextEncoder().encode(body)
96
+
97
+ response.addHeader("Content-Length", textEncoded.length)
96
98
  response.addHeader("Date", date.toUTCString())
97
99
  response.addHeader("Server", "Velocious")
98
100