bd-orm 0.0.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/.github/workflows/build-and-test.yml +26 -0
- package/.github/workflows/publish.yml +36 -0
- package/.prettierrc.json +14 -0
- package/CHANGELOG.md +3 -0
- package/README.md +5 -0
- package/check NBR en TODO.txt +32 -0
- package/dist/_/BdORMBase.d.ts +111 -0
- package/dist/_/BdORMBase.js +262 -0
- package/dist/_/BdORMCrud.d.ts +51 -0
- package/dist/_/BdORMCrud.js +223 -0
- package/dist/_/BdORMError.d.ts +4 -0
- package/dist/_/BdORMError.js +14 -0
- package/dist/_/BdOrmConnection.d.ts +32 -0
- package/dist/_/BdOrmConnection.js +5 -0
- package/dist/_/cdsBaseOrm.d.ts +12 -0
- package/dist/_/cdsBaseOrm.js +21 -0
- package/dist/dbConnections/BdOrmDbConnectionCapHana/index.d.ts +26 -0
- package/dist/dbConnections/BdOrmDbConnectionCapHana/index.js +78 -0
- package/dist/dbConnections/BdOrmDbConnectionCapHana/utils.d.ts +14 -0
- package/dist/dbConnections/BdOrmDbConnectionCapHana/utils.js +49 -0
- package/dist/dbConnections/BdOrmDbConnectionCapSqlite/index.d.ts +22 -0
- package/dist/dbConnections/BdOrmDbConnectionCapSqlite/index.js +85 -0
- package/dist/dbConnections/BdOrmDbConnectionCapSqlite/utils.d.ts +3 -0
- package/dist/dbConnections/BdOrmDbConnectionCapSqlite/utils.js +74 -0
- package/dist/dbConnections/BdOrmDbConnectionSQLBase.d.ts +32 -0
- package/dist/dbConnections/BdOrmDbConnectionSQLBase.js +99 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +18 -0
- package/dist/test-assets/Post.d.ts +12 -0
- package/dist/test-assets/Post.js +13 -0
- package/dist/test-assets/User.d.ts +16 -0
- package/dist/test-assets/User.js +13 -0
- package/dist/test-assets/jestUtils.d.ts +5 -0
- package/dist/test-assets/jestUtils.js +30 -0
- package/jest.config.js +7 -0
- package/package.json +53 -0
- package/src/_/BdORMBase.ts +288 -0
- package/src/_/BdORMCrud.test.ts +198 -0
- package/src/_/BdORMCrud.ts +240 -0
- package/src/_/BdORMError.ts +10 -0
- package/src/_/BdORMbase.test.ts +166 -0
- package/src/_/BdOrmConnection.ts +39 -0
- package/src/_/cdsBaseOrm.ts +18 -0
- package/src/dbConnections/BdOrmDbConnectionCapHana/index.ts +95 -0
- package/src/dbConnections/BdOrmDbConnectionCapHana/utils.ts +47 -0
- package/src/dbConnections/BdOrmDbConnectionCapHana.test.ts +18 -0
- package/src/dbConnections/BdOrmDbConnectionCapSqlite/index.ts +89 -0
- package/src/dbConnections/BdOrmDbConnectionCapSqlite/utils.ts +75 -0
- package/src/dbConnections/BdOrmDbConnectionCapSqlite.test.ts +41 -0
- package/src/dbConnections/BdOrmDbConnectionSQLBase.ts +124 -0
- package/src/index.ts +8 -0
- package/src/test-assets/Post.ts +16 -0
- package/src/test-assets/User.ts +18 -0
- package/src/test-assets/db/BdOrm.cds +20 -0
- package/src/test-assets/db/csv/bdorm-user.csv +3 -0
- package/src/test-assets/db/views/user.hdbview +3 -0
- package/src/test-assets/jestUtils.ts +24 -0
- package/tsconfig.json +16 -0
- package/validate-package.js +113 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { BdORMError } from './BdORMError';
|
|
2
|
+
|
|
3
|
+
// Local variables
|
|
4
|
+
const PROPERTIES_WEAKMAP = new WeakMap(), // memory leak prevention
|
|
5
|
+
LOCAL_WEAKMAP = new WeakMap();
|
|
6
|
+
|
|
7
|
+
// Helper methods
|
|
8
|
+
const getLocalWeakMapValue = (instance: BdORMBase, key: string) => {
|
|
9
|
+
const localWeakMap = LOCAL_WEAKMAP.get(instance) ?? {};
|
|
10
|
+
return key in localWeakMap ? localWeakMap[key] : null;
|
|
11
|
+
},
|
|
12
|
+
getPropertyDescriptor = (instance: BdORMBase, property: string) => {
|
|
13
|
+
let descriptor;
|
|
14
|
+
while (instance && !descriptor) {
|
|
15
|
+
descriptor = Object.getOwnPropertyDescriptor(instance, property);
|
|
16
|
+
instance = Object.getPrototypeOf(instance);
|
|
17
|
+
}
|
|
18
|
+
return descriptor;
|
|
19
|
+
},
|
|
20
|
+
definePropertyDescriptors = (instance: BdORMBase, data: Record<string, any>) => {
|
|
21
|
+
Object.keys(data).forEach(property => {
|
|
22
|
+
const propertyDefinion = getPropertyDescriptor(instance, property) ?? {};
|
|
23
|
+
if (!('get' in propertyDefinion) || propertyDefinion.get === undefined) {
|
|
24
|
+
propertyDefinion.get = () => {
|
|
25
|
+
const value = instance.getProperty(property) as string;
|
|
26
|
+
if (typeof value === 'string' && (value.trim().startsWith('{') || value.trim().startsWith('['))) {
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(value);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (!('set' in propertyDefinion) || propertyDefinion.set === undefined) {
|
|
37
|
+
propertyDefinion.set = (value: any) => {
|
|
38
|
+
if (value && typeof value === 'object') {
|
|
39
|
+
try {
|
|
40
|
+
instance.setProperty(property, JSON.stringify(value));
|
|
41
|
+
} catch (e) {
|
|
42
|
+
instance.setProperty(property, value);
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
instance.setProperty(property, value);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if ('value' in propertyDefinion && propertyDefinion.value === undefined) {
|
|
50
|
+
delete propertyDefinion.value;
|
|
51
|
+
if ('writable' in propertyDefinion) delete propertyDefinion.writable;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
Object.defineProperty(instance, property, propertyDefinion);
|
|
55
|
+
} catch (e) {
|
|
56
|
+
throw new BdORMError(
|
|
57
|
+
`Invalid property descriptor "${property}" ${propertyDefinion.value} in ${instance.constructor.name}`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
// data toevoegen
|
|
61
|
+
if (data[property] !== undefined) instance[property] = data[property];
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Class which only contains the getters and setters for the base ORM
|
|
67
|
+
*/
|
|
68
|
+
abstract class BdORMBase {
|
|
69
|
+
/**
|
|
70
|
+
* Properties will be defined in the constructor (see definePropertyDescriptors)
|
|
71
|
+
*/
|
|
72
|
+
[key: string]: any;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @returns the model name
|
|
76
|
+
*/
|
|
77
|
+
public static getModelName(): string {
|
|
78
|
+
return this.name;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
constructor(data: Record<string, any> = {}) {
|
|
82
|
+
const ormData = { ...data };
|
|
83
|
+
// primary key to 0 if not present
|
|
84
|
+
const primaryKey = this.getPrimaryKey();
|
|
85
|
+
if (!(primaryKey in ormData)) {
|
|
86
|
+
ormData[primaryKey] = 0; // 0 means new entry
|
|
87
|
+
}
|
|
88
|
+
// required property check
|
|
89
|
+
if (this.getRequiredProperties().length > 0) {
|
|
90
|
+
this.getRequiredProperties().forEach(property => {
|
|
91
|
+
if (!(property in ormData)) throw new BdORMError(`Property "${property}" is required`);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
// set properties
|
|
95
|
+
definePropertyDescriptors(this, ormData);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* This method is ONLY used in the FETCH method
|
|
100
|
+
* @returns the columns to fetch from the database
|
|
101
|
+
*/
|
|
102
|
+
public static readonly COLUMNS_TO_FETCH: string | string[] = '*';
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* which default methods are not allowed to be used
|
|
106
|
+
* for example: ['delete'] will prevent you from using model.delete();
|
|
107
|
+
*/
|
|
108
|
+
public static readonly METHODS_NOT_ALLOWED: string[] = [];
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get the primary key for the current table
|
|
112
|
+
* @returns the primary key for the current table
|
|
113
|
+
*/
|
|
114
|
+
public static readonly PRIMARY_KEY: string = 'id';
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Specify which properties should be set as read-only.
|
|
118
|
+
* These properties can only be set once, when the object is created.
|
|
119
|
+
* @return array
|
|
120
|
+
*/
|
|
121
|
+
public static readonly PROPERTIES_NOT_ALLOWED_TO_CHANGE: string[] = [];
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* If there are values that should not be duplicated,
|
|
125
|
+
* specify here which properties those should be.
|
|
126
|
+
* @return array
|
|
127
|
+
*/
|
|
128
|
+
public static readonly PROPERTIES_NOT_ALLOWED_TO_DUPLICATE: string[] = [];
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Specify which properties are required when creating a new object.
|
|
132
|
+
* @return array
|
|
133
|
+
*/
|
|
134
|
+
public static readonly REQUIRED_PROPERTIES: string[] = [];
|
|
135
|
+
|
|
136
|
+
public static isMethodAllowed(method: string, { throwErrorIfNotAllowed = false } = {}): boolean {
|
|
137
|
+
const allowed = !this.METHODS_NOT_ALLOWED.includes(method);
|
|
138
|
+
if (!allowed && throwErrorIfNotAllowed) {
|
|
139
|
+
throw new BdORMError(`Method "${method}" not allowed`);
|
|
140
|
+
}
|
|
141
|
+
return allowed;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get the table name as used in the database
|
|
146
|
+
* @returns the table name as used in the database
|
|
147
|
+
*/
|
|
148
|
+
public static readonly DB_TABLE: string;
|
|
149
|
+
public static get TABLE(): string {
|
|
150
|
+
if (!this.DB_TABLE) throw BdORMError.staticNotImplemented('get TABLE()');
|
|
151
|
+
return this.DB_TABLE;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Sometimes you want to use a custom view to read your model data
|
|
156
|
+
* @returns the view name as used in the database
|
|
157
|
+
*/
|
|
158
|
+
public static readonly DB_VIEW: string;
|
|
159
|
+
public static get VIEW(): string {
|
|
160
|
+
return this.DB_VIEW ?? this.TABLE;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
protected _setChangedProperties(changedProperties: string[]): void {
|
|
164
|
+
const local = LOCAL_WEAKMAP.get(this) || {};
|
|
165
|
+
LOCAL_WEAKMAP.set(this, {
|
|
166
|
+
...local,
|
|
167
|
+
changedProperties,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @returns the changed properties
|
|
173
|
+
*/
|
|
174
|
+
public getChangedProperties(): string[] {
|
|
175
|
+
return !this.isNew() ? (getLocalWeakMapValue(this, 'changedProperties') ?? []) : [];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @returns the data in json format
|
|
180
|
+
* @paaam {boolean} [preventFormatting=false] - prevent formatting of the data
|
|
181
|
+
*/
|
|
182
|
+
getData(preventFormatting = false): Record<string, any> {
|
|
183
|
+
const data: Record<string, any> = {},
|
|
184
|
+
returnData: Record<string, any> = {};
|
|
185
|
+
const properties = PROPERTIES_WEAKMAP.get(this) ?? {};
|
|
186
|
+
Object.keys(properties).forEach(property => {
|
|
187
|
+
data[property] = this.getProperty(property, { preventFormatting });
|
|
188
|
+
returnData[property] = preventFormatting ? data[property] : (this[property] ?? data[property]);
|
|
189
|
+
});
|
|
190
|
+
return returnData;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @returns the primary key for the current table
|
|
195
|
+
*/
|
|
196
|
+
public getPrimaryKey(): string {
|
|
197
|
+
return (this.constructor as typeof BdORMBase).PRIMARY_KEY;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public getPrimaryKeyValue(): number {
|
|
201
|
+
return this.getProperty(this.getPrimaryKey()) as number;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* get the model property
|
|
206
|
+
*/
|
|
207
|
+
public getProperty(key: string, { preventFormatting = false } = {}): string | number | null | undefined {
|
|
208
|
+
const properties = PROPERTIES_WEAKMAP.get(this) ?? {};
|
|
209
|
+
let value = key in properties ? properties[key] : null; // never properties[key] as it can be set to null, undefined or 0
|
|
210
|
+
if (!preventFormatting && value instanceof Buffer) value = value.toString();
|
|
211
|
+
return value;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* @returns the columns of the required properties needed to create a new object
|
|
216
|
+
*/
|
|
217
|
+
public getRequiredProperties(): string[] {
|
|
218
|
+
return (this.constructor as typeof BdORMBase).REQUIRED_PROPERTIES;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Get the table name as used in the database
|
|
223
|
+
* @returns the table name as used in the database
|
|
224
|
+
*/
|
|
225
|
+
public getTable(): string {
|
|
226
|
+
return (this.constructor as typeof BdORMBase).TABLE;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
*
|
|
231
|
+
* @returns
|
|
232
|
+
*/
|
|
233
|
+
public hasChanges(): boolean {
|
|
234
|
+
return this.getChangedProperties().length > 0;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Check if the property has been changed
|
|
239
|
+
*/
|
|
240
|
+
public hasPropertyValueChanged(property: string): boolean {
|
|
241
|
+
return this.getChangedProperties().includes(property);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Check if the current object is a new object
|
|
246
|
+
* @returns true if the object is new, false if it is not
|
|
247
|
+
*/
|
|
248
|
+
public isNew(): boolean {
|
|
249
|
+
return !this.getPrimaryKeyValue();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public setProperty(property: string, value: any, { forceChange = false } = {}): void {
|
|
253
|
+
// prevent overwrite of primary key
|
|
254
|
+
if (property === this.getPrimaryKey() && this.getPrimaryKeyValue() && this.getPrimaryKeyValue() !== value) {
|
|
255
|
+
throw new BdORMError(`Primary key cannot be changed from ${this.getPrimaryKeyValue()} to ${value}`);
|
|
256
|
+
}
|
|
257
|
+
// prevent overwrite of read-only properties
|
|
258
|
+
if (
|
|
259
|
+
!forceChange &&
|
|
260
|
+
!this.isNew() &&
|
|
261
|
+
(this.constructor as typeof BdORMBase).PROPERTIES_NOT_ALLOWED_TO_CHANGE.includes(property) &&
|
|
262
|
+
![undefined, null].includes(this.getProperty(property) as null) &&
|
|
263
|
+
this.getProperty(property) != value // != is used to check for null and undefined
|
|
264
|
+
) {
|
|
265
|
+
throw new BdORMError(`Property "${property}" is not allowed to be changed`);
|
|
266
|
+
}
|
|
267
|
+
if (!this.isNew() && this.getPrimaryKey() === property && this.getPrimaryKeyValue() !== value) {
|
|
268
|
+
throw new BdORMError(`Primary key "${property}" is not allowed to be changed`);
|
|
269
|
+
}
|
|
270
|
+
// set changed flag
|
|
271
|
+
const origValue = this.getProperty(property);
|
|
272
|
+
if (![undefined, null].includes(this.getProperty(property) as null) && origValue !== value) {
|
|
273
|
+
// todo set orig
|
|
274
|
+
const changedProperties = this.getChangedProperties();
|
|
275
|
+
if (!changedProperties.includes(property)) {
|
|
276
|
+
changedProperties.push(property);
|
|
277
|
+
this._setChangedProperties(changedProperties);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// waarde instellen
|
|
281
|
+
const properties = PROPERTIES_WEAKMAP.get(this) ?? {};
|
|
282
|
+
properties[property] = value;
|
|
283
|
+
PROPERTIES_WEAKMAP.set(this, properties);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export default BdORMBase;
|
|
288
|
+
export { definePropertyDescriptors };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import BdOrmDbConnectionCapSqlite from '../dbConnections/BdOrmDbConnectionCapSqlite';
|
|
2
|
+
import BdOrm from '../index';
|
|
3
|
+
import User from '../test-assets/User';
|
|
4
|
+
import { expectErrorMessage } from '../test-assets/jestUtils';
|
|
5
|
+
import cds from '@sap/cds';
|
|
6
|
+
|
|
7
|
+
describe('bd-orm BdORMCrud', () => {
|
|
8
|
+
let dbConnection: BdOrmDbConnectionCapSqlite;
|
|
9
|
+
//beforeEach(() => {
|
|
10
|
+
BdOrm.clearDbConnection();
|
|
11
|
+
dbConnection = new BdOrmDbConnectionCapSqlite(__dirname + '/../test-assets/db');
|
|
12
|
+
BdOrm.setDbConnection(dbConnection);
|
|
13
|
+
//});
|
|
14
|
+
|
|
15
|
+
it('Prevent setting the db connection twice', () => {
|
|
16
|
+
expectErrorMessage(async () => BdOrm.setDbConnection(dbConnection), 'DbConnection already set');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("Count the number of users in the database, it's 2", async () => {
|
|
20
|
+
const count = await User.count();
|
|
21
|
+
expect(count).toBe(2);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('Create a user ', async () => {
|
|
25
|
+
const user = new User({ firstname: 'Test', lastname: 'Persoon' });
|
|
26
|
+
await user.save();
|
|
27
|
+
expect(user.id).toBe(3);
|
|
28
|
+
const results = await dbConnection.query('SELECT * FROM bdorm_user WHERE id = 3');
|
|
29
|
+
expect(results[0].firstname).toBe('Test');
|
|
30
|
+
expect(results[0].lastname).toBe('Persoon');
|
|
31
|
+
// alternate creation method
|
|
32
|
+
const user2 = await User.create({ firstname: 'Test2', lastname: 'Persoon2' });
|
|
33
|
+
expect(user2.id).toBe(4);
|
|
34
|
+
const results2 = await dbConnection.query('SELECT * FROM bdorm_user WHERE id = 4');
|
|
35
|
+
expect(results2[0].firstname).toBe('Test2');
|
|
36
|
+
expect(results2[0].lastname).toBe('Persoon2');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('Create a user with properties that are not in the table', async () => {
|
|
40
|
+
const user = new User({ firstname: 'Invalid', lastname: 'Property', invalidprop: 'sadf' });
|
|
41
|
+
await user.save();
|
|
42
|
+
const results = await dbConnection.query('SELECT * FROM bdorm_user WHERE id = ?', [user.id]);
|
|
43
|
+
expect(results[0].firstname).toBe('Invalid');
|
|
44
|
+
expect(results[0].lastname).toBe('Property');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('Delete a user', async () => {
|
|
48
|
+
// first add a user
|
|
49
|
+
const user = await User.create({ firstname: 'Delete', lastname: 'Me' });
|
|
50
|
+
const id = user.id;
|
|
51
|
+
const results = await dbConnection.query('SELECT * FROM bdorm_user WHERE id = ?', [id]);
|
|
52
|
+
expect(results).toHaveLength(1);
|
|
53
|
+
// then delete the user
|
|
54
|
+
await user.delete();
|
|
55
|
+
const resultsAfterDelete = await dbConnection.query('SELECT * FROM bdorm_user WHERE id = ?', [id]);
|
|
56
|
+
expect(resultsAfterDelete).toHaveLength(0);
|
|
57
|
+
const resultsAfterDelete2 = await dbConnection.query('SELECT * FROM bdorm_user WHERE firstname = ?', [
|
|
58
|
+
'Delete',
|
|
59
|
+
]);
|
|
60
|
+
expect(resultsAfterDelete2).toHaveLength(0);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('Fetch a user by id', async () => {
|
|
64
|
+
const user = await User.fetchByPrimaryKey(1);
|
|
65
|
+
expect(user).toBeInstanceOf(User);
|
|
66
|
+
expect(user?.firstname).toBe('John');
|
|
67
|
+
expect(user?.lastname).toBe('Doe');
|
|
68
|
+
|
|
69
|
+
const user2 = await User.fetchById(2);
|
|
70
|
+
expect(user2).toBeInstanceOf(User);
|
|
71
|
+
expect(user2?.firstname).toBe('Barry');
|
|
72
|
+
expect(user2?.lastname).toBe('Dam');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('Fetch multiple users', async () => {
|
|
76
|
+
const users = await User.fetch();
|
|
77
|
+
expect(users[0]).toBeInstanceOf(User);
|
|
78
|
+
expect(users[1]).toBeInstanceOf(User);
|
|
79
|
+
expect(users[0].firstname).toBe('John');
|
|
80
|
+
expect(users[1].firstname).toBe('Barry');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('Fetch with a where clause as object', async () => {
|
|
84
|
+
const users = await User.fetch({ firstname: 'John' });
|
|
85
|
+
expect(users).toHaveLength(1);
|
|
86
|
+
expect(users[0].firstname).toBe('John');
|
|
87
|
+
expect(users[0].lastname).toBe('Doe');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('Fetch with a where clause as string', async () => {
|
|
91
|
+
const users = await User.fetch('firstname = ?', ['Barry']);
|
|
92
|
+
expect(users).toHaveLength(1);
|
|
93
|
+
expect(users[0].firstname).toBe('Barry');
|
|
94
|
+
expect(users[0].lastname).toBe('Dam');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("Fetch where clause that doesn't match", async () => {
|
|
98
|
+
const user = await User.fetch({ firstname: 'Barry', lastname: 'Doe' });
|
|
99
|
+
expect(user.length).toBe(0);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('Fetch One', async () => {
|
|
103
|
+
const user = await User.fetchOne({ firstname: 'Barry' });
|
|
104
|
+
expect(user).toBeInstanceOf(User);
|
|
105
|
+
expect(user?.firstname).toBe('Barry');
|
|
106
|
+
expect(user?.lastname).toBe('Dam');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('Update a user', async () => {
|
|
110
|
+
const user = await User.fetchById(1);
|
|
111
|
+
expect(user).toBeInstanceOf(User);
|
|
112
|
+
if (!user) throw new Error('User not found');
|
|
113
|
+
const firstname = user.firstname;
|
|
114
|
+
user.firstname = 'Jane';
|
|
115
|
+
await user.save();
|
|
116
|
+
const results = await dbConnection.query('SELECT * FROM bdorm_user WHERE id = 1');
|
|
117
|
+
expect(results[0].firstname).toBe('Jane');
|
|
118
|
+
user.firstname = firstname;
|
|
119
|
+
await user.save();
|
|
120
|
+
const results2 = await dbConnection.query('SELECT * FROM bdorm_user WHERE id = 1');
|
|
121
|
+
expect(results2[0].firstname).toBe('John');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('Should save JSON options as a string in the db', async () => {
|
|
125
|
+
const user = new User({ firstname: 'Json', lastname: 'Persoon', options: { test: 'test 123' } });
|
|
126
|
+
await user.save();
|
|
127
|
+
const results = await dbConnection.query('SELECT * FROM bdorm_user WHERE firstname = ?', ['Json']);
|
|
128
|
+
expect(results[0].options).toBe('{"test":"test 123"}');
|
|
129
|
+
const userJSON = await User.fetchOne({ firstname: 'Json' });
|
|
130
|
+
expect(userJSON?.options).toEqual({ test: 'test 123' });
|
|
131
|
+
expect(userJSON?.options?.test).toEqual('test 123');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('Should not allow me to run delete and save', async () => {
|
|
135
|
+
class userNotAllowedDeleteAndSave extends User {
|
|
136
|
+
static readonly METHODS_NOT_ALLOWED = ['save', 'delete'];
|
|
137
|
+
}
|
|
138
|
+
const user = new userNotAllowedDeleteAndSave({ firstname: 'Json', lastname: 'Persoon' });
|
|
139
|
+
expectErrorMessage(async () => {
|
|
140
|
+
await user.save();
|
|
141
|
+
}, 'Method "save" not allowed');
|
|
142
|
+
expectErrorMessage(async () => {
|
|
143
|
+
await user.delete();
|
|
144
|
+
}, 'Method "delete" not allowed');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('Columns to fetch is altered and works correctly', async () => {
|
|
148
|
+
class UserWithColumnsToFetch extends User {
|
|
149
|
+
static readonly COLUMNS_TO_FETCH = ['id', 'firstname'];
|
|
150
|
+
}
|
|
151
|
+
const users = await UserWithColumnsToFetch.fetch();
|
|
152
|
+
expect(users[0]).toBeInstanceOf(UserWithColumnsToFetch);
|
|
153
|
+
expect(users[0].firstname).toBe('John');
|
|
154
|
+
expect(users[0].lastname).toBeUndefined();
|
|
155
|
+
class UserWithColumnsToFetch2 extends User {
|
|
156
|
+
static readonly COLUMNS_TO_FETCH = 'id, firstname, lastname as achternaam';
|
|
157
|
+
}
|
|
158
|
+
const user = await UserWithColumnsToFetch2.fetchOne('firstname = ? and lastname = ?', ['John', 'Doe']);
|
|
159
|
+
expect(user).toBeInstanceOf(UserWithColumnsToFetch2);
|
|
160
|
+
expect(user?.firstname).toBe('John');
|
|
161
|
+
expect(user?.lastname).toBeUndefined();
|
|
162
|
+
expect(user?.achternaam).toBe('Doe');
|
|
163
|
+
expect(user?.fullname).toBeUndefined();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('Duplicate tests', () => {
|
|
167
|
+
it('Should duplicate the user as draft and remove dateCreated', async () => {
|
|
168
|
+
const user = await User.fetchById(1); // John Doe
|
|
169
|
+
const user2 = await user?.duplicate({ asDraft: true });
|
|
170
|
+
expect(user2).toBeInstanceOf(User);
|
|
171
|
+
expect(user2?.firstname).toBe('John');
|
|
172
|
+
expect(user2?.lastname).toBe('Doe');
|
|
173
|
+
expect(user2?.isNew()).toBe(true);
|
|
174
|
+
expect(user2?.dateCreated).toBeUndefined();
|
|
175
|
+
});
|
|
176
|
+
it('Should duplicate the user as draft and set the firstname to Johnny', async () => {
|
|
177
|
+
const user = await User.fetchById(1); // John Doe
|
|
178
|
+
const user2 = await user?.duplicate({ asDraft: true, newData: { firstname: 'Johnny' } });
|
|
179
|
+
expect(user2).toBeInstanceOf(User);
|
|
180
|
+
expect(user2?.firstname).toBe('Johnny');
|
|
181
|
+
expect(user2?.lastname).toBe('Doe');
|
|
182
|
+
expect(user2?.isNew()).toBe(true);
|
|
183
|
+
});
|
|
184
|
+
it('Should duplicate the user and save it to the DB', async () => {
|
|
185
|
+
const user = await User.fetchById(1); // John Doe
|
|
186
|
+
const user2 = await user?.duplicate();
|
|
187
|
+
expect(user2).toBeInstanceOf(User);
|
|
188
|
+
expect(user2?.firstname).toBe('John');
|
|
189
|
+
expect(user2?.lastname).toBe('Doe');
|
|
190
|
+
expect(user2?.isNew()).toBe(false);
|
|
191
|
+
expect(user2?.dateCreated).not.toBeUndefined();
|
|
192
|
+
const results = await dbConnection.query('SELECT * FROM bdorm_user WHERE id = ?', [user2?.id]);
|
|
193
|
+
expect(results[0].firstname).toBe('John');
|
|
194
|
+
expect(results[0].lastname).toBe('Doe');
|
|
195
|
+
expect(results[0].id).toBe(user2?.id);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|