masquerade-orm 0.8.2 → 0.8.3
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 +15 -14
- package/bin/universalTsInit.js +59 -59
- package/docs/deletion.md +3 -3
- package/docs/find.md +15 -5
- package/index.d.ts +7 -7
- package/package.json +1 -1
- package/src/changeLogger/changeLogger.js +2 -2
- package/src/entity/entity.js +3 -3
- package/src/entity/find/find.js +7 -7
- package/src/entity/find/scopeProxies.js +2 -2
- package/src/entity/find/where/{relationalWhere.js → templateWhere.js} +18 -18
- package/src/entity/find/where/where.js +4 -4
- package/src/misc/classes.js +59 -5
- package/src/misc/ormStore.js +3 -0
- package/src/misc/types.d.ts +2 -2
- package/src/proxies/instanceProxy.js +42 -78
- package/src/webpack/masquerade-loader.js +16 -14
- package/src/webpack/plugin.js +42 -43
- package/testing/postgres.test.js +1 -1
- package/testing/testInit.js +34 -0
package/README.md
CHANGED
|
@@ -37,21 +37,22 @@ npm install masquerade-orm
|
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
# Features
|
|
40
|
-
- **Effortless setup** -
|
|
41
|
-
- **Zero schema planning** -
|
|
42
|
-
- **Powerful IntelliSense** -
|
|
43
|
-
- **Minimal memory usage** -
|
|
44
|
-
- **Optimized querying** -
|
|
45
|
-
- **
|
|
46
|
-
- **
|
|
47
|
-
- **
|
|
48
|
-
- **
|
|
49
|
-
- **
|
|
50
|
-
- **
|
|
51
|
-
- **Abstract and non-abstract inheritance** -
|
|
40
|
+
- **Effortless setup** - No ORM-specific structures; just use your classes.
|
|
41
|
+
- **Zero schema planning** - Tables and schema are generated automatically.
|
|
42
|
+
- **Powerful IntelliSense** - Confidently build complex queries with real-time IDE guidance and warnings when something’s wrong.
|
|
43
|
+
- **Minimal memory usage** - One class instance per database row, minimizing memory usage and avoiding duplicates through smart state management.
|
|
44
|
+
- **Optimized querying** - Fewer queries through intelligent transaction grouping without sacrificing data integrity.
|
|
45
|
+
- **Expressive template-literal WHERE clauses** - Write complex, readable conditions such as LIKE, ≥, nested property access, array element matching (and more) by using IntelliSense-enabled tagged template literals. Any SQL WHERE logic can be expressed through this API.
|
|
46
|
+
- **Cross-column conditions** - Easily write WHERE clauses that compare two columns (within the same table or across joined tables).
|
|
47
|
+
- **Powerful relation capabilities** - Full support for eager & lazy loading, unidirectional / bidirectional / self-referencing relationships, and modifying associations even when they are not loaded.
|
|
48
|
+
- **SQL injection protection** - All queries are parameterized.
|
|
49
|
+
- **Minimal data transfer size** - Improves performance in client-server setups (not applicable for embedded databases like SQLite).
|
|
50
|
+
- **Soft + hard deletion support**
|
|
51
|
+
- **Abstract and non-abstract inheritance** - Enables the use of abstract classes, even in JavaScript.
|
|
52
|
+
- **Strong typing even in JavaScript** - Powered by JSDoc, no compile step required.
|
|
53
|
+
- **Smart schema cleanup** - Automatically detect and easily remove unused tables and columns, reducing database bloat and improving performance.
|
|
54
|
+
- **Lightweight** - Minimal dependencies.
|
|
52
55
|
- **Combines the convenience of embedded SQLite with the strict typing of RDBMS**
|
|
53
|
-
- **Eager and lazy relations**
|
|
54
|
-
- **Unidirectional, bidirectional, and self-referenced relations**
|
|
55
56
|
|
|
56
57
|
|
|
57
58
|
# Example Code Implementation
|
package/bin/universalTsInit.js
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import ts from "typescript"
|
|
4
|
-
import fs from "fs"
|
|
5
|
-
import path from "path"
|
|
6
|
-
import { createSourceFile, SyntaxKind, ScriptKind, ScriptTarget } from "typescript"
|
|
7
|
-
import { nodeArr2ClassDict } from "../src/ORM/bootOrm.js"
|
|
8
|
-
|
|
9
|
-
const configPath = ts.findConfigFile(
|
|
10
|
-
"./",
|
|
11
|
-
ts.sys.fileExists,
|
|
12
|
-
"tsconfig.json"
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
if (!configPath) {
|
|
16
|
-
throw new Error("tsconfig.json not found")
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const configFile = ts.readConfigFile(
|
|
20
|
-
configPath,
|
|
21
|
-
ts.sys.readFile
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
const parsed = ts.parseJsonConfigFileContent(
|
|
25
|
-
configFile.config,
|
|
26
|
-
ts.sys,
|
|
27
|
-
"./"
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
const program = ts.createProgram({
|
|
31
|
-
rootNames: parsed.fileNames,
|
|
32
|
-
options: parsed.options
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
const classNodesArr = []
|
|
36
|
-
|
|
37
|
-
for (const sourceFile of program.getSourceFiles()) {
|
|
38
|
-
if (sourceFile.isDeclarationFile) continue
|
|
39
|
-
const fileText = sourceFile.getFullText()
|
|
40
|
-
const fileNodesArr = createSourceFile('', fileText, ScriptTarget.Latest, true, ScriptKind.TSX).statements
|
|
41
|
-
|
|
42
|
-
for (const node of fileNodesArr) {
|
|
43
|
-
//@ts-ignore
|
|
44
|
-
if ((node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && node.heritageClauses)
|
|
45
|
-
classNodesArr.push(node)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const classDict = nodeArr2ClassDict(classNodesArr)
|
|
50
|
-
const filePath = path.join(
|
|
51
|
-
process.cwd(),
|
|
52
|
-
"ormTypeScriptSetup.js"
|
|
53
|
-
)
|
|
54
|
-
const content = `export function UniversalTsSetup() {globalThis.masqueradeClassDict_ = ${JSON.stringify(classDict)};\n}`
|
|
55
|
-
fs.writeFileSync(filePath, content, "utf8")
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import ts from "typescript"
|
|
4
|
+
import fs from "fs"
|
|
5
|
+
import path from "path"
|
|
6
|
+
import { createSourceFile, SyntaxKind, ScriptKind, ScriptTarget } from "typescript"
|
|
7
|
+
import { nodeArr2ClassDict } from "../src/ORM/bootOrm.js"
|
|
8
|
+
|
|
9
|
+
const configPath = ts.findConfigFile(
|
|
10
|
+
"./",
|
|
11
|
+
ts.sys.fileExists,
|
|
12
|
+
"tsconfig.json"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
if (!configPath) {
|
|
16
|
+
throw new Error("tsconfig.json not found")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const configFile = ts.readConfigFile(
|
|
20
|
+
configPath,
|
|
21
|
+
ts.sys.readFile
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
const parsed = ts.parseJsonConfigFileContent(
|
|
25
|
+
configFile.config,
|
|
26
|
+
ts.sys,
|
|
27
|
+
"./"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
const program = ts.createProgram({
|
|
31
|
+
rootNames: parsed.fileNames,
|
|
32
|
+
options: parsed.options
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const classNodesArr = []
|
|
36
|
+
|
|
37
|
+
for (const sourceFile of program.getSourceFiles()) {
|
|
38
|
+
if (sourceFile.isDeclarationFile) continue
|
|
39
|
+
const fileText = sourceFile.getFullText()
|
|
40
|
+
const fileNodesArr = createSourceFile('', fileText, ScriptTarget.Latest, true, ScriptKind.TSX).statements
|
|
41
|
+
|
|
42
|
+
for (const node of fileNodesArr) {
|
|
43
|
+
//@ts-ignore
|
|
44
|
+
if ((node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && node.heritageClauses)
|
|
45
|
+
classNodesArr.push(node)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const classDict = nodeArr2ClassDict(classNodesArr)
|
|
50
|
+
const filePath = path.join(
|
|
51
|
+
process.cwd(),
|
|
52
|
+
"ormTypeScriptSetup.js"
|
|
53
|
+
)
|
|
54
|
+
const content = `export function UniversalTsSetup() {globalThis.masqueradeClassDict_ = ${JSON.stringify(classDict)};\n}`
|
|
55
|
+
fs.writeFileSync(filePath, content, "utf8")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
package/docs/deletion.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Deleting Instances from the Database
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Soft Deletion
|
|
4
4
|
The ORM does not support soft deletion by default. To implement soft deletion, just create an abstract class like so:
|
|
5
5
|
|
|
6
6
|
**TypeScript**
|
|
@@ -69,7 +69,7 @@ const softDelUser = new SoftDeletableUser('JohnDoe', 'JohnDoe@gmail.com', 'hashe
|
|
|
69
69
|
|
|
70
70
|
**Note:** Unlike `Entity`, the `SoftDel` classes need to be passed into the `ORM.boot` method that is being called to init the ORM.
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
## Hard Deletion
|
|
73
73
|
|
|
74
74
|
```ts
|
|
75
75
|
import { sql } from "masquerade-orm"
|
|
@@ -91,7 +91,7 @@ The `delete` method hard-deletes the instance from the database; the instance ca
|
|
|
91
91
|
</div>
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
## Pre-Deletion Step
|
|
94
|
+
## Pre-Deletion Step for Hard Deletion
|
|
95
95
|
|
|
96
96
|
### When is a pre-deletion step required?
|
|
97
97
|
A pre-deletion step is required when the class instance has **dependents**.
|
package/docs/find.md
CHANGED
|
@@ -13,7 +13,7 @@ The three optional fields are:
|
|
|
13
13
|
|
|
14
14
|
- relations
|
|
15
15
|
- where
|
|
16
|
-
-
|
|
16
|
+
- templateWhere
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
@@ -138,6 +138,16 @@ await User.find({
|
|
|
138
138
|
// 'where' conditions in an easy-to-read and easy-to-write manner.
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
+
<!-- **Equivalent Alternative Syntax:**
|
|
142
|
+
```js
|
|
143
|
+
await User.find({
|
|
144
|
+
where: {
|
|
145
|
+
donations: (donations) => sql`1200 < ${donations} AND ${donations} < 5700`,
|
|
146
|
+
createdAt: (createdAt) => sql`${twoYearsAgo} <= ${createdAt} AND ${createdAt} <= ${oneYearAgo}`
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
``` -->
|
|
150
|
+
|
|
141
151
|
### Using the `sql` function to create a `LIKE` `WHERE` condition
|
|
142
152
|
```js
|
|
143
153
|
import { sql } from "masquerade-orm"
|
|
@@ -176,27 +186,27 @@ const completedOrders = await Order.find({
|
|
|
176
186
|
- **Note:** for SQL-client specific guide for writing `WHERE` conditions involving JSON and array data, go to the bottom of this page or click **[here](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/find.md#array-and-json-where-conditions-guide)**.
|
|
177
187
|
|
|
178
188
|
|
|
179
|
-
## The `
|
|
189
|
+
## The `templateWhere` Field:
|
|
180
190
|
|
|
181
191
|
```js
|
|
182
192
|
import { sql } from "masquerade-orm"
|
|
183
193
|
|
|
184
194
|
// Finds users that have at least one chat that contains at least one message whose sender's username is 'Glory2Christ'.
|
|
185
195
|
await User.find({
|
|
186
|
-
|
|
196
|
+
templateWhere: (user) => sql`${user.chats.messages.sender.username} = 'Glory2Christ'`
|
|
187
197
|
})
|
|
188
198
|
```
|
|
189
199
|
|
|
190
200
|
```js
|
|
191
201
|
import { sql } from "masquerade-orm"
|
|
192
202
|
|
|
193
|
-
// Identical to the previous example, but here the
|
|
203
|
+
// Identical to the previous example, but here the 'templateWhere' is called from a different scope.
|
|
194
204
|
// note: the field has an underscore, to prevent any (rather impossible) name collisions.
|
|
195
205
|
|
|
196
206
|
await User.find({
|
|
197
207
|
where: {
|
|
198
208
|
chats: {
|
|
199
|
-
|
|
209
|
+
templateWhere_: (chat) => sql`${chat.messages.sender.username} = 'Glory2Christ'`,
|
|
200
210
|
// can be combined with regular 'where' conditions - below is valid code
|
|
201
211
|
// chatName: 'The History of Orthodoxy'
|
|
202
212
|
}
|
package/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export {ORM} from "./src/ORM/ORM
|
|
3
|
-
export {Entity} from './src/entity/entity'
|
|
4
|
-
export {DbManager} from "./src/ORM/DbManager"
|
|
5
|
-
export {sql, AND, OR} from "./src/entity/find/where/whereArgsFunctions"
|
|
6
|
-
export {MasqueradePlugin} from "./src/webpack/plugin"
|
|
7
|
-
export {Unique, integer, OrmConfigObj} from './src/misc/types'
|
|
1
|
+
|
|
2
|
+
export {ORM} from "./src/ORM/ORM"
|
|
3
|
+
export {Entity} from './src/entity/entity'
|
|
4
|
+
export {DbManager} from "./src/ORM/DbManager"
|
|
5
|
+
export {sql, AND, OR} from "./src/entity/find/where/whereArgsFunctions"
|
|
6
|
+
export {MasqueradePlugin} from "./src/webpack/plugin"
|
|
7
|
+
export {Unique, integer, OrmConfigObj} from './src/misc/types'
|
package/package.json
CHANGED
|
@@ -20,8 +20,8 @@ export class ChangeLogger {
|
|
|
20
20
|
static async save() {
|
|
21
21
|
const dbChanges = OrmStore.store.dbChangesObj
|
|
22
22
|
if (!Object.keys(dbChanges).length || ChangeLogger.currentlySaving) return
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
|
|
24
|
+
ChangeLogger.currentlySaving = true
|
|
25
25
|
let paramIndex = 1
|
|
26
26
|
const { sqlClient, dbConnection } = OrmStore.store
|
|
27
27
|
const deletedInstancesArr = dbChanges.deletedInstancesArr
|
package/src/entity/entity.js
CHANGED
|
@@ -11,7 +11,7 @@ import { aliasedFindWiki2QueryRes, parseFindWiki, destructureAndValidateArg } fr
|
|
|
11
11
|
import { deproxifyScopeProxy, classWiki2ScopeProxy } from "./find/scopeProxies.js"
|
|
12
12
|
import { postgresCreateProxyArray } from "./find/sqlClients/postgresFuncs.js"
|
|
13
13
|
import { sqliteCreateProxyArray } from "./find/sqlClients/sqliteFuncs.js"
|
|
14
|
-
import {
|
|
14
|
+
import { mergeTemplateWhereScope } from "./find/where/templateWhere.js"
|
|
15
15
|
import { mergeWhereScope } from "./find/where/where.js"
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -68,11 +68,11 @@ export class Entity {
|
|
|
68
68
|
|
|
69
69
|
let classWiki = classWikiDict[this.name]
|
|
70
70
|
if (!classWiki) throw new Error(`The class '${this.name}' has not been included in the ORM boot method.`)
|
|
71
|
-
const [relationsArg, whereArg,
|
|
71
|
+
const [relationsArg, whereArg, templateWhereArg] = destructureAndValidateArg(findObj)
|
|
72
72
|
let findWiki
|
|
73
73
|
const baseProxyMap = classWiki2ScopeProxy(classWiki)
|
|
74
74
|
if (whereArg) mergeWhereScope(baseProxyMap, whereArg)
|
|
75
|
-
if (
|
|
75
|
+
if (templateWhereArg) findWiki = mergeTemplateWhereScope(baseProxyMap, templateWhereArg)
|
|
76
76
|
findWiki = deproxifyScopeProxy(baseProxyMap)
|
|
77
77
|
|
|
78
78
|
const [aliasedFindMap, joinStatements, whereObj] = parseFindWiki(findWiki)
|
package/src/entity/find/find.js
CHANGED
|
@@ -4,14 +4,14 @@ import { rowObj2InstanceProxy } from "../../proxies/instanceProxy.js"
|
|
|
4
4
|
import { createRelationalArrayProxy } from "../../proxies/relationalArrayProxy.js"
|
|
5
5
|
import { generateQueryStrWithCTEs } from "./queryBuilder.js"
|
|
6
6
|
import { junctionJoin, parentJoin } from "./joins.js"
|
|
7
|
-
import { relationalWhereFuncs2Statements } from "./where/
|
|
7
|
+
import { relationalWhereFuncs2Statements } from "./where/templateWhere.js"
|
|
8
8
|
import { whereValues2Statements } from "./where/where.js"
|
|
9
9
|
import { OrmStore } from "../../misc/ormStore.js"
|
|
10
10
|
|
|
11
11
|
export const proxyType = Symbol('proxyType')
|
|
12
12
|
|
|
13
13
|
export function destructureAndValidateArg(findObj) {
|
|
14
|
-
let { relations: eagerLoad, where,
|
|
14
|
+
let { relations: eagerLoad, where, templateWhere } = findObj
|
|
15
15
|
|
|
16
16
|
if (eagerLoad) {
|
|
17
17
|
const type = getType(eagerLoad)
|
|
@@ -25,11 +25,11 @@ export function destructureAndValidateArg(findObj) {
|
|
|
25
25
|
else if (Object.keys(where).length === 0) where = undefined
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
if (
|
|
29
|
-
const type = getType(
|
|
30
|
-
if (type !== "function") throw new Error(`\nInvalid value in the '
|
|
28
|
+
if (templateWhere) {
|
|
29
|
+
const type = getType(templateWhere)
|
|
30
|
+
if (type !== "function") throw new Error(`\nInvalid value in the 'templateWhere' field of the 'find' function's argument. Expected a function.`)
|
|
31
31
|
}
|
|
32
|
-
return [eagerLoad, where,
|
|
32
|
+
return [eagerLoad, where, templateWhere]
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function removeRelationFromUnusedRelations(classMap, key) {
|
|
@@ -63,7 +63,7 @@ export function parseFindWiki(findWiki, aliasBase = 'a', aliasArr = [], joinStat
|
|
|
63
63
|
returnedWiki.junctions[key] = parseFindWiki(joinedTable, aliasBase, aliasArr, joinStatements, whereObj, selectArr)[0]
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
if (returnedWiki.
|
|
66
|
+
if (returnedWiki.templateWhere) relationalWhereFuncs2Statements(returnedWiki, whereObj)
|
|
67
67
|
if (returnedWiki.where) whereValues2Statements(returnedWiki, whereObj)
|
|
68
68
|
return [returnedWiki, joinStatements, whereObj, selectArr]
|
|
69
69
|
}
|
|
@@ -40,7 +40,7 @@ export function classWiki2ScopeProxy(classWiki) {
|
|
|
40
40
|
|| key === "uncalledJunctions_"
|
|
41
41
|
|| key === "junctions_"
|
|
42
42
|
|| key === "where_"
|
|
43
|
-
|| key === "
|
|
43
|
+
|| key === "templateWhere_"
|
|
44
44
|
|| key === "isArray_"
|
|
45
45
|
) return target[key]
|
|
46
46
|
else if (key === proxyType) return 'categorizingProxy'
|
|
@@ -56,5 +56,5 @@ export function findPropOnScopeProxy(scopeProxy, key, rootClassName) {
|
|
|
56
56
|
else if (scopeProxy.uncalledJunctions_ && scopeProxy.uncalledJunctions_[key]) return [scopeProxy.uncalledJunctions_[key], scopeProxy, "uncalledJunctions_"]
|
|
57
57
|
else if (scopeProxy.junctions_ && scopeProxy.junctions_[key]) return [scopeProxy.junctions_[key], scopeProxy, "junctions_"]
|
|
58
58
|
else if (scopeProxy.parent_) return findPropOnScopeProxy(scopeProxy.parent_, key, rootClassName)
|
|
59
|
-
else throw new Error(`\n'${key}' is not a valid property of class ${rootClassName}. Please fix the find function's argument. \nhint: use
|
|
59
|
+
else throw new Error(`\n'${key}' is not a valid property of class ${rootClassName}. Please fix the find function's argument. \nhint: use IntelliSense.`)
|
|
60
60
|
}
|
|
@@ -5,7 +5,7 @@ import { proxyType, removeRelationFromUnusedRelations } from "../find.js"
|
|
|
5
5
|
import { deproxifyScopeProxy, findPropOnScopeProxy, classWiki2ScopeObj } from "../scopeProxies.js"
|
|
6
6
|
|
|
7
7
|
export function relationalWhereFuncs2Statements(mapObj, whereObj, queryStr = ``) {
|
|
8
|
-
const relationalWhereFunc = mapObj.
|
|
8
|
+
const relationalWhereFunc = mapObj.templateWhere
|
|
9
9
|
let AliasObj4func = createFullAndFlatAliasObj(mapObj)
|
|
10
10
|
const sqlWhereObj = relationalWhereFunc(AliasObj4func)
|
|
11
11
|
while (sqlWhereObj.params.length + sqlWhereObj.strings.length > 0) {
|
|
@@ -49,24 +49,24 @@ function createFullAndFlatAliasObj(mapObj, fullFlatAliasObj = {}) {
|
|
|
49
49
|
return fullFlatAliasObj
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export function
|
|
52
|
+
export function mergeTemplateWhereScope(proxyMap, relationalWhereFunc) {
|
|
53
53
|
if (typeof relationalWhereFunc !== "function") throw new Error(`Relational where expects a function.`)
|
|
54
54
|
let mapObj = deproxifyScopeProxy(proxyMap)
|
|
55
55
|
const classWiki = OrmStore.store.classWikiDict[mapObj.className_]
|
|
56
|
-
const relationalWhereMapProxy =
|
|
56
|
+
const relationalWhereMapProxy = createTemplateWhereProxy(mapObj, classWiki)
|
|
57
57
|
relationalWhereFunc(relationalWhereMapProxy)
|
|
58
58
|
mapObj = deproxifyScopeProxy(relationalWhereMapProxy)
|
|
59
|
-
mapObj.
|
|
60
|
-
return
|
|
59
|
+
mapObj.templateWhere_ = relationalWhereFunc
|
|
60
|
+
return reproxyWikiPostTemplateWhere(mapObj, classWiki)
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
function
|
|
64
|
-
if (mapObj.parent_) mapObj.parent_ =
|
|
63
|
+
function reproxyWikiPostTemplateWhere(mapObj, classWiki) {
|
|
64
|
+
if (mapObj.parent_) mapObj.parent_ = reproxyWikiPostTemplateWhere(mapObj.parent_, classWiki.parent)
|
|
65
65
|
|
|
66
66
|
if (mapObj.junctions_) {
|
|
67
67
|
const mapRelations = mapObj.junctions_
|
|
68
68
|
for (const key of Object.keys(mapRelations))
|
|
69
|
-
mapRelations[key] =
|
|
69
|
+
mapRelations[key] = reproxyWikiPostTemplateWhere(mapRelations[key], classWiki.junctions[key])
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const proxy = new Proxy(mapObj, {
|
|
@@ -78,7 +78,7 @@ function reproxyMapObjPostRelationalWhere(mapObj, classWiki) {
|
|
|
78
78
|
|| key === "uncalledJunctions_"
|
|
79
79
|
|| key === "junctions_"
|
|
80
80
|
|| key === "where_"
|
|
81
|
-
|| key === "
|
|
81
|
+
|| key === "templateWhere_"
|
|
82
82
|
|| key === "isArray_"
|
|
83
83
|
) return target[key]
|
|
84
84
|
else if (key === "raw_") return target
|
|
@@ -89,20 +89,20 @@ function reproxyMapObjPostRelationalWhere(mapObj, classWiki) {
|
|
|
89
89
|
return proxy
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
export function
|
|
92
|
+
export function createTemplateWhereProxy(mapObj, classWiki) {
|
|
93
93
|
if (classWiki.parent) {
|
|
94
94
|
let parent
|
|
95
95
|
if (!mapObj.parent_) parent = classWiki2ScopeObj(classWiki)
|
|
96
96
|
else parent = mapObj.parent_
|
|
97
97
|
const parentOrmMap = classWiki.parent
|
|
98
|
-
mapObj.parent_ =
|
|
98
|
+
mapObj.parent_ = createTemplateWhereProxy(parent, parentOrmMap)
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
if (mapObj.junctions_) {
|
|
102
102
|
const mapRelations = mapObj.junctions_
|
|
103
103
|
for (const key of Object.keys(mapRelations)) {
|
|
104
104
|
const relationOrmMap = classWiki.junctions[key]
|
|
105
|
-
mapRelations[key] =
|
|
105
|
+
mapRelations[key] = createTemplateWhereProxy(mapRelations[key], relationOrmMap)
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -115,28 +115,28 @@ export function createRelationalWhereProxy(mapObj, classWiki) {
|
|
|
115
115
|
|| key === "uncalledJunctions_"
|
|
116
116
|
|| key === "junctions_"
|
|
117
117
|
|| key === "where_"
|
|
118
|
-
|| key === "
|
|
118
|
+
|| key === "templateWhere_"
|
|
119
119
|
|| key === "isArray_"
|
|
120
120
|
) return target[key]
|
|
121
121
|
else if (key === "raw_") return target
|
|
122
122
|
else if (key === proxyType) return 'relationalWhereProxy'
|
|
123
|
-
else return
|
|
123
|
+
else return findPropOnTemplateWhereProxy(target, key, classWiki)
|
|
124
124
|
}
|
|
125
125
|
})
|
|
126
126
|
return proxy
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
export function
|
|
129
|
+
export function findPropOnTemplateWhereProxy(mapObj, key, classWiki) {
|
|
130
130
|
if (mapObj.uncalledJunctions_[key]) {
|
|
131
131
|
const relation = mapObj.uncalledJunctions_[key]
|
|
132
132
|
const formattedRelationObj = classWiki2ScopeObj(relation)
|
|
133
133
|
removeRelationFromUnusedRelations(mapObj, key)
|
|
134
134
|
const proxyRelations = mapObj.junctions_ ??= {}
|
|
135
|
-
proxyRelations[key] =
|
|
135
|
+
proxyRelations[key] = createTemplateWhereProxy(formattedRelationObj, classWiki.junctions[key])
|
|
136
136
|
return proxyRelations[key]
|
|
137
137
|
}
|
|
138
138
|
else if (mapObj.columns_[key]) return mapObj.columns_[key]
|
|
139
139
|
else if (mapObj.junctions_[key]) return mapObj.junctions_[key]
|
|
140
|
-
else if (mapObj.parent_) return
|
|
141
|
-
else throw new Error(`\n'${key}' is not a valid property of class ${classWiki.className}. Please fix the find function's
|
|
140
|
+
else if (mapObj.parent_) return findPropOnTemplateWhereProxy(mapObj.parent_, key, classWiki.parent)
|
|
141
|
+
else throw new Error(`\n'${key}' is not a valid property of class ${classWiki.className}. Please fix the find function's templateWhere. \nhint: use intellisense by pressing CNTRL + space to see all viable options.`)
|
|
142
142
|
}
|
|
@@ -4,7 +4,7 @@ import { array2String, getType, nonSnake2Snake } from "../../../misc/miscFunctio
|
|
|
4
4
|
import { OrmStore } from "../../../misc/ormStore.js"
|
|
5
5
|
import { removeRelationFromUnusedRelations } from "../find.js"
|
|
6
6
|
import { classWiki2ScopeProxy } from "../scopeProxies.js"
|
|
7
|
-
import {
|
|
7
|
+
import { mergeTemplateWhereScope } from "./templateWhere.js"
|
|
8
8
|
/**@typedef {import('../../../misc/classes').AndArray} AndArray */
|
|
9
9
|
/**@typedef {import('../../../misc/classes').AndArray} OrArray */
|
|
10
10
|
|
|
@@ -209,7 +209,7 @@ export function mergeWhereScope(proxyMap, whereObj) {
|
|
|
209
209
|
for (const [key, whereVal] of entries) {
|
|
210
210
|
|
|
211
211
|
if (key === "_relationalWhere") {
|
|
212
|
-
proxyMap =
|
|
212
|
+
proxyMap = mergeTemplateWhereScope(proxyMap, whereVal)
|
|
213
213
|
continue
|
|
214
214
|
}
|
|
215
215
|
|
|
@@ -236,8 +236,8 @@ export function mergeWhereScope(proxyMap, whereObj) {
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
const passedMap = classMap.junctions_[key]
|
|
239
|
-
if (whereValType === "function") passedMap.
|
|
240
|
-
else if (whereValType === "array") passedMap.
|
|
239
|
+
if (whereValType === "function") passedMap.templateWhere_ = [whereVal]
|
|
240
|
+
else if (whereValType === "array") passedMap.templateWhere_ = whereVal
|
|
241
241
|
else mergeWhereScope(passedMap, whereVal)
|
|
242
242
|
}
|
|
243
243
|
}
|
package/src/misc/classes.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**@typedef {import('./types').PrimitivesNoNull} PrimitivesNoNull*/
|
|
2
2
|
|
|
3
|
+
import { OrmStore } from './ormStore.js'
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* @template T
|
|
@@ -51,13 +53,65 @@ export class Alias {
|
|
|
51
53
|
|
|
52
54
|
|
|
53
55
|
export class LazyPromise {
|
|
54
|
-
constructor(
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
constructor(instance, property, promiseType, executor) {
|
|
57
|
+
// if (typeof executor !== 'function') {
|
|
58
|
+
// throw new TypeError(
|
|
59
|
+
// `LazyPromise executor must be a function, got ${typeof executor}`
|
|
60
|
+
// )
|
|
61
|
+
// }
|
|
62
|
+
this.instanceContext = {
|
|
63
|
+
instanceId: instance.id,
|
|
64
|
+
instanceClass: instance.constructor.name,
|
|
65
|
+
property,
|
|
66
|
+
promiseType
|
|
67
|
+
}
|
|
68
|
+
this._executor = executor
|
|
69
|
+
this._promise = null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_getPromise() {
|
|
73
|
+
if (!this._promise) {
|
|
74
|
+
this._promise = new Promise((resolve, reject) => {
|
|
75
|
+
try {
|
|
76
|
+
this._executor(resolve, reject)
|
|
77
|
+
} catch (err) {
|
|
78
|
+
reject(err)
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
return this._promise
|
|
83
|
+
}
|
|
57
84
|
|
|
85
|
+
then(onFulfilled, onRejected) {
|
|
86
|
+
return this._getPromise().then(onFulfilled, onRejected)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
catch(onRejected) {
|
|
90
|
+
return this._getPromise().catch(onRejected)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
finally(onFinally) {
|
|
94
|
+
return this._getPromise().finally(onFinally)
|
|
58
95
|
}
|
|
59
96
|
|
|
60
97
|
toString() {
|
|
61
|
-
return `Promise<${this.
|
|
98
|
+
return `Promise<${this.instanceContext.promiseType}>`
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
push(...items) {
|
|
102
|
+
const { instanceClass, instanceId, property, promiseType } = this.instanceContext
|
|
103
|
+
const cleanedType = promiseType.endsWith('[]') ? promiseType.slice(0, -2) : promiseType
|
|
104
|
+
const addedIds = []
|
|
105
|
+
for (const item of items) {
|
|
106
|
+
if (item.constructor.name !== cleanedType) throw new Error(`${item} is of type ${item.constructor.name} but must be of type ${cleanedType}.`)
|
|
107
|
+
addedIds.push(item.id)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const changesObj = OrmStore.store.dbChangesObj
|
|
111
|
+
changesObj[instanceClass] ??= {}
|
|
112
|
+
const instanceChangeObj = changesObj[instanceClass][instanceId] ??= {}
|
|
113
|
+
const relationsLogger = instanceChangeObj[property] ??= { added: [], removed: [] }
|
|
114
|
+
relationsLogger.added.push(...addedIds)
|
|
62
115
|
}
|
|
63
|
-
|
|
116
|
+
|
|
117
|
+
}
|
package/src/misc/ormStore.js
CHANGED
package/src/misc/types.d.ts
CHANGED
|
@@ -204,7 +204,7 @@ type NonRelationsProperties<T> = Exclude<keyof T, RelationsProperties<T>>
|
|
|
204
204
|
export type FindObj<T> = {
|
|
205
205
|
relations?: Partial<RelationsOnly<T>>
|
|
206
206
|
where?: WhereProperties<T>
|
|
207
|
-
|
|
207
|
+
templateWhere?: sqlArrowFnTable<T> | (sqlArrowFn<T> | null)[] | null
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
// ---------------------------------------------------------
|
|
@@ -455,7 +455,7 @@ type ArrColumnsRawParams =
|
|
|
455
455
|
// export type FindObj<T> = {
|
|
456
456
|
// relations?: Partial<RelationsOnly<T>>
|
|
457
457
|
// where?: WhereProperties<T>
|
|
458
|
-
//
|
|
458
|
+
// templateWhere?: sqlArrowFn<T> | sqlArrowFn<T>[]
|
|
459
459
|
// }
|
|
460
460
|
|
|
461
461
|
// // ---------------------------------------------------------
|
|
@@ -65,8 +65,8 @@ export function rowObj2InstanceProxy(resultObj, findWiki, Entities) {
|
|
|
65
65
|
while (!currentWiki.uncalledJunctions[property]) currentWiki = currentWiki.parent
|
|
66
66
|
const uncalledJunctionObj = currentWiki.uncalledJunctions[property]
|
|
67
67
|
const nameOfMapWithJunction = uncalledJunctionObj.className
|
|
68
|
-
const
|
|
69
|
-
instance[property] = new LazyPromise(
|
|
68
|
+
const promiseType = uncalledJunctionObj.isArray ? nameOfMapWithJunction + `[]` : nameOfMapWithJunction
|
|
69
|
+
instance[property] = new LazyPromise(instance, property, promiseType, (resolve, reject) => promiseExecutor(instance, property, resolve, reject))
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -76,43 +76,57 @@ export function rowObj2InstanceProxy(resultObj, findWiki, Entities) {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
ORM[FinalizationRegistrySymb].register(proxy, [proxy.constructor.name, proxy.id])
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function instanceProxyGetHandler(target, key, classWiki) {
|
|
85
|
-
const val = target[key]
|
|
86
|
-
if (!(val instanceof LazyPromise)) return val
|
|
87
|
-
|
|
79
|
+
function promiseExecutor(target, key, resolve, reject) {
|
|
80
|
+
if (ChangeLogger.scheduledFlush) ChangeLogger.save().then()
|
|
88
81
|
const { sqlClient, dbConnection } = OrmStore.store
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (classification === "Join") joinedTable = classWiki.junctions[key]
|
|
93
|
-
else joinedTable = mapWithProp.junctions[key]
|
|
94
|
-
|
|
95
|
-
const isArrayOfInstances = joinedClassMap.isArray
|
|
82
|
+
const classWiki = OrmStore.getClassWiki(target)
|
|
83
|
+
const [classification, joinedClassWiki, mapWithProp] = getPropertyClassification(key, classWiki)
|
|
84
|
+
const isArrayOfInstances = joinedClassWiki.isArray
|
|
96
85
|
|
|
97
86
|
let queryStr = `SELECT entity.* FROM ${nonSnake2Snake(mapWithProp.className)}___${nonSnake2Snake(key)}_jt jt` +
|
|
98
|
-
` LEFT JOIN ${nonSnake2Snake(
|
|
87
|
+
` LEFT JOIN ${nonSnake2Snake(joinedClassWiki.className)} entity ON jt.joined_id = entity.id WHERE jt.joining_id = `
|
|
99
88
|
queryStr += sqlClient === "postgresql" ? `$1` : `?`
|
|
100
89
|
|
|
101
90
|
let queryFunc
|
|
102
91
|
if (sqlClient === "postgresql") queryFunc = (queryStr, id) => dbConnection.query(queryStr, [id])
|
|
103
92
|
else queryFunc = (queryStr, id) => dbConnection.prepare(queryStr).all(id)
|
|
104
93
|
|
|
105
|
-
let promise
|
|
106
94
|
try {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
95
|
+
Promise.resolve(queryFunc(queryStr, target.id))
|
|
96
|
+
.then(rows => {
|
|
97
|
+
const { className, columns, junctions } = joinedClassWiki
|
|
98
|
+
const findWiki = { className, columns, uncalledJunctions: junctions }
|
|
99
|
+
let currentWiki = joinedClassWiki
|
|
100
|
+
let currentScopedMap = findWiki
|
|
101
|
+
while (currentWiki.parent) {
|
|
102
|
+
const { className, columns, junctions } = currentWiki.parent
|
|
103
|
+
currentScopedMap.parent = { className, columns, uncalledJunctions: junctions }
|
|
104
|
+
currentScopedMap = currentScopedMap.parent
|
|
105
|
+
currentWiki = currentWiki.parent
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const proxyArr = []
|
|
109
|
+
for (const row of rows) {
|
|
110
|
+
const rowWithCamelCasedProps = Object.fromEntries(Object.entries(row).map(([key, val]) => [snake2Pascal(key, true), val]))
|
|
111
|
+
proxyArr.push(rowObj2InstanceProxy(rowWithCamelCasedProps, findWiki, OrmStore.store.entities))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (isArrayOfInstances) target[key] = createRelationalArrayProxy(target, key, proxyArr, classWiki.className)
|
|
115
|
+
else target[key] = proxyArr[0]
|
|
116
|
+
|
|
117
|
+
resolve(target[key])
|
|
118
|
+
})
|
|
119
|
+
.catch(reject)
|
|
110
120
|
}
|
|
111
|
-
catch (
|
|
112
|
-
coloredBackgroundConsoleLog(`Lazy loading failed. ${
|
|
121
|
+
catch (err) {
|
|
122
|
+
coloredBackgroundConsoleLog(`Lazy loading failed. ${err}`, 'failure')
|
|
123
|
+
reject(err)
|
|
113
124
|
}
|
|
125
|
+
}
|
|
114
126
|
|
|
115
|
-
|
|
127
|
+
export function insertProxyIntoEntityMap(proxy, entityMap) {
|
|
128
|
+
entityMap.set(proxy.id, new WeakRef(proxy))
|
|
129
|
+
ORM[FinalizationRegistrySymb].register(proxy, [proxy.constructor.name, proxy.id])
|
|
116
130
|
}
|
|
117
131
|
|
|
118
132
|
export function instanceProxySetHandler(target, key, value, eventListenersObj, classWiki) {
|
|
@@ -356,57 +370,6 @@ export function createLazyLoadQueryStr(property, classWiki) {
|
|
|
356
370
|
}
|
|
357
371
|
|
|
358
372
|
|
|
359
|
-
export function createLazyPromise(target, key, queryRes, classWiki, isArrayOfInstances, client) {
|
|
360
|
-
return new Promise(async (resolve) => {
|
|
361
|
-
let resultArr
|
|
362
|
-
try {
|
|
363
|
-
if (client === "postgresql") resultArr = (await queryRes).rows
|
|
364
|
-
else resultArr = queryRes
|
|
365
|
-
|
|
366
|
-
if (!resultArr.length) {
|
|
367
|
-
if (isArrayOfInstances) {
|
|
368
|
-
target[key] = []
|
|
369
|
-
resolve([])
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
target[key] = undefined
|
|
373
|
-
resolve(undefined)
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const { className, columns, junctions } = classWiki
|
|
378
|
-
const findWiki = { className, columns, uncalledJunctions: junctions }
|
|
379
|
-
let currentWiki = classWiki
|
|
380
|
-
let currentScopedMap = findWiki
|
|
381
|
-
while (currentWiki.parent) {
|
|
382
|
-
const { className, columns, junctions } = currentWiki.parent
|
|
383
|
-
currentScopedMap.parent = { className, columns, uncalledJunctions: junctions }
|
|
384
|
-
currentScopedMap = currentScopedMap.parent
|
|
385
|
-
currentWiki = currentWiki.parent
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
const proxyArr = []
|
|
389
|
-
for (const row of resultArr) {
|
|
390
|
-
const rowWithCamelCasedProps = Object.fromEntries(Object.entries(row).map(([key, val]) => [snake2Pascal(key, true), val]))
|
|
391
|
-
proxyArr.push(rowObj2InstanceProxy(rowWithCamelCasedProps, findWiki, OrmStore.store.entities))
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
if (isArrayOfInstances) {
|
|
395
|
-
target[key] = createRelationalArrayProxy(target, key, proxyArr, classWiki.className)
|
|
396
|
-
resolve(target[key])
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
target[key] = proxyArr[0]
|
|
400
|
-
resolve(target[key])
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
catch (e) {
|
|
404
|
-
coloredBackgroundConsoleLog(`Lazy loading failed. ${e}\n`, `failure`)
|
|
405
|
-
}
|
|
406
|
-
})
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
|
|
410
373
|
export function uncalledPropertySetHandler(target, key, value, columnClassificationArr) {
|
|
411
374
|
const [propertyType, propertyTypeObj, mapWithProp] = columnClassificationArr
|
|
412
375
|
const joiningId = target.id
|
|
@@ -496,7 +459,8 @@ export function proxifyEntityInstanceObj(instance, uncalledRelationalProperties)
|
|
|
496
459
|
else if (key === "eEmitter_") return emitter
|
|
497
460
|
else if (key === "eListener_") return eventListenersObj
|
|
498
461
|
else if (key === "_isDeleted_") return target[key]
|
|
499
|
-
return
|
|
462
|
+
return target[key]
|
|
463
|
+
//return instanceProxyGetHandler(target, key, classWiki)
|
|
500
464
|
},
|
|
501
465
|
set: (target, /**@type {string}*/ key, value) => {
|
|
502
466
|
instanceProxySetHandler(target, key, value, eventListenersObj, classWiki)
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { store } from "./store.js"
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export default function (source) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
1
|
+
import { store } from "./store.js"
|
|
2
|
+
import { SyntaxKind } from "typescript"
|
|
3
|
+
import ts from "typescript"
|
|
4
|
+
|
|
5
|
+
export default function (source) {
|
|
6
|
+
const sourceFile = ts.createSourceFile("", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
|
7
|
+
const nodes = sourceFile.statements
|
|
8
|
+
for (const node of nodes) {
|
|
9
|
+
if (!node) continue
|
|
10
|
+
//@ts-ignore
|
|
11
|
+
const isValid = (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && node.heritageClauses
|
|
12
|
+
//@ts-ignore
|
|
13
|
+
if (isValid) store.nodeArr.push(node)
|
|
14
|
+
}
|
|
15
|
+
return source
|
|
16
|
+
}
|
package/src/webpack/plugin.js
CHANGED
|
@@ -1,43 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
import { store } from "./store.js"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
1
|
+
|
|
2
|
+
import { store } from "./store.js"
|
|
3
|
+
import { nodeArr2ClassDict } from "../ORM/bootOrm.js"
|
|
4
|
+
|
|
5
|
+
export class MasqueradePlugin {
|
|
6
|
+
apply(compiler) {
|
|
7
|
+
compiler.hooks.compilation.tap(this.constructor.name, (compilation) => {
|
|
8
|
+
compilation.hooks.processAssets.tap(
|
|
9
|
+
{
|
|
10
|
+
name: this.constructor.name,
|
|
11
|
+
stage: compilation.constructor.PROCESS_ASSETS_STAGE_ADDITIONS,
|
|
12
|
+
},
|
|
13
|
+
(assets) => {
|
|
14
|
+
const classDict = nodeArr2ClassDict(store.nodeArr)
|
|
15
|
+
const prefix = `globalThis.masqueradeClassDict_ = ${JSON.stringify(classDict)};\n`
|
|
16
|
+
|
|
17
|
+
for (const entry of compilation.entrypoints.values()) {
|
|
18
|
+
for (const file of entry.getFiles()) {
|
|
19
|
+
if (!file.endsWith(".js")) continue
|
|
20
|
+
|
|
21
|
+
const asset = compilation.getAsset(file)
|
|
22
|
+
const source = asset.source.source()
|
|
23
|
+
|
|
24
|
+
compilation.updateAsset(
|
|
25
|
+
file,
|
|
26
|
+
new compiler.webpack.sources.RawSource(prefix + source)
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
package/testing/postgres.test.js
CHANGED
|
@@ -10,7 +10,7 @@ import { OrmStore } from '../src/misc/ormStore.js'
|
|
|
10
10
|
|
|
11
11
|
const { House, Person, NonRelationalClass2 } = classes
|
|
12
12
|
|
|
13
|
-
const configObj = createConfigObj()
|
|
13
|
+
const configObj = createConfigObj('postgres', '123456789')
|
|
14
14
|
await resetPostgresDb(configObj.dbConnection)
|
|
15
15
|
await initORM(configObj, classes)
|
|
16
16
|
let dbChanges = OrmStore.store.dbChangesObj
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ORM } from "../index.js"
|
|
2
|
+
import { DatabaseSync } from 'node:sqlite'
|
|
3
|
+
import { Pool } from 'pg'
|
|
4
|
+
/**@typedef {import('../index.js').OrmConfigObj} OrmConfigObj */
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export function createConfigObj(client, /**@type {undefined | string}*/ dbPaswword = undefined) {
|
|
8
|
+
if (client === `sqlite`) return {
|
|
9
|
+
dbConnection: new DatabaseSync('test'),
|
|
10
|
+
idTypeDefault: "INT"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
dbConnection: new Pool({
|
|
15
|
+
user: 'postgres', // e.g., 'postgres'
|
|
16
|
+
host: 'localhost', // database host
|
|
17
|
+
database: 'masquerade-test', // database name
|
|
18
|
+
password: `${dbPaswword}`, // your password
|
|
19
|
+
port: 5432, // default PostgreSQL port
|
|
20
|
+
}),
|
|
21
|
+
idTypeDefault: "INT"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function initORM(configObj, ...classes) {
|
|
26
|
+
await ORM.javascriptBoot(configObj, ...classes)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function resetPostgresDb(pool) {
|
|
30
|
+
await pool.query(
|
|
31
|
+
`DROP SCHEMA public CASCADE;
|
|
32
|
+
CREATE SCHEMA public;`
|
|
33
|
+
)
|
|
34
|
+
}
|