masquerade-orm 0.1.0
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/LICENSE +21 -0
- package/README.md +149 -0
- package/bin/universalTsInit.js +59 -0
- package/docs/deletion.md +186 -0
- package/docs/find.md +265 -0
- package/docs/getting-started-javascript.md +112 -0
- package/docs/getting-started-typescript.md +159 -0
- package/docs/in-depth-class-definitions.md +193 -0
- package/docs/jsdoc-ux-tips.md +17 -0
- package/docs/managing-the-database.md +37 -0
- package/docs/saving-to-database.md +37 -0
- package/index.d.ts +7 -0
- package/index.js +11 -0
- package/jsconfig.json +29 -0
- package/package.json +40 -0
- package/src/ORM/DbManager.js +76 -0
- package/src/ORM/ORM.js +181 -0
- package/src/ORM/bootOrm.js +929 -0
- package/src/changeLogger/changeLogger.js +55 -0
- package/src/changeLogger/save.js +237 -0
- package/src/changeLogger/sqlClients/postgres.js +97 -0
- package/src/changeLogger/sqlClients/sqlite.js +120 -0
- package/src/entity/delete/delete.js +20 -0
- package/src/entity/delete/getDependents.js +46 -0
- package/src/entity/entity.d.ts +46 -0
- package/src/entity/entity.js +228 -0
- package/src/entity/find/find.js +157 -0
- package/src/entity/find/joins.js +52 -0
- package/src/entity/find/queryBuilder.js +95 -0
- package/src/entity/find/relations.js +23 -0
- package/src/entity/find/scopeProxies.js +60 -0
- package/src/entity/find/sqlClients/postgresFuncs.js +171 -0
- package/src/entity/find/sqlClients/sqliteFuncs.js +211 -0
- package/src/entity/find/where/relationalWhere.js +142 -0
- package/src/entity/find/where/where.js +244 -0
- package/src/entity/find/where/whereArgsFunctions.js +49 -0
- package/src/misc/classes.js +63 -0
- package/src/misc/constants.js +42 -0
- package/src/misc/miscFunctions.js +167 -0
- package/src/misc/ormStore.js +18 -0
- package/src/misc/types.d.ts +560 -0
- package/src/proxies/instanceProxy.js +544 -0
- package/src/proxies/nonRelationalArrayProxy.js +76 -0
- package/src/proxies/objectProxy.js +50 -0
- package/src/proxies/relationalArrayProxy.js +130 -0
- package/src/webpack/masquerade-loader.js +14 -0
- package/src/webpack/plugin.js +43 -0
- package/src/webpack/store.js +2 -0
- package/src/webpack/webpack.config.js +41 -0
- package/testing/dev-doc.md +7 -0
- package/testing/generationFuncs.js +21 -0
- package/testing/miscFunctions.js +97 -0
- package/testing/postgres.test.js +254 -0
- package/testing/sqlite.test.js +257 -0
- package/testing/testing-classes.js +102 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
|
|
2
|
+
import test from 'node:test'
|
|
3
|
+
import assert from "node:assert"
|
|
4
|
+
import * as classes from './testing-classes.js'
|
|
5
|
+
import { initORM, createConfigObj } from "./testInit.js"
|
|
6
|
+
import { sql } from '..//src/entity/find/where/whereArgsFunctions.js'
|
|
7
|
+
import { generateFamiliesAndHouses } from "./generationFuncs.js"
|
|
8
|
+
import { validateUpdatedAt } from "./miscFunctions.js"
|
|
9
|
+
import { OrmStore } from '../src/misc/ormStore.js'
|
|
10
|
+
import fs from "fs/promises"
|
|
11
|
+
|
|
12
|
+
const { House, Person, NonRelationalClass2 } = classes
|
|
13
|
+
|
|
14
|
+
const configObj = createConfigObj(`sqlite`)
|
|
15
|
+
await initORM(configObj, classes)
|
|
16
|
+
let dbChanges = OrmStore.store.dbChangesObj
|
|
17
|
+
generateFamiliesAndHouses()
|
|
18
|
+
for (let i = 0; i < 3; i++) new NonRelationalClass2()
|
|
19
|
+
|
|
20
|
+
const nonRelationalTest = await NonRelationalClass2.find({ where: { json: sql`json_extract(#, '$.someInt') = 5` } })
|
|
21
|
+
test('test 1 - find basics and change logging', async (t) => {
|
|
22
|
+
|
|
23
|
+
await t.test('find basics', async (t) => {
|
|
24
|
+
|
|
25
|
+
await t.test('find result length is correct', async () => {
|
|
26
|
+
assert.strictEqual(nonRelationalTest.length, 3)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
await t.test('find returns correct typing', async () => {
|
|
30
|
+
assert.strictEqual(typeof nonRelationalTest[0].bigint, 'bigint')
|
|
31
|
+
assert.strictEqual(typeof nonRelationalTest[0].boolean, 'boolean')
|
|
32
|
+
assert.strictEqual(typeof nonRelationalTest[0].stringArr[0], 'string')
|
|
33
|
+
assert.strictEqual(typeof nonRelationalTest[0].id, 'number')
|
|
34
|
+
assert.strictEqual(typeof nonRelationalTest[0].json, 'object')
|
|
35
|
+
assert.strictEqual(typeof nonRelationalTest[0].jsonArr[0], 'object')
|
|
36
|
+
assert.ok(Array.isArray(nonRelationalTest[0].stringArr))
|
|
37
|
+
assert.ok(Array.isArray(nonRelationalTest[0].jsonArr))
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
await t.test('assignments and dbChanges', async (t) => {
|
|
42
|
+
const typeTestId = nonRelationalTest[0].id.toString()
|
|
43
|
+
nonRelationalTest[0].int = 157
|
|
44
|
+
|
|
45
|
+
const testInstanceChangeLog = dbChanges.NonRelationalClass2[typeTestId]
|
|
46
|
+
|
|
47
|
+
/** @type {any} */
|
|
48
|
+
let expectedVal = {
|
|
49
|
+
booleanField: false,
|
|
50
|
+
floatVal: 12.33,
|
|
51
|
+
someInt: 7,
|
|
52
|
+
stringArr: ['masquerade', 'orm', 'best', 'orm'],
|
|
53
|
+
unstructuredData: 'random data'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let currentTime
|
|
57
|
+
|
|
58
|
+
await t.test('non-relational non-arrays', async () => {
|
|
59
|
+
currentTime = new Date()
|
|
60
|
+
nonRelationalTest[0].boolean = false
|
|
61
|
+
|
|
62
|
+
assert.strictEqual(testInstanceChangeLog.boolean, false)
|
|
63
|
+
assert.strictEqual(validateUpdatedAt(testInstanceChangeLog.updatedAt, currentTime), true)
|
|
64
|
+
|
|
65
|
+
currentTime = new Date()
|
|
66
|
+
nonRelationalTest[0].json = {
|
|
67
|
+
booleanField: false,
|
|
68
|
+
floatVal: 12.33,
|
|
69
|
+
someInt: 7,
|
|
70
|
+
stringArr: ['masquerade', 'orm']
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
nonRelationalTest[0].json.unstructuredData = 'random data'
|
|
74
|
+
nonRelationalTest[0].json.stringArr.push('best', 'orm')
|
|
75
|
+
|
|
76
|
+
assert.deepStrictEqual(testInstanceChangeLog.json, expectedVal)
|
|
77
|
+
assert.strictEqual(validateUpdatedAt(testInstanceChangeLog.updatedAt, currentTime), true)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
await t.test('non-relational arrays', async () => {
|
|
81
|
+
currentTime = new Date()
|
|
82
|
+
nonRelationalTest[0].stringArr = ['good', 'day']
|
|
83
|
+
nonRelationalTest[0].stringArr.push('sir')
|
|
84
|
+
|
|
85
|
+
assert.deepStrictEqual(testInstanceChangeLog.stringArr, ['good', 'day', 'sir'])
|
|
86
|
+
assert.strictEqual(validateUpdatedAt(testInstanceChangeLog.updatedAt, currentTime), true)
|
|
87
|
+
|
|
88
|
+
currentTime = new Date()
|
|
89
|
+
nonRelationalTest[0].jsonArr.push({
|
|
90
|
+
someInt: 7,
|
|
91
|
+
booleanField: false,
|
|
92
|
+
floatVal: 7.7,
|
|
93
|
+
stringArr: ['hola', 'mundo']
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
expectedVal =
|
|
97
|
+
'[{"booleanField":true,"floatVal":15.7,"someInt":5,"stringArr":["a","b","c"]},{"someInt":7,"booleanField":false,"floatVal":7.7,"stringArr":["hola","mundo"]}]'
|
|
98
|
+
|
|
99
|
+
assert.deepStrictEqual(testInstanceChangeLog.jsonArr, expectedVal)
|
|
100
|
+
assert.strictEqual(validateUpdatedAt(testInstanceChangeLog.updatedAt, currentTime), true)
|
|
101
|
+
|
|
102
|
+
currentTime = new Date()
|
|
103
|
+
nonRelationalTest[0].jsonArr[0].stringArr = ['someString']
|
|
104
|
+
|
|
105
|
+
expectedVal =
|
|
106
|
+
'[{"booleanField":true,"floatVal":15.7,"someInt":5,"stringArr":["someString"]},{"someInt":7,"booleanField":false,"floatVal":7.7,"stringArr":["hola","mundo"]}]'
|
|
107
|
+
|
|
108
|
+
assert.deepStrictEqual(testInstanceChangeLog.jsonArr, expectedVal)
|
|
109
|
+
assert.strictEqual(validateUpdatedAt(testInstanceChangeLog.updatedAt, currentTime), true)
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
let undefinedTest = await House.find({ relations: { owner: true, tenants: true } })
|
|
114
|
+
|
|
115
|
+
const lastHouse = undefinedTest[undefinedTest.length - 1]
|
|
116
|
+
lastHouse.owner = undefined
|
|
117
|
+
lastHouse.tenants = undefined
|
|
118
|
+
|
|
119
|
+
undefinedTest = await House.find({
|
|
120
|
+
where: { id: lastHouse.id },
|
|
121
|
+
relations: { owner: true, tenants: true }
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
await t.test('assigning undefined values to relational props', async () => {
|
|
125
|
+
assert.strictEqual(undefinedTest[0].owner, undefined)
|
|
126
|
+
assert.deepStrictEqual(undefinedTest[0].tenants, [])
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
await t.test('presave new instances', async (t) => {
|
|
130
|
+
await t.test('new instance proxies communicate with dbChanges correctly', async () => {
|
|
131
|
+
const preSaveChanges = new NonRelationalClass2()
|
|
132
|
+
preSaveChanges.stringArr.push('please rewrite this in rust')
|
|
133
|
+
preSaveChanges.bigint = 12n
|
|
134
|
+
|
|
135
|
+
const preSaveChangesObj =
|
|
136
|
+
dbChanges.NonRelationalClass2[preSaveChanges.id.toString()]
|
|
137
|
+
|
|
138
|
+
assert.deepStrictEqual(
|
|
139
|
+
preSaveChangesObj.stringArr,
|
|
140
|
+
['hello', 'world', 'please rewrite this in rust']
|
|
141
|
+
)
|
|
142
|
+
assert.deepStrictEqual(preSaveChangesObj.bigint, 12n)
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
test('test 2 - promises and instance logging', async (t) => {
|
|
149
|
+
|
|
150
|
+
await t.test('overwriting promises without loading', async (t) => {
|
|
151
|
+
let firstRelationalTest = (await House.find({ where: { id: 1 } }))[0]
|
|
152
|
+
const mrClean = (firstRelationalTest.owner = new Person('Mr Clean', 30))
|
|
153
|
+
firstRelationalTest.tenants = [mrClean, new Person('Mrs Clean', 24)]
|
|
154
|
+
|
|
155
|
+
firstRelationalTest = (await House.find({ where: { id: 1 } }))[0]
|
|
156
|
+
await initORM(configObj, classes)
|
|
157
|
+
|
|
158
|
+
firstRelationalTest = (
|
|
159
|
+
await House.find({
|
|
160
|
+
where: { id: 1 },
|
|
161
|
+
relations: { owner: true, tenants: true }
|
|
162
|
+
})
|
|
163
|
+
)[0]
|
|
164
|
+
|
|
165
|
+
await t.test('1-to-1 relational promise assignment', async () => {
|
|
166
|
+
assert.strictEqual(firstRelationalTest?.owner?.fullName, 'Mr Clean')
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
await t.test('1-to-many relational promise assignment', async () => {
|
|
170
|
+
assert.strictEqual(firstRelationalTest?.tenants?.length, 2)
|
|
171
|
+
assert.strictEqual(firstRelationalTest.tenants[0].fullName, 'Mr Clean')
|
|
172
|
+
assert.strictEqual(firstRelationalTest.tenants[1].fullName, 'Mrs Clean')
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
await t.test('check instance logging', async (t) => {
|
|
177
|
+
const original = (
|
|
178
|
+
await House.find({
|
|
179
|
+
where: { id: 2 },
|
|
180
|
+
relations: { owner: true, tenants: true }
|
|
181
|
+
})
|
|
182
|
+
)[0]
|
|
183
|
+
|
|
184
|
+
const sameInstance = (await House.find({ where: { id: 2 } }))[0]
|
|
185
|
+
|
|
186
|
+
await t.test('instance logging is working correctly', async () => {
|
|
187
|
+
assert.strictEqual(original === sameInstance, true)
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
test('test 3 - deletion', async (t) => {
|
|
193
|
+
let house = (await House.find({
|
|
194
|
+
relations:
|
|
195
|
+
{
|
|
196
|
+
owner:
|
|
197
|
+
{ children: true },
|
|
198
|
+
tenants:
|
|
199
|
+
{
|
|
200
|
+
father: true,
|
|
201
|
+
mother: true
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
where: { id: 5 }
|
|
205
|
+
}))[0]
|
|
206
|
+
|
|
207
|
+
const father = house.owner
|
|
208
|
+
const childrenCount = father?.children.length
|
|
209
|
+
const tenantCount = house.tenants?.length
|
|
210
|
+
// for some reason during tests 1-1 event listeners are empty but relational array event listeners are fine
|
|
211
|
+
//house.tenants?.forEach(tenant => console.log(tenant.eListener_))
|
|
212
|
+
//console.log(father?.children.eListener_)
|
|
213
|
+
//@ts-ignore
|
|
214
|
+
let children = [...father?.children]
|
|
215
|
+
const firstChild = children.shift()
|
|
216
|
+
|
|
217
|
+
await t.test('deletion events - relational arrays', async () => {
|
|
218
|
+
await firstChild.delete()
|
|
219
|
+
//@ts-ignore
|
|
220
|
+
assert.strictEqual(childrenCount - father?.children.length === 1, true)
|
|
221
|
+
assert.strictEqual(father?.children.includes(firstChild), false)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
await t.test('deletion events - 1-to-1 relation', async () => {
|
|
225
|
+
await father?.delete()
|
|
226
|
+
await House.find({})
|
|
227
|
+
await initORM(configObj, classes)
|
|
228
|
+
|
|
229
|
+
house = (await House.find({
|
|
230
|
+
relations:
|
|
231
|
+
{
|
|
232
|
+
owner:
|
|
233
|
+
{ children: true },
|
|
234
|
+
tenants:
|
|
235
|
+
{
|
|
236
|
+
father: true,
|
|
237
|
+
mother: true,
|
|
238
|
+
children: true
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
where: { id: 5 }
|
|
242
|
+
}))[0]
|
|
243
|
+
|
|
244
|
+
const childrenIds = children.map(child => child.id)
|
|
245
|
+
house.tenants && tenantCount && assert.strictEqual(tenantCount - house.tenants?.length, 2)
|
|
246
|
+
assert.strictEqual(childrenIds.includes(firstChild.id), false)
|
|
247
|
+
for (const person of house.tenants ?? []) assert.strictEqual(person.father, undefined)
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
test.after(async () => {
|
|
252
|
+
// @ts-ignore
|
|
253
|
+
configObj.dbConnection.close()
|
|
254
|
+
await fs.rm("./test", { force: true })
|
|
255
|
+
console.log('db reset')
|
|
256
|
+
})
|
|
257
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Entity } from 'masquerade'
|
|
2
|
+
import { jsonGenerator } from './miscFunctions.js'
|
|
3
|
+
/**@typedef {import('masquerade').integer} integer */
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class House extends Entity {
|
|
7
|
+
/**@type {Person | undefined}*/ owner
|
|
8
|
+
/**@type {Person[] | undefined}*/ tenants
|
|
9
|
+
constructor(/**@type {Person}*/ owner, /**@type {Person[]}*/ tenants) {
|
|
10
|
+
super()
|
|
11
|
+
this.owner = owner
|
|
12
|
+
this.tenants = tenants
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class Person extends Entity {
|
|
17
|
+
/**@type {string}*/ fullName
|
|
18
|
+
/**@type {integer}*/ age
|
|
19
|
+
/**@type {Person | undefined}*/ mother
|
|
20
|
+
/**@type {Person | undefined}*/ father
|
|
21
|
+
/**@type {Person[]}*/ children = []
|
|
22
|
+
|
|
23
|
+
// /**@type {Person[]}*/ siblings = []
|
|
24
|
+
// /**@type {integer}*/ numOfSiblings = this.siblings.length
|
|
25
|
+
constructor(/**@type {string}*/ fullName, /**@type {integer}*/ age, /**@type {Person | undefined}*/ father = undefined, /**@type {Person | undefined}*/ mother = undefined) {
|
|
26
|
+
super()
|
|
27
|
+
this.fullName = fullName
|
|
28
|
+
this.age = age
|
|
29
|
+
this.father = father
|
|
30
|
+
this.mother = mother
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @typedef {Object} JSON
|
|
37
|
+
* @property {boolean} booleanField
|
|
38
|
+
* @property {string[]} stringArr
|
|
39
|
+
* @property {number} floatVal
|
|
40
|
+
* @property {integer} someInt
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
export class NonRelationalClass extends Entity {
|
|
44
|
+
/**@type {bigint}*/ bigint = 57n
|
|
45
|
+
/**@type {integer}*/ int = 57
|
|
46
|
+
/**@type {number}*/ float = 57.7
|
|
47
|
+
/**@satisfies {JSON[]}*/ jsonArr = [jsonGenerator()]
|
|
48
|
+
/**@satisfies {JSON}*/ json = jsonGenerator()
|
|
49
|
+
|
|
50
|
+
constructor() {
|
|
51
|
+
super()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class NonRelationalClass2 extends NonRelationalClass {
|
|
56
|
+
/**@type {boolean}*/ boolean = true
|
|
57
|
+
/**@type {string[]}*/ stringArr = ['hello', 'world']
|
|
58
|
+
|
|
59
|
+
// /**@type {Person | undefined}*/ typesChildRelation
|
|
60
|
+
constructor() {
|
|
61
|
+
super()
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
export class TestUser extends Entity {
|
|
67
|
+
/**@type {string}*/ username
|
|
68
|
+
/**@type {string}*/ email
|
|
69
|
+
/**@type {string}*/ password
|
|
70
|
+
/**@type {TestChat[]}*/ chats = []
|
|
71
|
+
|
|
72
|
+
constructor(username, email, password) {
|
|
73
|
+
super()
|
|
74
|
+
this.username = username
|
|
75
|
+
this.email = email
|
|
76
|
+
this.password = password
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export class TestChat extends Entity {
|
|
82
|
+
/**@type {string}*/ chatName
|
|
83
|
+
/**@type {TestUser[]}*/ users
|
|
84
|
+
/**@type {TestMessage[]}*/ messages = []
|
|
85
|
+
constructor(chatName, /**@type {TestUser}*/ user) {
|
|
86
|
+
super()
|
|
87
|
+
this.chatName = chatName
|
|
88
|
+
this.users = [user]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export class TestMessage extends Entity {
|
|
93
|
+
/**@type {string}*/ text
|
|
94
|
+
/**@type {TestUser}*/ sender
|
|
95
|
+
|
|
96
|
+
constructor(text, /**@type {TestUser}*/ user) {
|
|
97
|
+
super()
|
|
98
|
+
this.text = text
|
|
99
|
+
this.sender = user
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|