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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -0
  3. package/bin/universalTsInit.js +59 -0
  4. package/docs/deletion.md +186 -0
  5. package/docs/find.md +265 -0
  6. package/docs/getting-started-javascript.md +112 -0
  7. package/docs/getting-started-typescript.md +159 -0
  8. package/docs/in-depth-class-definitions.md +193 -0
  9. package/docs/jsdoc-ux-tips.md +17 -0
  10. package/docs/managing-the-database.md +37 -0
  11. package/docs/saving-to-database.md +37 -0
  12. package/index.d.ts +7 -0
  13. package/index.js +11 -0
  14. package/jsconfig.json +29 -0
  15. package/package.json +40 -0
  16. package/src/ORM/DbManager.js +76 -0
  17. package/src/ORM/ORM.js +181 -0
  18. package/src/ORM/bootOrm.js +929 -0
  19. package/src/changeLogger/changeLogger.js +55 -0
  20. package/src/changeLogger/save.js +237 -0
  21. package/src/changeLogger/sqlClients/postgres.js +97 -0
  22. package/src/changeLogger/sqlClients/sqlite.js +120 -0
  23. package/src/entity/delete/delete.js +20 -0
  24. package/src/entity/delete/getDependents.js +46 -0
  25. package/src/entity/entity.d.ts +46 -0
  26. package/src/entity/entity.js +228 -0
  27. package/src/entity/find/find.js +157 -0
  28. package/src/entity/find/joins.js +52 -0
  29. package/src/entity/find/queryBuilder.js +95 -0
  30. package/src/entity/find/relations.js +23 -0
  31. package/src/entity/find/scopeProxies.js +60 -0
  32. package/src/entity/find/sqlClients/postgresFuncs.js +171 -0
  33. package/src/entity/find/sqlClients/sqliteFuncs.js +211 -0
  34. package/src/entity/find/where/relationalWhere.js +142 -0
  35. package/src/entity/find/where/where.js +244 -0
  36. package/src/entity/find/where/whereArgsFunctions.js +49 -0
  37. package/src/misc/classes.js +63 -0
  38. package/src/misc/constants.js +42 -0
  39. package/src/misc/miscFunctions.js +167 -0
  40. package/src/misc/ormStore.js +18 -0
  41. package/src/misc/types.d.ts +560 -0
  42. package/src/proxies/instanceProxy.js +544 -0
  43. package/src/proxies/nonRelationalArrayProxy.js +76 -0
  44. package/src/proxies/objectProxy.js +50 -0
  45. package/src/proxies/relationalArrayProxy.js +130 -0
  46. package/src/webpack/masquerade-loader.js +14 -0
  47. package/src/webpack/plugin.js +43 -0
  48. package/src/webpack/store.js +2 -0
  49. package/src/webpack/webpack.config.js +41 -0
  50. package/testing/dev-doc.md +7 -0
  51. package/testing/generationFuncs.js +21 -0
  52. package/testing/miscFunctions.js +97 -0
  53. package/testing/postgres.test.js +254 -0
  54. package/testing/sqlite.test.js +257 -0
  55. 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
+