masquerade-orm 0.8.1 → 0.8.2
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 +2 -3
- package/docs/deletion.md +1 -1
- package/docs/find.md +264 -264
- package/docs/getting-started-javascript.md +13 -4
- package/docs/getting-started-typescript.md +6 -4
- package/docs/in-depth-class-definitions.md +7 -7
- package/docs/jsdoc-ux-tips.md +251 -16
- package/docs/managing-the-database.md +1 -1
- package/package.json +1 -1
- package/src/webpack/masquerade-loader.js +1 -1
- package/testing/postgres.test.js +1 -1
- package/testing/sqlite.test.js +1 -2
- package/testing/testing-classes.js +2 -2
package/README.md
CHANGED
|
@@ -134,13 +134,12 @@ user.friendList.pop()
|
|
|
134
134
|
|
|
135
135
|
- **[Getting Started - Javascript](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/getting-started-javascript.md#class-definitions)**
|
|
136
136
|
- **[Getting Started - Typescript](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/getting-started-typescript.md#class-definitions)**
|
|
137
|
+
- **[Defining Classes: In-Depth](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/in-depth-class-definitions.md)** **(important read)**
|
|
137
138
|
- **[Find Method](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/find.md#find)**
|
|
138
139
|
- **[Saving to Database](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/saving-to-database.md#saving-to-the-database)**
|
|
139
140
|
- **[Deleting Instances from the Database](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/deletion.md)**
|
|
140
141
|
- **[Managing Database Tables](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/managing-the-database.md)**
|
|
141
|
-
- **[
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
- **[JSDoc – UX Tips](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/jsdoc-ux-tips.md)**
|
|
144
143
|
|
|
145
144
|
<br>
|
|
146
145
|
<div align="center">
|
package/docs/deletion.md
CHANGED
|
@@ -72,7 +72,7 @@ const softDelUser = new SoftDeletableUser('JohnDoe', 'JohnDoe@gmail.com', 'hashe
|
|
|
72
72
|
### Hard Deletion
|
|
73
73
|
|
|
74
74
|
```ts
|
|
75
|
-
import { sql } from "masquerade"
|
|
75
|
+
import { sql } from "masquerade-orm"
|
|
76
76
|
const twoYearsAgo = new Date().setFullYear(new Date().getFullYear() - 2)
|
|
77
77
|
|
|
78
78
|
// finds all instances that haven't been mutated in over two years
|
package/docs/find.md
CHANGED
|
@@ -1,265 +1,265 @@
|
|
|
1
|
-
# Find
|
|
2
|
-
|
|
3
|
-
```js
|
|
4
|
-
await ExampleClass.find(findObj)
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
The `find` method is the most complex part of the ORM. **Fortunately, it is fully covered by IntelliSense, and you are strongly encouraged to rely on it.**
|
|
8
|
-
|
|
9
|
-
It accepts a single argument, findObj, which contains three optional fields.
|
|
10
|
-
Because all fields are optional, findObj itself may be an empty object (although this is rarely useful, as it would return all instances of ExampleClass).
|
|
11
|
-
|
|
12
|
-
The three optional fields are:
|
|
13
|
-
|
|
14
|
-
- relations
|
|
15
|
-
- where
|
|
16
|
-
- relationalWhere
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
## The `relations` Field:
|
|
21
|
-
|
|
22
|
-
The `relations` field determines which relations are eagerly loaded from the database.
|
|
23
|
-
|
|
24
|
-
A crucial detail to understand is that relations are never filtered.
|
|
25
|
-
They are either loaded or not. The ORM never displays partial relational data.
|
|
26
|
-
|
|
27
|
-
```js
|
|
28
|
-
// assume that relationalProp is a property of type SomeClass or SomeClass[]
|
|
29
|
-
await ExampleClass.find(
|
|
30
|
-
{
|
|
31
|
-
relations: {relationalProp: true},
|
|
32
|
-
where: {
|
|
33
|
-
relationalProp: {
|
|
34
|
-
id: 57
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
)
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
The example above translates to:
|
|
42
|
-
**“Fetch all instances of ExampleClass whose relationalProp contains a SomeClass instance with id = 57.”**
|
|
43
|
-
|
|
44
|
-
In other words, the condition matches when either of the following is true:
|
|
45
|
-
|
|
46
|
-
```js
|
|
47
|
-
// 1-to-1 relationship case
|
|
48
|
-
exampleClassInstance.relationalProp === someClassId57
|
|
49
|
-
```
|
|
50
|
-
or
|
|
51
|
-
```js
|
|
52
|
-
// 1-to-many relationship case
|
|
53
|
-
exampleClassInstance.relationalProp.includes(someClassId57)
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Lazy Loading
|
|
57
|
-
|
|
58
|
-
```js
|
|
59
|
-
// Assume the 'Chat' class has relational properties 'users' and 'messages'.
|
|
60
|
-
// Initially, we load only the 'messages' relation for a specific chat.
|
|
61
|
-
|
|
62
|
-
const resultArray = await Chat.find({
|
|
63
|
-
relations: { messages: true }, // eager load the 'messages' relation
|
|
64
|
-
where: { id: 123 } // fetch the chat with ID 123
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
const someChat = resultArray[0]
|
|
68
|
-
|
|
69
|
-
// At this point, 'someChat.users' is not loaded.
|
|
70
|
-
// To load the 'users' relation, we need to await it.
|
|
71
|
-
await someChat.users
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
## The `where` Field:
|
|
76
|
-
|
|
77
|
-
The `where` field is for filtering the root instances, in the following case, Chat instances.
|
|
78
|
-
```js
|
|
79
|
-
await Chat.find({
|
|
80
|
-
where: {
|
|
81
|
-
messages: {
|
|
82
|
-
sender: {
|
|
83
|
-
id: 12
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
```
|
|
89
|
-
Translation: **“Find all chats that contain a message from a user with the id 12, without loading messages.“**
|
|
90
|
-
|
|
91
|
-
- **Note:** The scope of the `where` condtions is agnostic to the scope of the `relations` (eager-loading).
|
|
92
|
-
It is completely safe to filter based on specific relations without having said relations passed into the `relations` field.
|
|
93
|
-
|
|
94
|
-
### Introduction to the `sql`, `OR` and `AND` functions
|
|
95
|
-
|
|
96
|
-
```js
|
|
97
|
-
import { sql, AND, OR } from "masquerade"
|
|
98
|
-
|
|
99
|
-
await Angel.find({
|
|
100
|
-
where: {
|
|
101
|
-
// name is either "Micheal" OR "Gabriel"
|
|
102
|
-
name: OR('Micheal', 'Gabriel'),
|
|
103
|
-
|
|
104
|
-
// demonsSentToAbyss is greater than 12,000 AND less than 57,000
|
|
105
|
-
demonsSentToAbyss: AND(sql`> 12000`, sql`< 57000`)
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Using the `sql` function with explicit column identifiers
|
|
111
|
-
In the previous example, the `sql` function implicitly inserted a column identifier (`#`) on the left side of the SQL statement.
|
|
112
|
-
```js
|
|
113
|
-
// these two statements are equivalent
|
|
114
|
-
sql`> 12000`
|
|
115
|
-
sql`# > 12000`
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
In next example, `#` identifiers must be written explicitly because the SQL string uses `AND` conditional operators directly, rather than using the `AND()` helper function.
|
|
119
|
-
|
|
120
|
-
```js
|
|
121
|
-
import { sql } from "masquerade"
|
|
122
|
-
|
|
123
|
-
const twoYearsAgo = new Date().setFullYear(new Date().getFullYear() - 2)
|
|
124
|
-
const oneYearAgo = new Date().setFullYear(new Date().getFullYear() - 1)
|
|
125
|
-
|
|
126
|
-
await User.find({
|
|
127
|
-
where: {
|
|
128
|
-
// donations between 1,200 and 5,700 cents (exclusive)
|
|
129
|
-
donations: sql`1200 < # AND # < 5700`,
|
|
130
|
-
|
|
131
|
-
// account's age is between one and two years old.
|
|
132
|
-
createdAt: sql`${twoYearsAgo} <= # AND # <= ${oneYearAgo}`
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
// The ANDs are written directly inside the 'sql' string instead of
|
|
136
|
-
// having to rely on helper functions to achieve the same result.
|
|
137
|
-
// The 'sql' function gives you the ability to write powerful
|
|
138
|
-
// 'where' conditions in an easy-to-read and easy-to-write manner.
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Using the `sql` function to create a `LIKE` `WHERE` condition
|
|
142
|
-
```js
|
|
143
|
-
import { sql } from "masquerade"
|
|
144
|
-
|
|
145
|
-
await User.find({
|
|
146
|
-
where: {
|
|
147
|
-
// registered using a Gmail email
|
|
148
|
-
email: sql`LIKE '%@gmail.com%'`
|
|
149
|
-
}
|
|
150
|
-
})
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Using the `sql` function to create a `WHERE` condition for matching JSON values
|
|
154
|
-
|
|
155
|
-
```ts
|
|
156
|
-
import { Entity } from "masquerade"
|
|
157
|
-
|
|
158
|
-
type OrderOverview = {
|
|
159
|
-
status: "pending" | "completed" | "cancelled"
|
|
160
|
-
total: number
|
|
161
|
-
currency: string
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
class Order extends Entity {
|
|
165
|
-
// other properties...
|
|
166
|
-
metadata: UserMetadata
|
|
167
|
-
// other properties + constructor...
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const completedOrders = await Order.find({
|
|
171
|
-
where:
|
|
172
|
-
{ overview: sql`json_extract(#, '$.status') = 'completed'` }
|
|
173
|
-
})
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
- **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
|
-
|
|
178
|
-
|
|
179
|
-
## The `relationalWhere` Field:
|
|
180
|
-
|
|
181
|
-
```js
|
|
182
|
-
import { sql } from "masquerade"
|
|
183
|
-
|
|
184
|
-
// Finds users that have at least one chat that contains at least one message whose sender's username is 'Glory2Christ'.
|
|
185
|
-
await User.find({
|
|
186
|
-
relationalWhere: (user) => sql`${user.chats.messages.sender.username} = 'Glory2Christ'`
|
|
187
|
-
})
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
```js
|
|
191
|
-
import { sql } from "masquerade"
|
|
192
|
-
|
|
193
|
-
// Identical to the previous example, but here the relational where is called from a different scope.
|
|
194
|
-
// note: the field has an underscore, to prevent any (rather impossible) name collisions.
|
|
195
|
-
|
|
196
|
-
await User.find({
|
|
197
|
-
where: {
|
|
198
|
-
chats: {
|
|
199
|
-
relationalWhere_: (chat) => sql`${chat.messages.sender.username} = 'Glory2Christ'`,
|
|
200
|
-
// can be combined with regular 'where' conditions - below is valid code
|
|
201
|
-
// chatName: 'The History of Orthodoxy'
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
})
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Array and JSON `WHERE` Conditions Guide
|
|
208
|
-
|
|
209
|
-
The model we will use for the examples:
|
|
210
|
-
|
|
211
|
-
```ts
|
|
212
|
-
import { Entity } from "masquerade"
|
|
213
|
-
|
|
214
|
-
type UserMetadata = {
|
|
215
|
-
roles: string[] // e.g., ["admin", "moderator"]
|
|
216
|
-
lastLogin?: string // optional, ISO date string
|
|
217
|
-
preferences?: {
|
|
218
|
-
theme?: "light" | "dark"
|
|
219
|
-
notifications?: boolean
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
class User extends Entity {
|
|
224
|
-
// other properties...
|
|
225
|
-
metadata: UserMetadata
|
|
226
|
-
sessions: string[]
|
|
227
|
-
// other properties + constructor...
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
Assuming we are writing the condition for the property `metadata` or `sessions` like so:
|
|
232
|
-
```ts
|
|
233
|
-
import { sql } from "masquerade"
|
|
234
|
-
// 'metadata' find
|
|
235
|
-
const users = await User.find({where: {metadata: sql`_OPERATION_STRING_`}})
|
|
236
|
-
|
|
237
|
-
// 'sessions' find
|
|
238
|
-
const users2 = await User.find({where: {sessions: sql`_OPERATION_STRING_`}})
|
|
239
|
-
|
|
240
|
-
// **if not specified, the default is the 'metadata' find
|
|
241
|
-
|
|
242
|
-
// replace _OPERATION_STRING_ with the appropriate
|
|
243
|
-
// operation string from the table below
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
<strong>**Operation String Table**
|
|
247
|
-
|
|
248
|
-
| Operation | SQLite | PostgreSQL |
|
|
249
|
-
|-------------|---------------|------------|
|
|
250
|
-
Array length <br>(example uses len = 2) | **'metadata' find** <br> `json_array_length(json_extract(#, '$.roles')) > 2` <br> **'sessions' find** <br> `json_array_length(json_extract(#)) > 2` | **'metadata' find** <br> `jsonb_array_length(#->'roles') > 2` <br> **'sessions' find** <br> `jsonb_array_length(#) > 2`|
|
|
251
|
-
| Access index `i` of array | **'metadata' find** <br>`json_extract(#, '$.roles[i]') = 'admin'`<br> **'sessions' find** <br>`json_extract(#, '$[i]') = 'SOME_SESSION_ID'` | **'metadata' find** <br>`#->'roles'->>i = 'admin''`<br> **'sessions' find** <br>`#->>i = 'admin'` |
|
|
252
|
-
| Check if array contains a value | `json_extract(#, '$.roles') LIKE '%"admin"%'` | `#->'roles' @> '["admin"]'::jsonb` |
|
|
253
|
-
Check nested field | `json_extract(#, '$.preferences.theme') = 'dark'` | `#->'preferences'->>'theme' = 'dark'` |
|
|
254
|
-
</strong>
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
<br>
|
|
258
|
-
<div align="center">
|
|
259
|
-
<strong>
|
|
260
|
-
© 2026
|
|
261
|
-
<a href="https://github.com/MasqueradeORM">MasqueradeORM </a>
|
|
262
|
-
-
|
|
263
|
-
Released under the MIT License
|
|
264
|
-
</strong>
|
|
1
|
+
# Find
|
|
2
|
+
|
|
3
|
+
```js
|
|
4
|
+
await ExampleClass.find(findObj)
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
The `find` method is the most complex part of the ORM. **Fortunately, it is fully covered by IntelliSense, and you are strongly encouraged to rely on it.**
|
|
8
|
+
|
|
9
|
+
It accepts a single argument, findObj, which contains three optional fields.
|
|
10
|
+
Because all fields are optional, findObj itself may be an empty object (although this is rarely useful, as it would return all instances of ExampleClass).
|
|
11
|
+
|
|
12
|
+
The three optional fields are:
|
|
13
|
+
|
|
14
|
+
- relations
|
|
15
|
+
- where
|
|
16
|
+
- relationalWhere
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## The `relations` Field:
|
|
21
|
+
|
|
22
|
+
The `relations` field determines which relations are eagerly loaded from the database.
|
|
23
|
+
|
|
24
|
+
A crucial detail to understand is that relations are never filtered.
|
|
25
|
+
They are either loaded or not. The ORM never displays partial relational data.
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
// assume that relationalProp is a property of type SomeClass or SomeClass[]
|
|
29
|
+
await ExampleClass.find(
|
|
30
|
+
{
|
|
31
|
+
relations: {relationalProp: true},
|
|
32
|
+
where: {
|
|
33
|
+
relationalProp: {
|
|
34
|
+
id: 57
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The example above translates to:
|
|
42
|
+
**“Fetch all instances of ExampleClass whose relationalProp contains a SomeClass instance with id = 57.”**
|
|
43
|
+
|
|
44
|
+
In other words, the condition matches when either of the following is true:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
// 1-to-1 relationship case
|
|
48
|
+
exampleClassInstance.relationalProp === someClassId57
|
|
49
|
+
```
|
|
50
|
+
or
|
|
51
|
+
```js
|
|
52
|
+
// 1-to-many relationship case
|
|
53
|
+
exampleClassInstance.relationalProp.includes(someClassId57)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Lazy Loading
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
// Assume the 'Chat' class has relational properties 'users' and 'messages'.
|
|
60
|
+
// Initially, we load only the 'messages' relation for a specific chat.
|
|
61
|
+
|
|
62
|
+
const resultArray = await Chat.find({
|
|
63
|
+
relations: { messages: true }, // eager load the 'messages' relation
|
|
64
|
+
where: { id: 123 } // fetch the chat with ID 123
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const someChat = resultArray[0]
|
|
68
|
+
|
|
69
|
+
// At this point, 'someChat.users' is not loaded.
|
|
70
|
+
// To load the 'users' relation, we need to await it.
|
|
71
|
+
await someChat.users
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
## The `where` Field:
|
|
76
|
+
|
|
77
|
+
The `where` field is for filtering the root instances, in the following case, Chat instances.
|
|
78
|
+
```js
|
|
79
|
+
await Chat.find({
|
|
80
|
+
where: {
|
|
81
|
+
messages: {
|
|
82
|
+
sender: {
|
|
83
|
+
id: 12
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
Translation: **“Find all chats that contain a message from a user with the id 12, without loading messages.“**
|
|
90
|
+
|
|
91
|
+
- **Note:** The scope of the `where` condtions is agnostic to the scope of the `relations` (eager-loading).
|
|
92
|
+
It is completely safe to filter based on specific relations without having said relations passed into the `relations` field.
|
|
93
|
+
|
|
94
|
+
### Introduction to the `sql`, `OR` and `AND` functions
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
import { sql, AND, OR } from "masquerade-orm"
|
|
98
|
+
|
|
99
|
+
await Angel.find({
|
|
100
|
+
where: {
|
|
101
|
+
// name is either "Micheal" OR "Gabriel"
|
|
102
|
+
name: OR('Micheal', 'Gabriel'),
|
|
103
|
+
|
|
104
|
+
// demonsSentToAbyss is greater than 12,000 AND less than 57,000
|
|
105
|
+
demonsSentToAbyss: AND(sql`> 12000`, sql`< 57000`)
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Using the `sql` function with explicit column identifiers
|
|
111
|
+
In the previous example, the `sql` function implicitly inserted a column identifier (`#`) on the left side of the SQL statement.
|
|
112
|
+
```js
|
|
113
|
+
// these two statements are equivalent
|
|
114
|
+
sql`> 12000`
|
|
115
|
+
sql`# > 12000`
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
In next example, `#` identifiers must be written explicitly because the SQL string uses `AND` conditional operators directly, rather than using the `AND()` helper function.
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
import { sql } from "masquerade-orm"
|
|
122
|
+
|
|
123
|
+
const twoYearsAgo = new Date().setFullYear(new Date().getFullYear() - 2)
|
|
124
|
+
const oneYearAgo = new Date().setFullYear(new Date().getFullYear() - 1)
|
|
125
|
+
|
|
126
|
+
await User.find({
|
|
127
|
+
where: {
|
|
128
|
+
// donations between 1,200 and 5,700 cents (exclusive)
|
|
129
|
+
donations: sql`1200 < # AND # < 5700`,
|
|
130
|
+
|
|
131
|
+
// account's age is between one and two years old.
|
|
132
|
+
createdAt: sql`${twoYearsAgo} <= # AND # <= ${oneYearAgo}`
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
// The ANDs are written directly inside the 'sql' string instead of
|
|
136
|
+
// having to rely on helper functions to achieve the same result.
|
|
137
|
+
// The 'sql' function gives you the ability to write powerful
|
|
138
|
+
// 'where' conditions in an easy-to-read and easy-to-write manner.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Using the `sql` function to create a `LIKE` `WHERE` condition
|
|
142
|
+
```js
|
|
143
|
+
import { sql } from "masquerade-orm"
|
|
144
|
+
|
|
145
|
+
await User.find({
|
|
146
|
+
where: {
|
|
147
|
+
// registered using a Gmail email
|
|
148
|
+
email: sql`LIKE '%@gmail.com%'`
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Using the `sql` function to create a `WHERE` condition for matching JSON values
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { Entity } from "masquerade-orm"
|
|
157
|
+
|
|
158
|
+
type OrderOverview = {
|
|
159
|
+
status: "pending" | "completed" | "cancelled"
|
|
160
|
+
total: number
|
|
161
|
+
currency: string
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
class Order extends Entity {
|
|
165
|
+
// other properties...
|
|
166
|
+
metadata: UserMetadata
|
|
167
|
+
// other properties + constructor...
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const completedOrders = await Order.find({
|
|
171
|
+
where:
|
|
172
|
+
{ overview: sql`json_extract(#, '$.status') = 'completed'` }
|
|
173
|
+
})
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
- **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
|
+
|
|
178
|
+
|
|
179
|
+
## The `relationalWhere` Field:
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
import { sql } from "masquerade-orm"
|
|
183
|
+
|
|
184
|
+
// Finds users that have at least one chat that contains at least one message whose sender's username is 'Glory2Christ'.
|
|
185
|
+
await User.find({
|
|
186
|
+
relationalWhere: (user) => sql`${user.chats.messages.sender.username} = 'Glory2Christ'`
|
|
187
|
+
})
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
import { sql } from "masquerade-orm"
|
|
192
|
+
|
|
193
|
+
// Identical to the previous example, but here the relational where is called from a different scope.
|
|
194
|
+
// note: the field has an underscore, to prevent any (rather impossible) name collisions.
|
|
195
|
+
|
|
196
|
+
await User.find({
|
|
197
|
+
where: {
|
|
198
|
+
chats: {
|
|
199
|
+
relationalWhere_: (chat) => sql`${chat.messages.sender.username} = 'Glory2Christ'`,
|
|
200
|
+
// can be combined with regular 'where' conditions - below is valid code
|
|
201
|
+
// chatName: 'The History of Orthodoxy'
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Array and JSON `WHERE` Conditions Guide
|
|
208
|
+
|
|
209
|
+
The model we will use for the examples:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
import { Entity } from "masquerade-orm"
|
|
213
|
+
|
|
214
|
+
type UserMetadata = {
|
|
215
|
+
roles: string[] // e.g., ["admin", "moderator"]
|
|
216
|
+
lastLogin?: string // optional, ISO date string
|
|
217
|
+
preferences?: {
|
|
218
|
+
theme?: "light" | "dark"
|
|
219
|
+
notifications?: boolean
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
class User extends Entity {
|
|
224
|
+
// other properties...
|
|
225
|
+
metadata: UserMetadata
|
|
226
|
+
sessions: string[]
|
|
227
|
+
// other properties + constructor...
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Assuming we are writing the condition for the property `metadata` or `sessions` like so:
|
|
232
|
+
```ts
|
|
233
|
+
import { sql } from "masquerade-orm"
|
|
234
|
+
// 'metadata' find
|
|
235
|
+
const users = await User.find({where: {metadata: sql`_OPERATION_STRING_`}})
|
|
236
|
+
|
|
237
|
+
// 'sessions' find
|
|
238
|
+
const users2 = await User.find({where: {sessions: sql`_OPERATION_STRING_`}})
|
|
239
|
+
|
|
240
|
+
// **if not specified, the default is the 'metadata' find
|
|
241
|
+
|
|
242
|
+
// replace _OPERATION_STRING_ with the appropriate
|
|
243
|
+
// operation string from the table below
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
<strong>**Operation String Table**
|
|
247
|
+
|
|
248
|
+
| Operation | SQLite | PostgreSQL |
|
|
249
|
+
|-------------|---------------|------------|
|
|
250
|
+
Array length <br>(example uses len = 2) | **'metadata' find** <br> `json_array_length(json_extract(#, '$.roles')) > 2` <br> **'sessions' find** <br> `json_array_length(json_extract(#)) > 2` | **'metadata' find** <br> `jsonb_array_length(#->'roles') > 2` <br> **'sessions' find** <br> `jsonb_array_length(#) > 2`|
|
|
251
|
+
| Access index `i` of array | **'metadata' find** <br>`json_extract(#, '$.roles[i]') = 'admin'`<br> **'sessions' find** <br>`json_extract(#, '$[i]') = 'SOME_SESSION_ID'` | **'metadata' find** <br>`#->'roles'->>i = 'admin''`<br> **'sessions' find** <br>`#->>i = 'admin'` |
|
|
252
|
+
| Check if array contains a value | `json_extract(#, '$.roles') LIKE '%"admin"%'` | `#->'roles' @> '["admin"]'::jsonb` |
|
|
253
|
+
Check nested field | `json_extract(#, '$.preferences.theme') = 'dark'` | `#->'preferences'->>'theme' = 'dark'` |
|
|
254
|
+
</strong>
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
<br>
|
|
258
|
+
<div align="center">
|
|
259
|
+
<strong>
|
|
260
|
+
© 2026
|
|
261
|
+
<a href="https://github.com/MasqueradeORM">MasqueradeORM </a>
|
|
262
|
+
-
|
|
263
|
+
Released under the MIT License
|
|
264
|
+
</strong>
|
|
265
265
|
</div>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
## 1) Declaring the Class:
|
|
5
5
|
```js
|
|
6
|
-
import { Entity } from 'masquerade'
|
|
6
|
+
import { Entity } from 'masquerade-orm'
|
|
7
7
|
|
|
8
8
|
class YourClass extends Entity {
|
|
9
9
|
// class properties
|
|
@@ -18,7 +18,7 @@ The class **MUST** extend `Entity` or a descendent of `Entity`.
|
|
|
18
18
|
|
|
19
19
|
## 3) Making a Table Column Unique:
|
|
20
20
|
```js
|
|
21
|
-
/**@typedef {import('masquerade').integer} integer */
|
|
21
|
+
/**@typedef {import('masquerade-orm').integer} integer */
|
|
22
22
|
/**@type {string | Unique}*/ propertyName
|
|
23
23
|
```
|
|
24
24
|
|
|
@@ -26,7 +26,8 @@ The class **MUST** extend `Entity` or a descendent of `Entity`.
|
|
|
26
26
|
Assuming we have the following classes extending Entity: `User`, `Chat` and `Message`.
|
|
27
27
|
|
|
28
28
|
```js
|
|
29
|
-
import { Entity } from 'masquerade'
|
|
29
|
+
import { Entity } from 'masquerade-orm'
|
|
30
|
+
import { User, Chat, Message } from './your/entities'
|
|
30
31
|
|
|
31
32
|
class Example extends Entity {
|
|
32
33
|
// one-to-one relationship with a User instance
|
|
@@ -47,6 +48,8 @@ class Example extends Entity {
|
|
|
47
48
|
Each relational property will create a junction table named `className___propName_jt`.
|
|
48
49
|
|
|
49
50
|
|
|
51
|
+
** **For more in-depth documentation regarding class definitions **[click here](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/in-depth-class-definitions.md)**.** **
|
|
52
|
+
|
|
50
53
|
# Booting Up the ORM
|
|
51
54
|
|
|
52
55
|
## 1) Database Connection Driver:
|
|
@@ -76,7 +79,7 @@ const yourDbConnection = new Pool({
|
|
|
76
79
|
|
|
77
80
|
## 2) Configuration Object:
|
|
78
81
|
```js
|
|
79
|
-
/**@typedef {import('masquerade').OrmConfigObj} OrmConfigObj*/
|
|
82
|
+
/**@typedef {import('masquerade-orm').OrmConfigObj} OrmConfigObj*/
|
|
80
83
|
|
|
81
84
|
/** @type {OrmConfigObj} */ const ormConfig = {
|
|
82
85
|
dbConnection: yourDbConnection,
|
|
@@ -101,6 +104,12 @@ await ORM.javascriptBoot(ormConfig, classes, moreClasses, someClass)
|
|
|
101
104
|
|
|
102
105
|
<h1 align="center">All done!</h1>
|
|
103
106
|
|
|
107
|
+
<div align="center">
|
|
108
|
+
|
|
109
|
+
### **It is HIGHLY recommended to read [JSDoc – UX Tips](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/jsdoc-ux-tips.md)**
|
|
110
|
+
|
|
111
|
+
</div>
|
|
112
|
+
|
|
104
113
|
<br>
|
|
105
114
|
<div align="center">
|
|
106
115
|
<strong>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
## 1) Declaring the Class:
|
|
5
5
|
```js
|
|
6
|
-
import { Entity } from 'masquerade'
|
|
6
|
+
import { Entity } from 'masquerade-orm'
|
|
7
7
|
|
|
8
8
|
class YourClass extends Entity {
|
|
9
9
|
// class properties
|
|
@@ -20,7 +20,7 @@ propertyName?: string
|
|
|
20
20
|
## 3) Making a Table Column Unique:
|
|
21
21
|
|
|
22
22
|
```ts
|
|
23
|
-
import { Unique } from 'masquerade'
|
|
23
|
+
import { Unique } from 'masquerade-orm'
|
|
24
24
|
propertyName: string | Unique
|
|
25
25
|
```
|
|
26
26
|
|
|
@@ -28,7 +28,8 @@ propertyName: string | Unique
|
|
|
28
28
|
Assuming we have the following classes extending Entity: `User`, `Chat` and `Message`.
|
|
29
29
|
|
|
30
30
|
```ts
|
|
31
|
-
import { Entity } from 'masquerade'
|
|
31
|
+
import { Entity } from 'masquerade-orm'
|
|
32
|
+
import { User, Chat, Message } from './your/entities'
|
|
32
33
|
|
|
33
34
|
class Example extends Entity {
|
|
34
35
|
// one-to-one relationship with a User instance
|
|
@@ -48,6 +49,7 @@ class Example extends Entity {
|
|
|
48
49
|
```
|
|
49
50
|
Each relational property will create a junction table named `className___propName_jt`.
|
|
50
51
|
|
|
52
|
+
** **For more in-depth documentation regarding class definitions **[click here](https://github.com/MasqueradeORM/MasqueradeORM/blob/master/docs/in-depth-class-definitions.md)**.** **
|
|
51
53
|
|
|
52
54
|
# Booting Up the ORM
|
|
53
55
|
|
|
@@ -78,7 +80,7 @@ const yourDbConnection = new Pool({
|
|
|
78
80
|
|
|
79
81
|
## 2) Configuration Object:
|
|
80
82
|
```ts
|
|
81
|
-
import type { OrmConfigObj } from "masquerade"
|
|
83
|
+
import type { OrmConfigObj } from "masquerade-orm"
|
|
82
84
|
|
|
83
85
|
const ormConfig: OrmConfigObj = {
|
|
84
86
|
dbConnection: yourDbConnection,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
**TypseScript**
|
|
7
7
|
```ts
|
|
8
|
-
import { Entity, integer } from 'masquerade'
|
|
8
|
+
import { Entity, integer } from 'masquerade-orm'
|
|
9
9
|
|
|
10
10
|
type MyJSON = {
|
|
11
11
|
booleanField: boolean
|
|
@@ -45,8 +45,8 @@ class ExampleClass extends Entity {
|
|
|
45
45
|
```
|
|
46
46
|
**JavaScript**
|
|
47
47
|
```js
|
|
48
|
-
import { Entity } from 'masquerade'
|
|
49
|
-
/**@typedef {import('masquerade').integer} integer */
|
|
48
|
+
import { Entity } from 'masquerade-orm'
|
|
49
|
+
/**@typedef {import('masquerade-orm').integer} integer */
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* @typedef {Object} MyJSON
|
|
@@ -63,7 +63,7 @@ class ExampleClass extends Entity {
|
|
|
63
63
|
/**@type {number}*/ float = 15.7
|
|
64
64
|
|
|
65
65
|
// Allowed
|
|
66
|
-
/**@type {(string | undefined)[]}*/ stringArrWithUndefineds = [
|
|
66
|
+
/**@type { (string | undefined)[] }*/ stringArrWithUndefineds = [
|
|
67
67
|
'hello', 'world' , undefined
|
|
68
68
|
]
|
|
69
69
|
|
|
@@ -117,7 +117,7 @@ Both approaches will allow for proper detection and persisting of such changes.
|
|
|
117
117
|
## 2) Overriding the Default Id-Type
|
|
118
118
|
|
|
119
119
|
```js
|
|
120
|
-
import { Entity } from 'masquerade'
|
|
120
|
+
import { Entity } from 'masquerade-orm'
|
|
121
121
|
|
|
122
122
|
class ClassA extends Entity {
|
|
123
123
|
// to avoid bugs put 'ormClassSettings_' as the first property.
|
|
@@ -131,7 +131,7 @@ The above code lets you override the default id-type that is assigned to all Ent
|
|
|
131
131
|
Setting the `idType` is only possible on a **direct child of Entity**.
|
|
132
132
|
|
|
133
133
|
```ts
|
|
134
|
-
import { Entity } from 'masquerade'
|
|
134
|
+
import { Entity } from 'masquerade-orm'
|
|
135
135
|
|
|
136
136
|
class ClassA extends Entity {
|
|
137
137
|
// properties and constructor...
|
|
@@ -152,7 +152,7 @@ At the moment, this is the only class setting supported, but it may evolve in th
|
|
|
152
152
|
### How to create an `abstract class` when using JSDoc?
|
|
153
153
|
Put the decorator `/**@abstract*/` right above the constructor of the class.
|
|
154
154
|
```js
|
|
155
|
-
import { Entity } from 'masquerade'
|
|
155
|
+
import { Entity } from 'masquerade-orm'
|
|
156
156
|
|
|
157
157
|
class User extends Entity {
|
|
158
158
|
// properties...
|
package/docs/jsdoc-ux-tips.md
CHANGED
|
@@ -1,17 +1,252 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
# JSDoc - UX Tips
|
|
2
|
+
|
|
3
|
+
#### ** Note: The following guide is for Visual Studio Code users **
|
|
4
|
+
|
|
5
|
+
This guide will instruct you on how to adjust your VS Code settings to vastly improve your experience with JSDoc annotation.
|
|
6
|
+
|
|
7
|
+
Here is how your code will look like after applying the settings:
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### 1) Install the [`Inline fold`](https://marketplace.visualstudio.com/items?itemName=moalamri.inline-fold) Extension
|
|
15
|
+
|
|
16
|
+
Either click the link in the title or run the following command in the terminal:
|
|
17
|
+
```bash
|
|
18
|
+
code --install-extension moalamri.inline-fold
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 2) Modify `User Settings (JSON)`
|
|
22
|
+
**First Step**
|
|
23
|
+
- Windows / Linux: Ctrl + Shift + P
|
|
24
|
+
- macOS: Cmd + Shift + P
|
|
25
|
+
|
|
26
|
+
**Second Step**
|
|
27
|
+
|
|
28
|
+
Type `Preferences: Open User Settings (JSON)` and press Enter.
|
|
29
|
+
|
|
30
|
+
**Third Step**
|
|
31
|
+
|
|
32
|
+
Copy the lines below into the JSON and save.
|
|
33
|
+
```JSON
|
|
34
|
+
{
|
|
35
|
+
"inlineFold.regex": "(\\/\\*\\*@\\w+\\s+\\{|(?<=\\/\\*\\*@\\w+\\s+\\{.*)\\}\\s*\\w*\\*\\/)",
|
|
36
|
+
"inlineFold.regexGroup": "1",
|
|
37
|
+
"inlineFold.maskChar": "",
|
|
38
|
+
"inlineFold.after": "",
|
|
39
|
+
"inlineFold.unfoldOnLineSelect": true,
|
|
40
|
+
"inlineFold.unfoldedOpacity": 1
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3) Create Snippet File
|
|
45
|
+
**First Step**
|
|
46
|
+
- Windows / Linux: Ctrl + Shift + P
|
|
47
|
+
- macOS: Cmd + Shift + P
|
|
48
|
+
|
|
49
|
+
**Second Step**
|
|
50
|
+
|
|
51
|
+
Type `Snippets: Configure Snippets` and press Enter.
|
|
52
|
+
|
|
53
|
+
**Third Step**
|
|
54
|
+
|
|
55
|
+
Choose the `New Global Snippets file...` option and press Enter.
|
|
56
|
+
|
|
57
|
+
**Fourth Step**
|
|
58
|
+
|
|
59
|
+
Name you snippet file, for example, `JSDoc_UX`.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
**Fifth Step**
|
|
63
|
+
|
|
64
|
+
Copy the JSON below and save.
|
|
65
|
+
```JSON
|
|
66
|
+
{
|
|
67
|
+
"@type let": {
|
|
68
|
+
"scope": "javascript,typescript",
|
|
69
|
+
"prefix": "let",
|
|
70
|
+
"body": [
|
|
71
|
+
"/**@type {${1}}*/ let $0"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
"@type const": {
|
|
75
|
+
"scope": "javascript,typescript",
|
|
76
|
+
"prefix": "const",
|
|
77
|
+
"body": [
|
|
78
|
+
"/**@type {${1}}*/ const $0"
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
"@type string": {
|
|
82
|
+
"scope": "javascript,typescript",
|
|
83
|
+
"prefix": "string",
|
|
84
|
+
"body": [
|
|
85
|
+
"/**@type {string${1}}*/$0"
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
"@type number": {
|
|
89
|
+
"scope": "javascript,typescript",
|
|
90
|
+
"prefix": "number",
|
|
91
|
+
"body": [
|
|
92
|
+
"/**@type {number${1}}*/$0"
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
"@type boolean": {
|
|
96
|
+
"scope": "javascript,typescript",
|
|
97
|
+
"prefix": "boolean",
|
|
98
|
+
"body": [
|
|
99
|
+
"/**@type {boolean${1}}*/$0"
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
"@type any": {
|
|
103
|
+
"scope": "javascript,typescript",
|
|
104
|
+
"prefix": "any",
|
|
105
|
+
"body": [
|
|
106
|
+
"/**@type {any${1}}*/$0"
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
"@type Map": {
|
|
110
|
+
"scope": "javascript,typescript",
|
|
111
|
+
"prefix": "Map",
|
|
112
|
+
"body": [
|
|
113
|
+
"/**@type {Map<${1}>}*/$0"
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
"@type Function": {
|
|
117
|
+
"scope": "javascript,typescript",
|
|
118
|
+
"prefix": "Function",
|
|
119
|
+
"body": [
|
|
120
|
+
"/**@type {Function${1}}*/$0"
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
"@type": {
|
|
124
|
+
"scope": "javascript,typescript",
|
|
125
|
+
"prefix": "type",
|
|
126
|
+
"body": [
|
|
127
|
+
"/**@type {${1}}*/$0"
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
"@return": {
|
|
131
|
+
"scope": "javascript,typescript",
|
|
132
|
+
"prefix": "return",
|
|
133
|
+
"body": [
|
|
134
|
+
"/**@return {${1}}*/$0"
|
|
135
|
+
]
|
|
136
|
+
},
|
|
137
|
+
"@typedef import": {
|
|
138
|
+
"scope": "javascript,typescript",
|
|
139
|
+
"prefix": "importTypedef",
|
|
140
|
+
"body": [
|
|
141
|
+
"/**@typedef {import('${1}').$2} $3*/$0"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
"@typedef": {
|
|
145
|
+
"scope": "javascript,typescript",
|
|
146
|
+
"prefix": "typedef",
|
|
147
|
+
"body": [
|
|
148
|
+
"/**",
|
|
149
|
+
"* @typedef {Object} ${1:MyObject}",
|
|
150
|
+
"* @property {${2:boolean}} ${3:booleanField}",
|
|
151
|
+
"* @property {${4:object}} ${5:nestedObj}",
|
|
152
|
+
"*/"
|
|
153
|
+
],
|
|
154
|
+
"description": "JSDoc typedef for an object"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
**Note:** You can change the `prefix` fields if you do not like the shortcut names.
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
### 4) Configure the `jsconfig.json` file
|
|
162
|
+
|
|
163
|
+
Add the following lines to your `jsconfig.json` (or `tsconfig.json`) file:
|
|
164
|
+
```JSON
|
|
165
|
+
"allowJs": true,
|
|
166
|
+
"checkJs": true
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
## Using the Shortcuts
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
### Importing Types
|
|
174
|
+
|
|
175
|
+
- **Use `importTypedef`**
|
|
176
|
+
```js
|
|
177
|
+
// importing from a package
|
|
178
|
+
/**@typedef {import('masquerade-orm').OrmConfigObj} OrmConfigObjAlias*/
|
|
179
|
+
// importing from some file
|
|
180
|
+
/**@typedef {import('./path/to/file').YourImportedType} YourImportedTypeAlias*/
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+

|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
### Typing Variables
|
|
187
|
+
- **Use `type` / `string` / `number` / `boolean` (etc)**
|
|
188
|
+
```js
|
|
189
|
+
/**@type {string}*/ someString = '123'
|
|
190
|
+
/**@type {number}*/ someNumber = 567
|
|
191
|
+
```
|
|
192
|
+

|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
### `Object` Type Deinition Template
|
|
196
|
+
- **Use `typedef`**
|
|
197
|
+
```js
|
|
198
|
+
/**
|
|
199
|
+
* @typedef {Object} YourObject
|
|
200
|
+
* @property {string} someString
|
|
201
|
+
* @property {number} someNum
|
|
202
|
+
*/
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+

|
|
206
|
+
|
|
207
|
+
### Defining Classes
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
import { Entity } from 'masquerade-orm'
|
|
211
|
+
/**@typedef {import('masquerade-orm').Unique} Unique*/
|
|
212
|
+
|
|
213
|
+
class User extends Entity {
|
|
214
|
+
/**@type {string | Unique}*/ username
|
|
215
|
+
/**@type {string | Unique}*/ email
|
|
216
|
+
/**@type {string}*/ password
|
|
217
|
+
/**@type {boolean}*/ isBanned = false
|
|
218
|
+
/**@satisfies {UserMetadata}*/ metadata = {
|
|
219
|
+
twoFactorAuth: false,
|
|
220
|
+
createdAt: new Date()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
constructor(
|
|
224
|
+
/**@type {string}*/ username,
|
|
225
|
+
/**@type {string}*/ email,
|
|
226
|
+
/**@type {string}*/ password) {
|
|
227
|
+
super()
|
|
228
|
+
this.username = username
|
|
229
|
+
this.email = email
|
|
230
|
+
this.password = password
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @typedef {Object} UserMetadata
|
|
236
|
+
* @property {boolean} twoFactorAuth
|
|
237
|
+
* @property {Date} createdAt
|
|
238
|
+
*/
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
<h1 align="center">All done!</h1>
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
<br>
|
|
245
|
+
<div align="center">
|
|
246
|
+
<strong>
|
|
247
|
+
© 2026
|
|
248
|
+
<a href="https://github.com/MasqueradeORM">MasqueradeORM </a>
|
|
249
|
+
-
|
|
250
|
+
Released under the MIT License
|
|
251
|
+
</strong>
|
|
17
252
|
</div>
|
|
@@ -9,7 +9,7 @@ We offer a simple way to clean up your database using the `DbManager` class and
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
```js
|
|
12
|
-
import { DbManager } from 'masquerade'
|
|
12
|
+
import { DbManager } from 'masquerade-orm'
|
|
13
13
|
// will drop all unused columns in the database
|
|
14
14
|
await DbManager.dropUnusedColumns()
|
|
15
15
|
// will drop all unused columns in entity_table
|
package/package.json
CHANGED
package/testing/postgres.test.js
CHANGED
|
@@ -3,7 +3,7 @@ import test from 'node:test'
|
|
|
3
3
|
import assert from "node:assert"
|
|
4
4
|
import * as classes from './testing-classes.js'
|
|
5
5
|
import { resetPostgresDb, initORM, createConfigObj } from "./testInit.js"
|
|
6
|
-
import { sql } from '
|
|
6
|
+
import { sql } from '../src/entity/find/where/whereArgsFunctions.js'
|
|
7
7
|
import { generateFamiliesAndHouses } from "./generationFuncs.js"
|
|
8
8
|
import { validateUpdatedAt } from "./miscFunctions.js"
|
|
9
9
|
import { OrmStore } from '../src/misc/ormStore.js'
|
package/testing/sqlite.test.js
CHANGED
|
@@ -3,7 +3,7 @@ import test from 'node:test'
|
|
|
3
3
|
import assert from "node:assert"
|
|
4
4
|
import * as classes from './testing-classes.js'
|
|
5
5
|
import { initORM, createConfigObj } from "./testInit.js"
|
|
6
|
-
import { sql } from '
|
|
6
|
+
import { sql } from '../src/entity/find/where/whereArgsFunctions.js'
|
|
7
7
|
import { generateFamiliesAndHouses } from "./generationFuncs.js"
|
|
8
8
|
import { validateUpdatedAt } from "./miscFunctions.js"
|
|
9
9
|
import { OrmStore } from '../src/misc/ormStore.js'
|
|
@@ -254,4 +254,3 @@ test.after(async () => {
|
|
|
254
254
|
await fs.rm("./test", { force: true })
|
|
255
255
|
console.log('db reset')
|
|
256
256
|
})
|
|
257
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Entity } from '
|
|
1
|
+
import { Entity } from '../index.js'
|
|
2
2
|
import { jsonGenerator } from './miscFunctions.js'
|
|
3
|
-
/**@typedef {import('
|
|
3
|
+
/**@typedef {import('../index.js').integer} integer */
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
export class House extends Entity {
|