@drax/crud-back 3.2.0 → 3.4.1
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/dist/repository/AbstractSqliteRepository.js +72 -12
- package/package.json +3 -3
- package/src/repository/AbstractSqliteRepository.ts +94 -14
- package/test/people/repository/sqlite/LanguageSqliteRepository.ts +1 -6
- package/test/repository/AbstractSqliteRepository.test.ts +95 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/types/repository/AbstractSqliteRepository.d.ts +5 -0
- package/types/repository/AbstractSqliteRepository.d.ts.map +1 -1
|
@@ -6,6 +6,7 @@ class AbstractSqliteRepository {
|
|
|
6
6
|
this.tableName = '';
|
|
7
7
|
this.searchFields = [];
|
|
8
8
|
this.booleanFields = [];
|
|
9
|
+
this.jsonFields = [];
|
|
9
10
|
this.identifier = '_id';
|
|
10
11
|
if (!dataBaseFile) {
|
|
11
12
|
throw new Error("dataBaseFile is required");
|
|
@@ -30,6 +31,67 @@ class AbstractSqliteRepository {
|
|
|
30
31
|
async prepareItem(item) {
|
|
31
32
|
return item;
|
|
32
33
|
}
|
|
34
|
+
parseJsonValue(value) {
|
|
35
|
+
if (typeof value !== 'string') {
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(value);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
normalizeSqliteValue(value) {
|
|
46
|
+
if (value === undefined) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
if (value === null) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
if (typeof value === 'boolean') {
|
|
53
|
+
return value ? 1 : 0;
|
|
54
|
+
}
|
|
55
|
+
if (typeof value === 'number' || typeof value === 'string' || typeof value === 'bigint') {
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
if (Buffer.isBuffer(value)) {
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
if (value instanceof Date) {
|
|
62
|
+
return value.toISOString();
|
|
63
|
+
}
|
|
64
|
+
if (value instanceof ArrayBuffer) {
|
|
65
|
+
return Buffer.from(value);
|
|
66
|
+
}
|
|
67
|
+
if (ArrayBuffer.isView(value)) {
|
|
68
|
+
return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
|
|
69
|
+
}
|
|
70
|
+
if (typeof value === 'object') {
|
|
71
|
+
return JSON.stringify(value);
|
|
72
|
+
}
|
|
73
|
+
return String(value);
|
|
74
|
+
}
|
|
75
|
+
normalizeSqliteData(data) {
|
|
76
|
+
if (!data || typeof data !== 'object') {
|
|
77
|
+
return data;
|
|
78
|
+
}
|
|
79
|
+
for (const key of Object.keys(data)) {
|
|
80
|
+
data[key] = this.normalizeSqliteValue(data[key]);
|
|
81
|
+
}
|
|
82
|
+
return data;
|
|
83
|
+
}
|
|
84
|
+
deserializeSqliteData(item) {
|
|
85
|
+
if (!item || typeof item !== 'object') {
|
|
86
|
+
return item;
|
|
87
|
+
}
|
|
88
|
+
for (const field of this.jsonFields) {
|
|
89
|
+
if (Object.prototype.hasOwnProperty.call(item, field)) {
|
|
90
|
+
item[field] = this.parseJsonValue(item[field]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return item;
|
|
94
|
+
}
|
|
33
95
|
async execPopulate(item) {
|
|
34
96
|
for (const field of this.populateFields) {
|
|
35
97
|
if (item[field.field]) {
|
|
@@ -49,6 +111,7 @@ class AbstractSqliteRepository {
|
|
|
49
111
|
}
|
|
50
112
|
async decorate(item) {
|
|
51
113
|
await this.execPopulate(item);
|
|
114
|
+
this.deserializeSqliteData(item);
|
|
52
115
|
this.castToBoolean(item);
|
|
53
116
|
await this.prepareItem(item);
|
|
54
117
|
}
|
|
@@ -57,11 +120,6 @@ class AbstractSqliteRepository {
|
|
|
57
120
|
if (!data[this.identifier]) {
|
|
58
121
|
data[this.identifier] = randomUUID();
|
|
59
122
|
}
|
|
60
|
-
for (const key in data) {
|
|
61
|
-
if (typeof data[key] === 'boolean') {
|
|
62
|
-
data[key] = data[key] ? 1 : 0;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
123
|
if (this.hasCreatedAt()) {
|
|
66
124
|
data.createdAt = (new Date().toISOString());
|
|
67
125
|
}
|
|
@@ -69,6 +127,7 @@ class AbstractSqliteRepository {
|
|
|
69
127
|
data.updatedAt = (new Date().toISOString());
|
|
70
128
|
}
|
|
71
129
|
await this.prepareData(data);
|
|
130
|
+
this.normalizeSqliteData(data);
|
|
72
131
|
const fields = Object.keys(data)
|
|
73
132
|
.map(field => `${field}`)
|
|
74
133
|
.join(', ');
|
|
@@ -82,7 +141,7 @@ class AbstractSqliteRepository {
|
|
|
82
141
|
return item;
|
|
83
142
|
}
|
|
84
143
|
catch (e) {
|
|
85
|
-
console.error(e);
|
|
144
|
+
console.error("sqlite create", e);
|
|
86
145
|
throw SqliteErrorToValidationError(e, data);
|
|
87
146
|
}
|
|
88
147
|
}
|
|
@@ -91,15 +150,11 @@ class AbstractSqliteRepository {
|
|
|
91
150
|
}
|
|
92
151
|
async update(id, data) {
|
|
93
152
|
try {
|
|
94
|
-
for (const key in data) {
|
|
95
|
-
if (typeof data[key] === 'boolean') {
|
|
96
|
-
data[key] = data[key] ? 1 : 0;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
153
|
if (this.hasUpdatedAt()) {
|
|
100
154
|
data.updatedAt = (new Date().toISOString());
|
|
101
155
|
}
|
|
102
156
|
await this.prepareData(data);
|
|
157
|
+
this.normalizeSqliteData(data);
|
|
103
158
|
const setClauses = Object.keys(data)
|
|
104
159
|
.map(field => `${field} = @${field}`)
|
|
105
160
|
.join(', ');
|
|
@@ -159,12 +214,14 @@ class AbstractSqliteRepository {
|
|
|
159
214
|
for (const item of items) {
|
|
160
215
|
await this.decorate(item);
|
|
161
216
|
}
|
|
162
|
-
|
|
217
|
+
const pagination = {
|
|
163
218
|
page,
|
|
164
219
|
limit,
|
|
165
220
|
total: rCount.count,
|
|
166
221
|
items
|
|
167
222
|
};
|
|
223
|
+
console.log('Pagination result:', JSON.stringify(pagination, null, 4));
|
|
224
|
+
return pagination;
|
|
168
225
|
}
|
|
169
226
|
async find({ limit = 5, orderBy = '', order = 'desc', search = '', filters = [] }) {
|
|
170
227
|
let where = "";
|
|
@@ -219,6 +276,9 @@ class AbstractSqliteRepository {
|
|
|
219
276
|
return items;
|
|
220
277
|
}
|
|
221
278
|
async findById(id) {
|
|
279
|
+
if (id === undefined || id === null) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
222
282
|
const item = this.db.prepare(`SELECT *
|
|
223
283
|
FROM ${this.tableName}
|
|
224
284
|
WHERE ${this.identifier} = ?`).get(id);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "3.
|
|
6
|
+
"version": "3.4.1",
|
|
7
7
|
"description": "Crud utils across modules",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"types": "types/index.d.ts",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@drax/common-back": "^3.0.0",
|
|
26
26
|
"@drax/common-share": "^3.0.0",
|
|
27
27
|
"@drax/identity-share": "^3.0.0",
|
|
28
|
-
"@drax/media-back": "^3.
|
|
28
|
+
"@drax/media-back": "^3.4.1",
|
|
29
29
|
"@graphql-tools/load-files": "^7.0.0",
|
|
30
30
|
"@graphql-tools/merge": "^9.0.4",
|
|
31
31
|
"mongoose": "^8.23.0",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"typescript": "^5.9.3",
|
|
48
48
|
"vitest": "^3.2.4"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "bd93239e7b1cc56f1a12d9cb28ea5d87cda48c07"
|
|
51
51
|
}
|
|
@@ -23,6 +23,7 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
23
23
|
protected tableName: string = '';
|
|
24
24
|
protected searchFields: string[] = [];
|
|
25
25
|
protected booleanFields: string[] = [];
|
|
26
|
+
protected jsonFields: string[] = [];
|
|
26
27
|
protected identifier: string = '_id';
|
|
27
28
|
protected populateFields: { field: string, table: string, identifier: string }[]
|
|
28
29
|
protected tableFields: SqliteTableField[];
|
|
@@ -59,6 +60,84 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
59
60
|
return item
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
protected parseJsonValue(value: any): any {
|
|
64
|
+
if (typeof value !== 'string') {
|
|
65
|
+
return value
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(value)
|
|
70
|
+
} catch {
|
|
71
|
+
return value
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
protected normalizeSqliteValue(value: any): any {
|
|
76
|
+
if (value === undefined) {
|
|
77
|
+
return null
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (value === null) {
|
|
81
|
+
return null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof value === 'boolean') {
|
|
85
|
+
return value ? 1 : 0
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (typeof value === 'number' || typeof value === 'string' || typeof value === 'bigint') {
|
|
89
|
+
return value
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (Buffer.isBuffer(value)) {
|
|
93
|
+
return value
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (value instanceof Date) {
|
|
97
|
+
return value.toISOString()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (value instanceof ArrayBuffer) {
|
|
101
|
+
return Buffer.from(value)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (ArrayBuffer.isView(value)) {
|
|
105
|
+
return Buffer.from(value.buffer, value.byteOffset, value.byteLength)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (typeof value === 'object') {
|
|
109
|
+
return JSON.stringify(value)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return String(value)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
protected normalizeSqliteData(data: any): any {
|
|
116
|
+
if (!data || typeof data !== 'object') {
|
|
117
|
+
return data
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
for (const key of Object.keys(data)) {
|
|
121
|
+
data[key] = this.normalizeSqliteValue(data[key])
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return data
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
protected deserializeSqliteData(item: any): any {
|
|
128
|
+
if (!item || typeof item !== 'object') {
|
|
129
|
+
return item
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
for (const field of this.jsonFields) {
|
|
133
|
+
if (Object.prototype.hasOwnProperty.call(item, field)) {
|
|
134
|
+
item[field] = this.parseJsonValue(item[field])
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return item
|
|
139
|
+
}
|
|
140
|
+
|
|
62
141
|
async execPopulate(item: any) {
|
|
63
142
|
for (const field of this.populateFields) {
|
|
64
143
|
if (item[field.field]) {
|
|
@@ -81,10 +160,13 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
81
160
|
|
|
82
161
|
async decorate(item: any) {
|
|
83
162
|
await this.execPopulate(item)
|
|
163
|
+
this.deserializeSqliteData(item)
|
|
84
164
|
this.castToBoolean(item)
|
|
85
165
|
await this.prepareItem(item)
|
|
86
166
|
}
|
|
87
167
|
|
|
168
|
+
|
|
169
|
+
|
|
88
170
|
async create(data: any): Promise<T> {
|
|
89
171
|
try {
|
|
90
172
|
|
|
@@ -92,12 +174,6 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
92
174
|
data[this.identifier] = randomUUID()
|
|
93
175
|
}
|
|
94
176
|
|
|
95
|
-
for (const key in data) {
|
|
96
|
-
if (typeof data[key] === 'boolean') {
|
|
97
|
-
data[key] = data[key] ? 1 : 0
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
177
|
if (this.hasCreatedAt()) {
|
|
102
178
|
data.createdAt = (new Date().toISOString())
|
|
103
179
|
}
|
|
@@ -106,7 +182,10 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
106
182
|
data.updatedAt = (new Date().toISOString())
|
|
107
183
|
}
|
|
108
184
|
|
|
185
|
+
|
|
186
|
+
|
|
109
187
|
await this.prepareData(data)
|
|
188
|
+
this.normalizeSqliteData(data)
|
|
110
189
|
|
|
111
190
|
const fields = Object.keys(data)
|
|
112
191
|
.map(field => `${field}`)
|
|
@@ -124,7 +203,7 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
124
203
|
return item
|
|
125
204
|
|
|
126
205
|
} catch (e) {
|
|
127
|
-
console.error(e)
|
|
206
|
+
console.error("sqlite create",e)
|
|
128
207
|
throw SqliteErrorToValidationError(e, data)
|
|
129
208
|
}
|
|
130
209
|
}
|
|
@@ -137,17 +216,12 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
137
216
|
async update(id: string, data: any): Promise<T> {
|
|
138
217
|
try {
|
|
139
218
|
|
|
140
|
-
for (const key in data) {
|
|
141
|
-
if (typeof data[key] === 'boolean') {
|
|
142
|
-
data[key] = data[key] ? 1 : 0
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
219
|
if (this.hasUpdatedAt()) {
|
|
147
220
|
data.updatedAt = (new Date().toISOString())
|
|
148
221
|
}
|
|
149
222
|
|
|
150
223
|
await this.prepareData(data)
|
|
224
|
+
this.normalizeSqliteData(data)
|
|
151
225
|
|
|
152
226
|
const setClauses = Object.keys(data)
|
|
153
227
|
.map(field => `${field} = @${field}`)
|
|
@@ -237,12 +311,14 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
237
311
|
await this.decorate(item)
|
|
238
312
|
}
|
|
239
313
|
|
|
240
|
-
|
|
314
|
+
const pagination = {
|
|
241
315
|
page,
|
|
242
316
|
limit,
|
|
243
317
|
total: rCount.count,
|
|
244
318
|
items
|
|
245
319
|
}
|
|
320
|
+
console.log('Pagination result:', JSON.stringify(pagination,null,4))
|
|
321
|
+
return pagination
|
|
246
322
|
}
|
|
247
323
|
|
|
248
324
|
async find({
|
|
@@ -327,6 +403,10 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
327
403
|
}
|
|
328
404
|
|
|
329
405
|
async findById(id: string): Promise<T | null> {
|
|
406
|
+
if (id === undefined || id === null) {
|
|
407
|
+
return null
|
|
408
|
+
}
|
|
409
|
+
|
|
330
410
|
const item = this.db.prepare(`SELECT *
|
|
331
411
|
FROM ${this.tableName}
|
|
332
412
|
WHERE ${this.identifier} = ?`).get(id);
|
|
@@ -11,6 +11,7 @@ class LanguageSqliteRepository extends AbstractSqliteRepository<ILanguage, ILang
|
|
|
11
11
|
protected dataBaseFile: string;
|
|
12
12
|
protected searchFields: string[] = ['name'];
|
|
13
13
|
protected booleanFields: string[] = [];
|
|
14
|
+
protected jsonFields: string[] = ['icon'];
|
|
14
15
|
protected identifier: string = '_id';
|
|
15
16
|
protected populateFields = [
|
|
16
17
|
|
|
@@ -25,13 +26,7 @@ class LanguageSqliteRepository extends AbstractSqliteRepository<ILanguage, ILang
|
|
|
25
26
|
async prepareData(data: any): Promise<any> {
|
|
26
27
|
data.icon = JSON.stringify(data.icon)
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
async prepareItem(item: any): Promise<any> {
|
|
30
|
-
item.icon = JSON.parse(item.icon)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
29
|
}
|
|
34
30
|
|
|
35
31
|
export default LanguageSqliteRepository
|
|
36
32
|
export {LanguageSqliteRepository}
|
|
37
|
-
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {describe, test} from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import {randomUUID} from "node:crypto";
|
|
4
|
+
import {AbstractSqliteRepository} from "../../src/index.js";
|
|
5
|
+
import type {SqliteTableField} from "@drax/common-back";
|
|
6
|
+
|
|
7
|
+
class TestSqliteRepository extends AbstractSqliteRepository<any, any, any> {
|
|
8
|
+
protected tableName: string = "TestEntity";
|
|
9
|
+
protected searchFields: string[] = [];
|
|
10
|
+
protected booleanFields: string[] = ["enabled"];
|
|
11
|
+
protected jsonFields: string[] = ["payload", "tags"];
|
|
12
|
+
protected identifier: string = "_id";
|
|
13
|
+
protected populateFields = [];
|
|
14
|
+
protected tableFields: SqliteTableField[] = [
|
|
15
|
+
{name: "title", type: "TEXT", unique: false, primary: false},
|
|
16
|
+
{name: "payload", type: "TEXT", unique: false, primary: false},
|
|
17
|
+
{name: "tags", type: "TEXT", unique: false, primary: false},
|
|
18
|
+
{name: "enabled", type: "INTEGER", unique: false, primary: false},
|
|
19
|
+
{name: "bornAt", type: "TEXT", unique: false, primary: false},
|
|
20
|
+
{name: "optional", type: "TEXT", unique: false, primary: false},
|
|
21
|
+
{name: "createdAt", type: "TEXT", unique: false, primary: false},
|
|
22
|
+
{name: "updatedAt", type: "TEXT", unique: false, primary: false}
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
findRawById(id: string) {
|
|
26
|
+
return this.db.prepare(`SELECT * FROM ${this.tableName} WHERE ${this.identifier} = ?`).get(id);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("AbstractSqliteRepository", () => {
|
|
31
|
+
test("create should normalize non-bindable sqlite values", async () => {
|
|
32
|
+
const repository = new TestSqliteRepository(`/tmp/${randomUUID()}.db`);
|
|
33
|
+
repository.build();
|
|
34
|
+
|
|
35
|
+
const bornAt = new Date("2024-01-02T03:04:05.000Z");
|
|
36
|
+
|
|
37
|
+
const created = await repository.create({
|
|
38
|
+
title: "example",
|
|
39
|
+
payload: {foo: "bar", count: 2},
|
|
40
|
+
tags: ["a", "b"],
|
|
41
|
+
enabled: true,
|
|
42
|
+
bornAt,
|
|
43
|
+
optional: undefined
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const raw = repository.findRawById(created._id);
|
|
47
|
+
|
|
48
|
+
assert.deepEqual(created.payload, {foo: "bar", count: 2});
|
|
49
|
+
assert.deepEqual(created.tags, ["a", "b"]);
|
|
50
|
+
assert.equal(created.enabled, true);
|
|
51
|
+
assert.equal(created.bornAt, bornAt.toISOString());
|
|
52
|
+
assert.equal(created.optional, null);
|
|
53
|
+
assert.equal(raw.title, "example");
|
|
54
|
+
assert.equal(raw.payload, JSON.stringify({foo: "bar", count: 2}));
|
|
55
|
+
assert.equal(raw.tags, JSON.stringify(["a", "b"]));
|
|
56
|
+
assert.equal(raw.enabled, 1);
|
|
57
|
+
assert.equal(raw.bornAt, bornAt.toISOString());
|
|
58
|
+
assert.equal(raw.optional, null);
|
|
59
|
+
assert.ok(typeof raw.createdAt === "string");
|
|
60
|
+
assert.ok(typeof raw.updatedAt === "string");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("update should normalize non-bindable sqlite values", async () => {
|
|
64
|
+
const repository = new TestSqliteRepository(`/tmp/${randomUUID()}.db`);
|
|
65
|
+
repository.build();
|
|
66
|
+
|
|
67
|
+
const created = await repository.create({
|
|
68
|
+
title: "initial"
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const bornAt = new Date("2025-06-07T08:09:10.000Z");
|
|
72
|
+
|
|
73
|
+
const updated = await repository.update(created._id, {
|
|
74
|
+
payload: {nested: ["x"]},
|
|
75
|
+
tags: ["updated"],
|
|
76
|
+
enabled: false,
|
|
77
|
+
bornAt,
|
|
78
|
+
optional: undefined
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const raw = repository.findRawById(created._id);
|
|
82
|
+
|
|
83
|
+
assert.deepEqual(updated.payload, {nested: ["x"]});
|
|
84
|
+
assert.deepEqual(updated.tags, ["updated"]);
|
|
85
|
+
assert.equal(updated.enabled, false);
|
|
86
|
+
assert.equal(updated.bornAt, bornAt.toISOString());
|
|
87
|
+
assert.equal(updated.optional, null);
|
|
88
|
+
assert.equal(raw.payload, JSON.stringify({nested: ["x"]}));
|
|
89
|
+
assert.equal(raw.tags, JSON.stringify(["updated"]));
|
|
90
|
+
assert.equal(raw.enabled, 0);
|
|
91
|
+
assert.equal(raw.bornAt, bornAt.toISOString());
|
|
92
|
+
assert.equal(raw.optional, null);
|
|
93
|
+
assert.ok(typeof raw.updatedAt === "string");
|
|
94
|
+
});
|
|
95
|
+
});
|