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,244 @@
|
|
|
1
|
+
|
|
2
|
+
import { Alias, aliasSymb, SqlWhereObj } from "../../../misc/classes.js"
|
|
3
|
+
import { array2String, getType, nonSnake2Snake } from "../../../misc/miscFunctions.js"
|
|
4
|
+
import { OrmStore } from "../../../misc/ormStore.js"
|
|
5
|
+
import { removeRelationFromUnusedRelations } from "../find.js"
|
|
6
|
+
import { classWiki2ScopeProxy } from "../scopeProxies.js"
|
|
7
|
+
import { mergeRelationalWhereScope } from "./relationalWhere.js"
|
|
8
|
+
/**@typedef {import('../../../misc/classes').AndArray} AndArray */
|
|
9
|
+
/**@typedef {import('../../../misc/classes').AndArray} OrArray */
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export function whereValues2Statements(mapObj, whereObj) {
|
|
13
|
+
const whereValuesObj = mapObj.where
|
|
14
|
+
for (const key of Object.keys(whereValuesObj)) {
|
|
15
|
+
const whereValue = whereValuesObj[key]
|
|
16
|
+
validateWhereValue(whereValue, key, mapObj.columns[key])
|
|
17
|
+
whereValue2Statement(whereValue, key, mapObj, whereObj)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function validateWhereValue(whereValue, propertyName, /**@type {object}*/ propertyTypeObj) {
|
|
22
|
+
const columnType = propertyTypeObj.type
|
|
23
|
+
const columnIsArray = propertyTypeObj.isArray || false
|
|
24
|
+
const valueType = getType(whereValue)
|
|
25
|
+
let propertyType = columnType
|
|
26
|
+
|
|
27
|
+
if (valueType === "AND" || valueType === "OR") validateAndOrInputs(whereValue, propertyName, propertyType)
|
|
28
|
+
|
|
29
|
+
else if (valueType === "SqlWhereObj") validateSqlObjectParams(whereValue, propertyName)
|
|
30
|
+
|
|
31
|
+
else if (valueType === "function") validateSqlArrowFn(whereValue, propertyName)
|
|
32
|
+
|
|
33
|
+
else if (valueType === "array") {
|
|
34
|
+
if (!columnIsArray) throw new Error(`\nThe 'where' argument ${array2String(whereValue)} is invalid - expected argument of type ${columnType} | Raw | OR | AND | undefined | null.`)
|
|
35
|
+
else {
|
|
36
|
+
const validTypes = [propertyType, "null", "undefined"]
|
|
37
|
+
for (let i = 0; i < whereValue.length; i++) {
|
|
38
|
+
const el = whereValue[i]
|
|
39
|
+
const elType = getType(el)
|
|
40
|
+
if (!validTypes.includes(elType)) throw new Error(`\nThe 'where' argument ${array2String(whereValue)} is invalid due to containing an element of type ${elType} - expected elements of type ${columnType} | undefined | null.`)
|
|
41
|
+
if (!(i in whereValue)) throw new Error(`${whereValue} has a hole at index ${i}.`)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const validTypes = [propertyType, "null", "undefined"]
|
|
47
|
+
if (!validTypes.includes(valueType)) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`\n'${whereValue}' is of type ${valueType} but should be of type ${columnType} | null | undefined. The invalid argument is located in the 'where' field of property '${propertyName}'.`
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function validateAndOrInputs(/**@type {AndArray | OrArray}*/ AndOr, /**@type {string}*/ propertyName, /**@type {any}*/ propertyType) {
|
|
56
|
+
const AndOrValue = AndOr[0]
|
|
57
|
+
for (const elementVal of AndOrValue) {
|
|
58
|
+
const valueType = getType(elementVal)
|
|
59
|
+
if (valueType === "SqlWhereObj") validateSqlObjectParams(elementVal, propertyName)
|
|
60
|
+
else if (valueType === "AND" || valueType === "OR") validateAndOrInputs(elementVal, propertyName, propertyType)
|
|
61
|
+
else if (valueType === "array") {
|
|
62
|
+
//@ts-ignore
|
|
63
|
+
if (propertyType.isArray) validateArrayElementsType(elementVal, propertyType.type, ['null', 'undefined'])
|
|
64
|
+
else throw new Error(`\n'${elementVal}' of type ${valueType} is invalid as an argument of 'AND'/'OR' functions for the property '${propertyName}', which expects values of type ${propertyType.type} | null | undefined | SqlWhereObj | AND | OR.`)
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
//@ts-ignore
|
|
68
|
+
const validTypes = propertyType.isArray ? ["undefined", "null"] : [propertyType.type, "undefined", "null"]
|
|
69
|
+
if (!validTypes.includes(valueType)) throw new Error(`\n'${elementVal}' of type ${valueType} is invalid as an argument of 'AND'/'OR' functions for the property '${propertyName}', which expects values of type ${array2String(validTypes, true)} | SqlWhereObj | AND | OR.`)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function validateArrayElementsType(/**@type {any[]}*/ array, /**@type {string}*/ type, additionalValidTypes = []) {
|
|
75
|
+
const validTypes = [type, ...additionalValidTypes]
|
|
76
|
+
for (let i = 0; i < array.length; i++) {
|
|
77
|
+
if (!(i in array)) throw new Error(`${array2String(array)} has a hole at index ${i}.`)
|
|
78
|
+
const el = array[i]
|
|
79
|
+
const elType = getType(el)
|
|
80
|
+
if (!validTypes.includes(elType)) throw new Error(`\nThe value ${el} inside the array ${array2String(array)} is of type ${elType} but needs to be of type ${type} | null | undefined.`)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function validateSqlObjectParams(sqlObj, propertyName, whereValueFunc = null) {
|
|
85
|
+
if (sqlObj.params.length === 0) return
|
|
86
|
+
|
|
87
|
+
if (whereValueFunc) {
|
|
88
|
+
let hasPoundsign = false
|
|
89
|
+
hasPoundsign = sqlObj.strings.some(str => str.includes("#"))
|
|
90
|
+
if (hasPoundsign) throw new Error(`\nInvalid input in the 'where' field - the value of property ${propertyName} ( ${whereValueFunc} ) should not contain any #'s in the psuedo-query-string. \nWhen passing this property a function, only use a template literal of the function's argument as a placeholder. \nEXAMPLE: (a) => sql'\${a} < val1 OR \${a} > val2'.`)
|
|
91
|
+
|
|
92
|
+
let valueParams = 0
|
|
93
|
+
let placeholderParams = 0
|
|
94
|
+
sqlObj.params.forEach((param) => param instanceof Alias ? placeholderParams++ : valueParams++)
|
|
95
|
+
if (placeholderParams !== valueParams) throw new Error(
|
|
96
|
+
`\nInvalid input in the 'where' field - the value of property ${propertyName} is an 'sql' function ( ${whereValueFunc} ) that expected an equal number of template literals of the alias argument and of template literals of values, but instead got ${placeholderParams} of the former and ${valueParams} of the latter.`
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const param of sqlObj.params) {
|
|
101
|
+
const paramType = getType(param)
|
|
102
|
+
if (paramType === "array") {
|
|
103
|
+
for (let i = 0; i < param.length; i++) {
|
|
104
|
+
if (!(i in param)) throw new Error(`${array2String(param)} has a hole at index ${i}.`)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function validateSqlArrowFn(sqlFunc, propertyName) {
|
|
111
|
+
const sqlWhereObj = sqlFunc(new Alias(propertyName))
|
|
112
|
+
if (!(sqlWhereObj instanceof SqlWhereObj)) throw new Error(`\nInvalid input in the 'where' field, ${sqlFunc} of property ${propertyName} is not valid, the only valid function argument is the tagged template literal function sql. \nE.g. sql'> \${val}' | sql'# > \${val1} AND # < \${val2}' - for more advanced examples refer to documentation.`)
|
|
113
|
+
validateSqlObjectParams(sqlWhereObj, propertyName, sqlFunc)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
function whereValue2Statement(whereValue, propertyName, aliasObj, whereObj) {
|
|
118
|
+
const whereValueType = getType(whereValue)
|
|
119
|
+
let queryStr = ``
|
|
120
|
+
const columnIdentity = aliasObj.alias + `.${nonSnake2Snake(propertyName)}`
|
|
121
|
+
|
|
122
|
+
if (whereValueType === "AND" || whereValueType === "OR") {
|
|
123
|
+
queryStr += andOr2Statement(whereValue, whereValueType, columnIdentity, whereObj)
|
|
124
|
+
}
|
|
125
|
+
else if (whereValueType === "SqlWhereObj") {
|
|
126
|
+
queryStr += sqlWhereObj2Statement(whereValue, columnIdentity, whereObj)
|
|
127
|
+
}
|
|
128
|
+
else if (whereValueType === "function") {
|
|
129
|
+
queryStr += nonRelationalWhereFunction2Statement(whereValue, columnIdentity, whereObj)
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
//primitive values
|
|
133
|
+
if (Array.isArray(whereValue)) whereValue = whereValue.filter(() => true)
|
|
134
|
+
let paramIndex = whereObj.params.length + 1
|
|
135
|
+
queryStr += `${columnIdentity} = $${paramIndex}`
|
|
136
|
+
whereObj.params.push(whereValue)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
queryStr = queryStr.trim().replaceAll(" ", " ")
|
|
140
|
+
whereObj.statements.push(queryStr)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function andOr2Statement(whereValue, whereValueType, columnIdentity, whereObj) {
|
|
144
|
+
let queryStr = ``
|
|
145
|
+
let paramIndex
|
|
146
|
+
whereValue.forEach((el, index) => {
|
|
147
|
+
paramIndex = whereObj.params.length + 1
|
|
148
|
+
if (index !== 0) queryStr += whereValueType === "AND" ? ` AND` : ` OR`
|
|
149
|
+
const elType = getType(el)
|
|
150
|
+
|
|
151
|
+
if (elType === "AND" || elType === "OR") {
|
|
152
|
+
queryStr += andOr2Statement(el, elType, columnIdentity, whereObj)
|
|
153
|
+
}
|
|
154
|
+
else if (elType === "SqlWhereObj") {
|
|
155
|
+
queryStr += ` ` + sqlWhereObj2Statement(el, columnIdentity, whereObj)
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
queryStr += ` ${columnIdentity} = $${paramIndex}`
|
|
159
|
+
whereObj.params.push(el)
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
queryStr = queryStr.trim().replace(" ", " ")
|
|
163
|
+
queryStr = `(` + queryStr + `)`
|
|
164
|
+
return queryStr
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function sqlWhereObj2Statement(sqlWhereObj, columnIdentity, whereObj) {
|
|
168
|
+
let queryStr = ``
|
|
169
|
+
let paramIndex = whereObj.params.length + 1
|
|
170
|
+
let hasPoundsign = false
|
|
171
|
+
hasPoundsign = sqlWhereObj.strings.some(str => str.includes("#"))
|
|
172
|
+
if (!hasPoundsign) queryStr += `# `
|
|
173
|
+
|
|
174
|
+
while (sqlWhereObj.strings.length + sqlWhereObj.params.length > 0) {
|
|
175
|
+
if (sqlWhereObj.strings.length) queryStr += ` ` + sqlWhereObj.strings.shift()
|
|
176
|
+
if (sqlWhereObj.params.length) {
|
|
177
|
+
whereObj.params.push(sqlWhereObj.params.shift())
|
|
178
|
+
queryStr += ` $${paramIndex++}`
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
queryStr = queryStr.replaceAll("#", columnIdentity)
|
|
182
|
+
return queryStr
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function nonRelationalWhereFunction2Statement(func, columnIdentity, whereObj) {
|
|
186
|
+
let queryStr = ``
|
|
187
|
+
const sqlWhereObj = func(new Alias(columnIdentity))
|
|
188
|
+
while (sqlWhereObj.params.length + sqlWhereObj.strings.length > 0) {
|
|
189
|
+
let paramIndex = whereObj.params.length + 1
|
|
190
|
+
|
|
191
|
+
sqlWhereObj.strings.length && (queryStr += ` ` + sqlWhereObj.strings.shift())
|
|
192
|
+
if (sqlWhereObj.params.length) {
|
|
193
|
+
const param = sqlWhereObj.params.shift()
|
|
194
|
+
if (param instanceof Alias) queryStr += ` ` + param[aliasSymb]
|
|
195
|
+
else {
|
|
196
|
+
queryStr += ` $${paramIndex}`
|
|
197
|
+
whereObj.params.push(param)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
queryStr = `(` + queryStr.trim() + `)`
|
|
202
|
+
return queryStr
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
export function mergeWhereScope(proxyMap, whereObj) {
|
|
207
|
+
const entries = Object.entries(whereObj)
|
|
208
|
+
const classWikiDict = OrmStore.store.classWikiDict
|
|
209
|
+
for (const [key, whereVal] of entries) {
|
|
210
|
+
|
|
211
|
+
if (key === "_relationalWhere") {
|
|
212
|
+
proxyMap = mergeRelationalWhereScope(proxyMap, whereVal)
|
|
213
|
+
continue
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const [value, classMap, keyCategory] = proxyMap[key]
|
|
217
|
+
if (keyCategory === "columns_") {
|
|
218
|
+
classMap.where_ ??= {}
|
|
219
|
+
classMap.where_[key] = whereVal
|
|
220
|
+
}
|
|
221
|
+
else if (keyCategory === "uncalledJunctions_" || keyCategory === "junctions_") {
|
|
222
|
+
|
|
223
|
+
const whereValType = getType(whereVal)
|
|
224
|
+
if (whereValType !== "function" && whereValType !== "array" && whereValType !== "object")
|
|
225
|
+
throw new Error(
|
|
226
|
+
`\nThe 'where' field of the find function's argument must be an object where relational fields have values of:
|
|
227
|
+
• another object
|
|
228
|
+
• a single function
|
|
229
|
+
• an array of functions`
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
if (keyCategory === "uncalledJunctions_") {
|
|
233
|
+
removeRelationFromUnusedRelations(classMap, key)
|
|
234
|
+
classMap.junctions_ ??= {}
|
|
235
|
+
classMap.junctions_[key] = classWiki2ScopeProxy(classWikiDict[value.className])
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const passedMap = classMap.junctions_[key]
|
|
239
|
+
if (whereValType === "function") passedMap.relationalWhere_ = [whereVal]
|
|
240
|
+
else if (whereValType === "array") passedMap.relationalWhere_ = whereVal
|
|
241
|
+
else mergeWhereScope(passedMap, whereVal)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @template T
|
|
4
|
+
* @typedef {import('../../../misc/classes').OrArray<T>} OrArray
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @template T
|
|
10
|
+
* @typedef {import('../../../misc/classes').AndArray<T>} AndArray
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**@typedef {import('../../../misc/classes').SqlWhereObj} SqlWhereObjType */
|
|
14
|
+
/**@typedef {import('../../../misc/classes').Alias} Alias */
|
|
15
|
+
|
|
16
|
+
import { SqlWhereObj } from '../../../misc/classes.js'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @template T
|
|
21
|
+
* @param {...T | undefined | OrArray<T | SqlWhereObjType>} values
|
|
22
|
+
* @returns {AndArray<T>}
|
|
23
|
+
*/
|
|
24
|
+
export function AND(...values) {
|
|
25
|
+
//@ts-ignore
|
|
26
|
+
return new AndArray(values)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @template T
|
|
32
|
+
* @param {...T | undefined | AndArray<T | SqlWhereObjType>} values
|
|
33
|
+
* @returns {OrArray<T>}
|
|
34
|
+
*/
|
|
35
|
+
export function OR(...values) {
|
|
36
|
+
//@ts-ignore
|
|
37
|
+
return new OrArray(values)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @template T
|
|
43
|
+
* */
|
|
44
|
+
export function sql(strings,/**@type { (Alias | T)[]}*/ ...values) {
|
|
45
|
+
// strings = strings.filter((str) => str !== '')
|
|
46
|
+
strings = strings.map((el) => el.trim())
|
|
47
|
+
//@ts-ignore
|
|
48
|
+
return new SqlWhereObj(strings, values)
|
|
49
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**@typedef {import('./types').PrimitivesNoNull} PrimitivesNoNull*/
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @template T
|
|
6
|
+
*/
|
|
7
|
+
export class SqlWhereObj {
|
|
8
|
+
constructor(/**@type {string[]}*/ strings, /**@type {(Alias | PrimitivesNoNull)[]}*/ params) {
|
|
9
|
+
this.strings = strings
|
|
10
|
+
this.params = params
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @template T
|
|
17
|
+
* @extends {Array<T>}
|
|
18
|
+
*/
|
|
19
|
+
export class AndArray extends Array {
|
|
20
|
+
/**
|
|
21
|
+
* @param {...T} items
|
|
22
|
+
*/
|
|
23
|
+
constructor(...items) {
|
|
24
|
+
super(...items)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @template T
|
|
31
|
+
* @extends {Array<T>}
|
|
32
|
+
*/
|
|
33
|
+
export class OrArray extends Array {
|
|
34
|
+
/**
|
|
35
|
+
* @param {...T} items
|
|
36
|
+
*/
|
|
37
|
+
constructor(...items) {
|
|
38
|
+
super(...items)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const aliasSymb = Symbol("alias")
|
|
43
|
+
|
|
44
|
+
export class Alias {
|
|
45
|
+
errMsg
|
|
46
|
+
constructor(/**@type {string}*/ alias, /**@type {string | undefined}*/ errMsg = undefined) {
|
|
47
|
+
this[aliasSymb] = alias
|
|
48
|
+
if (errMsg) this.errMsg = errMsg
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
export class LazyPromise {
|
|
54
|
+
constructor(className) {
|
|
55
|
+
this.promise =
|
|
56
|
+
className
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
toString() {
|
|
61
|
+
return `Promise<${this.promise}>`
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export const newEntityInstanceSymb = Symbol("newEntity")
|
|
4
|
+
export const dependenciesSymb = Symbol("dependencies")
|
|
5
|
+
export const referencesSymb = Symbol("references")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const js2db = {
|
|
9
|
+
postgresql: {
|
|
10
|
+
string: "TEXT",
|
|
11
|
+
number: "DOUBLE PRECISION",
|
|
12
|
+
integer: "INTEGER",
|
|
13
|
+
boolean: "BOOLEAN",
|
|
14
|
+
object: "JSONB",
|
|
15
|
+
Date: "TIMESTAMPTZ",
|
|
16
|
+
bigint: "BIGINT",
|
|
17
|
+
BIGINT: "BIGINT",
|
|
18
|
+
INT: "INTEGER",
|
|
19
|
+
UUID: "UUID"
|
|
20
|
+
},
|
|
21
|
+
sqlite: {
|
|
22
|
+
string: "TEXT",
|
|
23
|
+
number: "REAL",
|
|
24
|
+
integer: "INTEGER",
|
|
25
|
+
boolean: "INTEGER",
|
|
26
|
+
object: "TEXT", // Store JSON as TEXT (serialized JSON string)
|
|
27
|
+
Date: "TEXT",
|
|
28
|
+
bigint: "TEXT",
|
|
29
|
+
BIGINT: "TEXT",
|
|
30
|
+
INT: "INTEGER",
|
|
31
|
+
UUID: "TEXT"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const floatColumnTypes = [
|
|
36
|
+
"DOUBLE",
|
|
37
|
+
"DOUBLE PRECISION",
|
|
38
|
+
"REAL",
|
|
39
|
+
"FLOAT",
|
|
40
|
+
"FLOAT8"
|
|
41
|
+
]
|
|
42
|
+
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { Alias, aliasSymb, AndArray, OrArray, SqlWhereObj } from './classes.js';
|
|
2
|
+
import { floatColumnTypes, js2db } from './constants.js';
|
|
3
|
+
|
|
4
|
+
export function nonSnake2Snake(/**@type {string}*/ str) {
|
|
5
|
+
if (str.at(0) === str.at(0)?.toUpperCase()) {
|
|
6
|
+
str = str[0].toLowerCase() + str.slice(1)
|
|
7
|
+
}
|
|
8
|
+
return str
|
|
9
|
+
.replace(/([A-Z])/g, (match, p1, offset) => {
|
|
10
|
+
// Don't prepend underscore if it's the first letter
|
|
11
|
+
return offset === 0 ? p1 : `_${p1}`
|
|
12
|
+
})
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function snake2Pascal(str, camelCase = false) {
|
|
17
|
+
if (camelCase) return str
|
|
18
|
+
.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
|
|
19
|
+
|
|
20
|
+
return str
|
|
21
|
+
.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()) // camelCase
|
|
22
|
+
.replace(/^([a-z])/, (_, first) => first.toUpperCase()); // capitalize first letter
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export function postgres2sqliteQueryStr(queryString) {
|
|
27
|
+
return queryString.replace(/\$\d+/g, '?')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function js2SqlTyping(sqlClient, /**@type {string | undefined}*/ type = undefined, isId = false) {
|
|
31
|
+
if (!type) return js2db[sqlClient]
|
|
32
|
+
const returnedType = js2db[sqlClient][type]
|
|
33
|
+
if (isId && floatColumnTypes.includes(returnedType)) return 'INTEGER'
|
|
34
|
+
return returnedType
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
export function postgres2JsTyping(value, columnTypeObj) {
|
|
39
|
+
if (value === null || value === undefined) return undefined
|
|
40
|
+
const type = columnTypeObj.type
|
|
41
|
+
if (type === 'bigint') return BigInt(value)
|
|
42
|
+
else return value
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function sqlite2JsTyping(value, columnTypeObj) {
|
|
46
|
+
if (value === null || value === undefined ) return undefined
|
|
47
|
+
const type = columnTypeObj.type
|
|
48
|
+
if (columnTypeObj.isArray || type === 'object' || type === 'OrmJSON') return JSON.parse(value)
|
|
49
|
+
else if (type === 'bigint') return BigInt(value)
|
|
50
|
+
else if (type === 'boolean') return value === 1
|
|
51
|
+
else if (type === 'Date') return new Date(value)
|
|
52
|
+
else return value
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function getType(val) {
|
|
56
|
+
if (val === null) return "null"
|
|
57
|
+
if (val instanceof OrArray) return "OR"
|
|
58
|
+
if (val instanceof AndArray) return "AND"
|
|
59
|
+
if (val instanceof SqlWhereObj) return "SqlWhereObj"
|
|
60
|
+
if (val instanceof Alias) return "Alias"
|
|
61
|
+
if (val instanceof Date) return "Date"
|
|
62
|
+
if (Array.isArray(val)) return "array"
|
|
63
|
+
const t = typeof val
|
|
64
|
+
return t
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function array2String(arr, displayingTypes = false) {
|
|
68
|
+
let str = displayingTypes ? `` : `[`
|
|
69
|
+
str += arr
|
|
70
|
+
.map(el => {
|
|
71
|
+
if (typeof el === "function") return "<function>"
|
|
72
|
+
if (el === null) return "null"
|
|
73
|
+
if (el === undefined) return "undefined"
|
|
74
|
+
if (Array.isArray(el)) return array2String(el)
|
|
75
|
+
if (el instanceof Alias) return el[aliasSymb] + `Alias`
|
|
76
|
+
if (typeof el === "object") return JSON.stringify(el)
|
|
77
|
+
return String(el)
|
|
78
|
+
})
|
|
79
|
+
.join(displayingTypes ? " | " : ", ")
|
|
80
|
+
str += displayingTypes ? `` : `]`
|
|
81
|
+
return str
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function jsValue2SqliteValue(param) {
|
|
85
|
+
if (param === undefined) return null
|
|
86
|
+
else {
|
|
87
|
+
const paramType = getType(param)
|
|
88
|
+
if (paramType === "boolean") return param ? 1 : 0
|
|
89
|
+
else if (paramType === "array" || paramType === "object") return JSON.stringify(param)
|
|
90
|
+
else if (paramType === "Date") return param.toISOString()
|
|
91
|
+
else if (paramType === "bigint" || paramType === "function") return param.toString()
|
|
92
|
+
else return param
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**@typedef {import('./types.js').ConsoleLogType} ConsoleLogType */
|
|
97
|
+
export function coloredBackgroundConsoleLog(msg, /**@type {ConsoleLogType}*/ loggingType) {
|
|
98
|
+
let colorCode
|
|
99
|
+
if (loggingType === "success") colorCode = `#00ca79ff`
|
|
100
|
+
else if (loggingType === "failure") colorCode = `#ca0000ff`
|
|
101
|
+
else colorCode = `#c99d00ff`
|
|
102
|
+
|
|
103
|
+
let loggingConfigStr = `color: white; background-color: ${colorCode}; font-size: 16px; font-weight: bold; padding: 10px; border-radius: 5px;`
|
|
104
|
+
console.log(`%c${msg}`, loggingConfigStr)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function getValidTypedArray(/**@type {any[]}*/ array, /**@type {string}*/ expectedType, /**@type {boolean}*/ isRelational) {
|
|
108
|
+
const returnedArr = []
|
|
109
|
+
if (isRelational) {
|
|
110
|
+
const idDict = {}
|
|
111
|
+
for (let i = 0; i < array.length; i++) {
|
|
112
|
+
if (!(i in array)) continue
|
|
113
|
+
const el = array[i]
|
|
114
|
+
if (!el) continue
|
|
115
|
+
|
|
116
|
+
if (idDict[el.id]) {
|
|
117
|
+
coloredBackgroundConsoleLog(`Provided relational array contains duplicate instance with id of ${el.id}. Duplicate removed.`, `warning`)
|
|
118
|
+
continue
|
|
119
|
+
}
|
|
120
|
+
returnedArr.push(el)
|
|
121
|
+
idDict[el.id] = true
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const expectedTypesArr = [expectedType, 'undefined']
|
|
126
|
+
array = array.map(el => el ? el : undefined)
|
|
127
|
+
for (let i = 0; i < array.length; i++) {
|
|
128
|
+
if (!(i in array)) continue
|
|
129
|
+
const el = array[i]
|
|
130
|
+
const elType = getType(el)
|
|
131
|
+
if (expectedTypesArr.includes(elType)) returnedArr.push(el)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return returnedArr
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function getPropertyClassification(propertyName, classWiki, /**@type {null | string | function}*/ errorMsgOrFunction = null) {
|
|
138
|
+
if (classWiki.columns && classWiki.columns[propertyName]) {
|
|
139
|
+
// found on column
|
|
140
|
+
return ["Primitive", classWiki.columns[propertyName], classWiki]
|
|
141
|
+
}
|
|
142
|
+
else if (classWiki.junctions && classWiki.junctions[propertyName]) {
|
|
143
|
+
// found on junction
|
|
144
|
+
return ["Join", classWiki.junctions[propertyName], classWiki]
|
|
145
|
+
}
|
|
146
|
+
else if (classWiki.parent) {
|
|
147
|
+
let currentClass = classWiki
|
|
148
|
+
while (currentClass.parent) {
|
|
149
|
+
const parent = currentClass.parent
|
|
150
|
+
if (parent.columns && parent.columns[propertyName]) {
|
|
151
|
+
// found on parent's columns
|
|
152
|
+
return ["ParentPrimitive", parent.columns[propertyName], parent]
|
|
153
|
+
}
|
|
154
|
+
else if (parent.junctions && parent.junctions[propertyName]) {
|
|
155
|
+
//found on parent's junctions
|
|
156
|
+
return ["ParentJoin", parent.junctions[propertyName], parent]
|
|
157
|
+
}
|
|
158
|
+
currentClass = currentClass.parent
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (errorMsgOrFunction) {
|
|
163
|
+
if (typeof errorMsgOrFunction === 'string') throw new Error(errorMsgOrFunction)
|
|
164
|
+
else errorMsgOrFunction(propertyName, classWiki)
|
|
165
|
+
}
|
|
166
|
+
return ["undefined"]
|
|
167
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class OrmStore {
|
|
2
|
+
static store = {}
|
|
3
|
+
|
|
4
|
+
static getClassChangesObj(instanceClass) {
|
|
5
|
+
const classChangesObj = this.store.dbChangesObj[instanceClass] ??= {}
|
|
6
|
+
return classChangesObj
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static clearDbChanges() {
|
|
10
|
+
const dbChanges = this.store.dbChangesObj
|
|
11
|
+
for (const key of Object.keys(dbChanges)) delete dbChanges[key]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static getClassWiki(instanceClass) {
|
|
15
|
+
return this.store.classWikiDict[instanceClass]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|