@cheetah.js/orm 0.1.106 → 0.1.107
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 +89 -39
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -1
- package/dist/decorators/computed.decorator.d.ts +1 -0
- package/dist/decorators/computed.decorator.js +12 -0
- package/dist/domain/base-entity.d.ts +7 -0
- package/dist/domain/base-entity.js +59 -10
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ export class User {
|
|
|
123
123
|
}
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
For define a index for a multiple properties, add the @Index decorator. You can use it on a property or on the class. It accepts either an array of property names (legacy) or an object with a properties field (recommended):
|
|
126
|
+
For define a index for a multiple properties, add the @Index decorator. You can use it on a property or on the class. It accepts either an array of property names (legacy) or an object with a properties field (recommended):
|
|
127
127
|
|
|
128
128
|
```javascript
|
|
129
129
|
@Entity()
|
|
@@ -134,29 +134,29 @@ export class User {
|
|
|
134
134
|
@Property()
|
|
135
135
|
name: string;
|
|
136
136
|
|
|
137
|
-
// Property-level (compound index)
|
|
138
|
-
@Index({ properties: ['name', 'email'] })
|
|
139
|
-
@Property()
|
|
140
|
-
email: string;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Or, at the class level
|
|
144
|
-
|
|
145
|
-
@Entity()
|
|
146
|
-
@Index<{ User }>({ properties: ['name', 'email'] })
|
|
147
|
-
export class User {
|
|
148
|
-
@PrimaryKey()
|
|
149
|
-
id: number;
|
|
150
|
-
|
|
151
|
-
@Property()
|
|
152
|
-
name: string;
|
|
153
|
-
|
|
154
|
-
@Property()
|
|
155
|
-
email: string;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Backward compatible usage (array):
|
|
159
|
-
// @Index(['name', 'email'])
|
|
137
|
+
// Property-level (compound index)
|
|
138
|
+
@Index({ properties: ['name', 'email'] })
|
|
139
|
+
@Property()
|
|
140
|
+
email: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Or, at the class level
|
|
144
|
+
|
|
145
|
+
@Entity()
|
|
146
|
+
@Index<{ User }>({ properties: ['name', 'email'] })
|
|
147
|
+
export class User {
|
|
148
|
+
@PrimaryKey()
|
|
149
|
+
id: number;
|
|
150
|
+
|
|
151
|
+
@Property()
|
|
152
|
+
name: string;
|
|
153
|
+
|
|
154
|
+
@Property()
|
|
155
|
+
email: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Backward compatible usage (array):
|
|
159
|
+
// @Index(['name', 'email'])
|
|
160
160
|
```
|
|
161
161
|
|
|
162
162
|
#### Property options
|
|
@@ -170,6 +170,56 @@ export class User {
|
|
|
170
170
|
| onUpdate | string | Define the action to be taken for this property when updating the entity in the database |
|
|
171
171
|
| onInsert | string | Defines the action to be taken for this property when inserting the entity in the database |
|
|
172
172
|
|
|
173
|
+
#### Computed Properties
|
|
174
|
+
The `@Computed` decorator allows you to define properties that are included in serialization but NOT persisted to the database. This is useful for derived values, formatted data, or any computation based on existing properties.
|
|
175
|
+
|
|
176
|
+
Computed properties are evaluated when the entity is serialized (e.g., `JSON.stringify()`) and are perfect for transforming or combining existing data.
|
|
177
|
+
|
|
178
|
+
##### Example:
|
|
179
|
+
```javascript
|
|
180
|
+
import { Entity, PrimaryKey, Property, Computed } from '@cheetah.js/orm';
|
|
181
|
+
|
|
182
|
+
@Entity()
|
|
183
|
+
export class Article {
|
|
184
|
+
@PrimaryKey()
|
|
185
|
+
id: number;
|
|
186
|
+
|
|
187
|
+
@Property()
|
|
188
|
+
title: string;
|
|
189
|
+
|
|
190
|
+
@Property()
|
|
191
|
+
body: string;
|
|
192
|
+
|
|
193
|
+
@Computed()
|
|
194
|
+
get excerpt() {
|
|
195
|
+
return this.body?.substring(0, 50) || '';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@Computed()
|
|
199
|
+
get titleUppercase() {
|
|
200
|
+
return this.title?.toUpperCase() || '';
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
When you serialize an article:
|
|
206
|
+
```javascript
|
|
207
|
+
const article = await Article.create({
|
|
208
|
+
title: 'My Article',
|
|
209
|
+
body: 'This is the full body text of the article...'
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
console.log(JSON.stringify(article));
|
|
213
|
+
// Output: {"id":1,"title":"My Article","body":"This is the full body text of the article...","excerpt":"This is the full body text of the article...","titleUppercase":"MY ARTICLE"}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Important Notes:**
|
|
217
|
+
- Computed properties are **NOT** stored in the database
|
|
218
|
+
- They are evaluated during serialization (toJSON)
|
|
219
|
+
- Best used with getter functions
|
|
220
|
+
- Can access other properties and even other computed properties
|
|
221
|
+
- Can return any JSON-serializable type (string, number, object, array, etc.)
|
|
222
|
+
|
|
173
223
|
### [Hooks](#hooks)
|
|
174
224
|
Cheetah ORM supports hooks for entities. The available hooks are: BeforeCreate, AfterCreate, BeforeUpdate, AfterUpdate, BeforeDelete, AfterDelete.
|
|
175
225
|
Hooks is only for modify the entity, not for create, update or delete another entities statements in database.
|
|
@@ -317,21 +367,21 @@ const user = await User.findOne({
|
|
|
317
367
|
| $ne | Not Equal | Matches all values that are not equal to a specified value. |
|
|
318
368
|
| $nin | Not In | Matches none of the values specified in an array. |
|
|
319
369
|
| $and | And | Joins query clauses with a logical AND returns all documents that match the conditions of both clauses. |
|
|
320
|
-
| $or | Or | Joins query clauses with a logical OR returns all documents that match the conditions of either clause. |
|
|
321
|
-
| $not | Not | Inverts the effect of a query expression and returns documents that do not match the query expression. |
|
|
322
|
-
|
|
323
|
-
#### Filter by Date columns
|
|
324
|
-
You can filter using JavaScript `Date` instances and the ORM translates them into precise SQL comparisons:
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
const reinforcement = await User.findOne({
|
|
328
|
-
updatedAt: new Date('2024-06-01T00:00:00.000Z'),
|
|
329
|
-
});
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### [Migrations](#migrations)
|
|
333
|
-
Cheetah ORM is capable of creating and running migrations.
|
|
334
|
-
To do this, you need to install our cli package:
|
|
370
|
+
| $or | Or | Joins query clauses with a logical OR returns all documents that match the conditions of either clause. |
|
|
371
|
+
| $not | Not | Inverts the effect of a query expression and returns documents that do not match the query expression. |
|
|
372
|
+
|
|
373
|
+
#### Filter by Date columns
|
|
374
|
+
You can filter using JavaScript `Date` instances and the ORM translates them into precise SQL comparisons:
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
const reinforcement = await User.findOne({
|
|
378
|
+
updatedAt: new Date('2024-06-01T00:00:00.000Z'),
|
|
379
|
+
});
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### [Migrations](#migrations)
|
|
383
|
+
Cheetah ORM is capable of creating and running migrations.
|
|
384
|
+
To do this, you need to install our cli package:
|
|
335
385
|
|
|
336
386
|
```bash
|
|
337
387
|
bun install @cheetah.js/cli
|
package/dist/constants.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export declare const PROPERTIES = "cheetah:properties";
|
|
|
3
3
|
export declare const PROPERTIES_METADATA = "cheetah:properties:metadata";
|
|
4
4
|
export declare const PROPERTIES_RELATIONS = "cheetah:properties:relations";
|
|
5
5
|
export declare const EVENTS_METADATA = "cheetah:events:metadata";
|
|
6
|
+
export declare const COMPUTED_PROPERTIES = "cheetah:computed:properties";
|
package/dist/constants.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EVENTS_METADATA = exports.PROPERTIES_RELATIONS = exports.PROPERTIES_METADATA = exports.PROPERTIES = exports.ENTITIES = void 0;
|
|
3
|
+
exports.COMPUTED_PROPERTIES = exports.EVENTS_METADATA = exports.PROPERTIES_RELATIONS = exports.PROPERTIES_METADATA = exports.PROPERTIES = exports.ENTITIES = void 0;
|
|
4
4
|
exports.ENTITIES = 'cheetah:entities';
|
|
5
5
|
exports.PROPERTIES = 'cheetah:properties';
|
|
6
6
|
exports.PROPERTIES_METADATA = 'cheetah:properties:metadata';
|
|
7
7
|
exports.PROPERTIES_RELATIONS = 'cheetah:properties:relations';
|
|
8
8
|
exports.EVENTS_METADATA = 'cheetah:events:metadata';
|
|
9
|
+
exports.COMPUTED_PROPERTIES = 'cheetah:computed:properties';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function Computed(): PropertyDecorator;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Computed = Computed;
|
|
4
|
+
const core_1 = require("@cheetah.js/core");
|
|
5
|
+
const constants_1 = require("../constants");
|
|
6
|
+
function Computed() {
|
|
7
|
+
return (target, propertyKey) => {
|
|
8
|
+
const computedProperties = core_1.Metadata.get(constants_1.COMPUTED_PROPERTIES, target.constructor) || [];
|
|
9
|
+
computedProperties.push(propertyKey);
|
|
10
|
+
core_1.Metadata.set(constants_1.COMPUTED_PROPERTIES, computedProperties, target.constructor);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -47,4 +47,11 @@ export declare abstract class BaseEntity {
|
|
|
47
47
|
*/
|
|
48
48
|
isPersisted(): boolean;
|
|
49
49
|
toJSON(): Record<string, any>;
|
|
50
|
+
private serializeWithEntity;
|
|
51
|
+
private serializeWithMetadata;
|
|
52
|
+
private shouldSkipProperty;
|
|
53
|
+
private shouldSkipPropertyBasic;
|
|
54
|
+
private isInternalProperty;
|
|
55
|
+
private getHiddenPropertiesFromMetadata;
|
|
56
|
+
private addComputedProperties;
|
|
50
57
|
}
|
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.BaseEntity = void 0;
|
|
4
4
|
const SqlBuilder_1 = require("../SqlBuilder");
|
|
5
5
|
const entities_1 = require("./entities");
|
|
6
|
+
const core_1 = require("@cheetah.js/core");
|
|
7
|
+
const constants_1 = require("../constants");
|
|
6
8
|
class BaseEntity {
|
|
7
9
|
constructor() {
|
|
8
10
|
this._oldValues = {};
|
|
@@ -121,24 +123,71 @@ class BaseEntity {
|
|
|
121
123
|
return this.$_isPersisted;
|
|
122
124
|
}
|
|
123
125
|
toJSON() {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
const storage = entities_1.EntityStorage.getInstance();
|
|
127
|
+
const entity = storage.get(this.constructor);
|
|
128
|
+
const data = entity
|
|
129
|
+
? this.serializeWithEntity(entity)
|
|
130
|
+
: this.serializeWithMetadata();
|
|
131
|
+
this.addComputedProperties(data);
|
|
132
|
+
return data;
|
|
133
|
+
}
|
|
134
|
+
serializeWithEntity(entity) {
|
|
135
|
+
const data = {};
|
|
136
|
+
const allProperties = new Set(Object.keys(entity.properties));
|
|
137
|
+
const hidePropertiesSet = new Set(entity.hideProperties);
|
|
128
138
|
for (const key in this) {
|
|
129
|
-
|
|
130
|
-
if (key.startsWith('$') || key.startsWith('_')) {
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
if (!allProperties.has(key)) {
|
|
139
|
+
if (this.shouldSkipProperty(key, allProperties, hidePropertiesSet)) {
|
|
134
140
|
continue;
|
|
135
141
|
}
|
|
136
|
-
|
|
142
|
+
data[key] = this[key];
|
|
143
|
+
}
|
|
144
|
+
return data;
|
|
145
|
+
}
|
|
146
|
+
serializeWithMetadata() {
|
|
147
|
+
const data = {};
|
|
148
|
+
const hideProperties = this.getHiddenPropertiesFromMetadata();
|
|
149
|
+
const hidePropertiesSet = new Set(hideProperties);
|
|
150
|
+
for (const key in this) {
|
|
151
|
+
if (this.shouldSkipPropertyBasic(key, hidePropertiesSet)) {
|
|
137
152
|
continue;
|
|
138
153
|
}
|
|
139
154
|
data[key] = this[key];
|
|
140
155
|
}
|
|
141
156
|
return data;
|
|
142
157
|
}
|
|
158
|
+
shouldSkipProperty(key, allProperties, hideProperties) {
|
|
159
|
+
if (this.isInternalProperty(key)) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
if (!allProperties.has(key)) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return hideProperties.has(key);
|
|
166
|
+
}
|
|
167
|
+
shouldSkipPropertyBasic(key, hideProperties) {
|
|
168
|
+
if (this.isInternalProperty(key)) {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
return hideProperties.has(key);
|
|
172
|
+
}
|
|
173
|
+
isInternalProperty(key) {
|
|
174
|
+
return key.startsWith('$') || key.startsWith('_');
|
|
175
|
+
}
|
|
176
|
+
getHiddenPropertiesFromMetadata() {
|
|
177
|
+
const properties = core_1.Metadata.get(constants_1.PROPERTIES_METADATA, this.constructor) || {};
|
|
178
|
+
const hideProperties = [];
|
|
179
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
180
|
+
if (prop.options?.hidden) {
|
|
181
|
+
hideProperties.push(key);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return hideProperties;
|
|
185
|
+
}
|
|
186
|
+
addComputedProperties(data) {
|
|
187
|
+
const computedProperties = core_1.Metadata.get(constants_1.COMPUTED_PROPERTIES, this.constructor) || [];
|
|
188
|
+
for (const key of computedProperties) {
|
|
189
|
+
data[key] = this[key];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
143
192
|
}
|
|
144
193
|
exports.BaseEntity = BaseEntity;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './decorators/one-many.decorator';
|
|
|
5
5
|
export * from './decorators/index.decorator';
|
|
6
6
|
export * from './decorators/event-hook.decorator';
|
|
7
7
|
export * from './decorators/enum.decorator';
|
|
8
|
+
export * from './decorators/computed.decorator';
|
|
8
9
|
export * from './orm';
|
|
9
10
|
export * from './orm.service';
|
|
10
11
|
export * from './domain/base-entity';
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ __exportStar(require("./decorators/one-many.decorator"), exports);
|
|
|
22
22
|
__exportStar(require("./decorators/index.decorator"), exports);
|
|
23
23
|
__exportStar(require("./decorators/event-hook.decorator"), exports);
|
|
24
24
|
__exportStar(require("./decorators/enum.decorator"), exports);
|
|
25
|
+
__exportStar(require("./decorators/computed.decorator"), exports);
|
|
25
26
|
__exportStar(require("./orm"), exports);
|
|
26
27
|
__exportStar(require("./orm.service"), exports);
|
|
27
28
|
__exportStar(require("./domain/base-entity"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cheetah.js/orm",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.107",
|
|
4
4
|
"description": "A simple ORM for Cheetah.js",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"bun",
|
|
56
56
|
"value-object"
|
|
57
57
|
],
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "0c79e3c070683f0a432056d7e57d6d6a6a53b190"
|
|
59
59
|
}
|