@rws-framework/db 3.10.1 → 3.11.1

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/dist/index.d.ts CHANGED
@@ -3,10 +3,10 @@ import { RWSModel, OpModelType } from "./models/_model";
3
3
  import { InverseRelation, Relation, TrackType, IdType, InverseTimeSeries, ITrackerMetaOpts, ITrackerOpts } from './decorators';
4
4
  import { DbHelper } from './helper/DbHelper';
5
5
  import { FieldsHelper } from './helper/FieldsHelper';
6
- import type { FindByType } from './types/FindParams';
6
+ import type { FindByType, OrderByType, OrderByField, OrderByArray, SortDirection } from './types/FindParams';
7
7
  import type { ITimeSeries } from './types/ITimeSeries';
8
8
  import type { IDbConfigHandler, IDbConfigParams } from './types/DbConfigHandler';
9
9
  import type { IRWSModel } from './types/IRWSModel';
10
10
  import { RWSCollection, IRWSCollectionMeta, IRWSCollectionOpts } from "./decorators/RWSCollection";
11
- export type { IRWSCollectionMeta, IRWSCollectionOpts, IRWSModel, ITrackerMetaOpts, ITrackerOpts, OpModelType, IDbConfigHandler, IDbConfigParams, ITimeSeries, };
11
+ export type { IRWSCollectionMeta, IRWSCollectionOpts, IRWSModel, ITrackerMetaOpts, ITrackerOpts, OpModelType, IDbConfigHandler, IDbConfigParams, ITimeSeries, OrderByType, OrderByField, OrderByArray, SortDirection };
12
12
  export { RWSModel, RWSCollection, DBService, FindByType, InverseRelation, Relation, TrackType, InverseTimeSeries, IdType, DbHelper, FieldsHelper };
@@ -140,18 +140,38 @@ class RWSModel {
140
140
  const data = {};
141
141
  const timeSeriesIds = TimeSeriesUtils_1.TimeSeriesUtils.getTimeSeriesModelFields(this);
142
142
  const timeSeriesHydrationFields = [];
143
+ // Get relation metadata to determine how to handle each relation
144
+ const classFields = FieldsHelper_1.FieldsHelper.getAllClassFields(this.constructor);
145
+ const relOneData = await this.getRelationOneMeta(classFields);
143
146
  for (const key in this) {
144
147
  if (await this.hasRelation(key)) {
145
- if (this[key] === null) {
146
- // For null relations, use disconnect or set to null
147
- data[key] = {
148
- disconnect: true
149
- };
150
- }
151
- else {
152
- data[key] = this.bindRelation(key, this[key]);
148
+ const relationMeta = relOneData[key];
149
+ if (relationMeta) {
150
+ // Use connect on relations that are either:
151
+ // 1. Required (required: true)
152
+ // 2. Have explicitly set cascade options (metaOpts.cascade)
153
+ const hasExplicitCascade = relationMeta.cascade && Object.keys(relationMeta.cascade).length > 0;
154
+ const shouldUseConnect = relationMeta.required || hasExplicitCascade;
155
+ if (shouldUseConnect) {
156
+ // Relations with required=true or explicit cascade → use connect
157
+ if (this[key] === null) {
158
+ data[key] = { disconnect: true };
159
+ }
160
+ else if (this[key] && this[key].id) {
161
+ data[key] = { connect: { id: this[key].id } };
162
+ }
163
+ }
164
+ else {
165
+ // Simple optional relations → use foreign key field directly
166
+ const foreignKeyField = relationMeta.hydrationField;
167
+ if (this[key] === null) {
168
+ data[foreignKeyField] = null;
169
+ }
170
+ else if (this[key] && this[key].id) {
171
+ data[foreignKeyField] = this[key].id;
172
+ }
173
+ }
153
174
  }
154
- // Don't try to set the foreign key directly anymore
155
175
  continue;
156
176
  }
157
177
  if (!(await this.isDbVariable(key))) {
@@ -12,6 +12,10 @@ export type RelOneMetaType<T extends IRWSModel> = {
12
12
  model: OpModelType<T>;
13
13
  hydrationField: string;
14
14
  foreignKey: string;
15
+ cascade?: {
16
+ onDelete?: string;
17
+ onUpdate?: string;
18
+ };
15
19
  };
16
20
  };
17
21
  export type RelManyMetaType<T extends IRWSModel> = {
@@ -19,7 +19,8 @@ class RelationUtils {
19
19
  required: resolvedMetadata.required,
20
20
  model: resolvedMetadata.relatedTo,
21
21
  hydrationField: resolvedMetadata.relationField,
22
- foreignKey: resolvedMetadata.relatedToField
22
+ foreignKey: resolvedMetadata.relatedToField,
23
+ cascade: resolvedMetadata.cascade
23
24
  };
24
25
  }
25
26
  }
@@ -3,7 +3,7 @@ import { Collection, Db, MongoClient } from 'mongodb';
3
3
  import { ITimeSeries } from '../types/ITimeSeries';
4
4
  import { IModel } from '../models/interfaces/IModel';
5
5
  import { IDbConfigHandler } from '../types/DbConfigHandler';
6
- import { IPaginationParams } from '../types/FindParams';
6
+ import { IPaginationParams, OrderByType } from '../types/FindParams';
7
7
  import { OpModelType } from '../models/interfaces/OpModelType';
8
8
  interface IDBClientCreate {
9
9
  dbUrl?: string;
@@ -24,16 +24,13 @@ declare class DBService {
24
24
  watchCollection(collectionName: string, preRun: () => void): Promise<any>;
25
25
  insert(data: any, collection: string, isTimeSeries?: boolean): Promise<any>;
26
26
  update(data: any, collection: string, pk: string | string[]): Promise<IModel>;
27
- findOneBy(collection: string, conditions: any, fields?: string[] | null, ordering?: {
28
- [fieldName: string]: string;
29
- }): Promise<IModel | null>;
27
+ findOneBy(collection: string, conditions: any, fields?: string[] | null, ordering?: OrderByType): Promise<IModel | null>;
30
28
  delete(collection: string, conditions: any): Promise<void>;
31
- findBy(collection: string, conditions: any, fields?: string[] | null, ordering?: {
32
- [fieldName: string]: string;
33
- }, pagination?: IPaginationParams): Promise<IModel[]>;
29
+ findBy(collection: string, conditions: any, fields?: string[] | null, ordering?: OrderByType, pagination?: IPaginationParams): Promise<IModel[]>;
34
30
  collectionExists(collection_name: string): Promise<boolean>;
35
31
  createTimeSeriesCollection(collection_name: string): Promise<Collection<ITimeSeries>>;
36
32
  private getCollectionHandler;
33
+ private convertOrderingToPrismaFormat;
37
34
  private setOpts;
38
35
  count<T = any>(opModel: OpModelType<T>, where?: {
39
36
  [k: string]: any;
@@ -135,7 +135,7 @@ class DBService {
135
135
  });
136
136
  }
137
137
  if (ordering) {
138
- params.orderBy = ordering;
138
+ params.orderBy = this.convertOrderingToPrismaFormat(ordering);
139
139
  }
140
140
  const retData = await this.getCollectionHandler(collection).findFirst(params);
141
141
  return retData;
@@ -153,7 +153,7 @@ class DBService {
153
153
  });
154
154
  }
155
155
  if (ordering) {
156
- params.orderBy = ordering;
156
+ params.orderBy = this.convertOrderingToPrismaFormat(ordering);
157
157
  }
158
158
  if (pagination) {
159
159
  const perPage = pagination.per_page || 50;
@@ -202,6 +202,17 @@ class DBService {
202
202
  }
203
203
  return this.client[collection];
204
204
  }
205
+ convertOrderingToPrismaFormat(ordering) {
206
+ if (!ordering) {
207
+ return null;
208
+ }
209
+ // If it's already an array, return as is (but handle null values for booleans)
210
+ if (Array.isArray(ordering)) {
211
+ return ordering;
212
+ }
213
+ // If it's a single object, convert to array format
214
+ return [ordering];
215
+ }
205
216
  setOpts(opts = null) {
206
217
  this.opts = opts;
207
218
  return this;
@@ -1,8 +1,12 @@
1
+ export type SortDirection = 'asc' | 'desc';
2
+ export type OrderByField = {
3
+ [fieldName: string]: SortDirection;
4
+ };
5
+ export type OrderByArray = OrderByField[];
6
+ export type OrderByType = OrderByField | OrderByArray;
1
7
  export type FindByType = {
2
8
  conditions?: any;
3
- ordering?: {
4
- [fieldName: string]: string;
5
- };
9
+ ordering?: OrderByType;
6
10
  fields?: string[];
7
11
  allowRelations?: boolean;
8
12
  fullData?: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rws-framework/db",
3
3
  "private": false,
4
- "version": "3.10.1",
4
+ "version": "3.11.1",
5
5
  "description": "",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  import { DbHelper } from './helper/DbHelper';
15
15
  import { FieldsHelper } from './helper/FieldsHelper';
16
16
 
17
- import type { FindByType } from './types/FindParams';
17
+ import type { FindByType, OrderByType, OrderByField, OrderByArray, SortDirection } from './types/FindParams';
18
18
  import type { ITimeSeries } from './types/ITimeSeries';
19
19
  import type { IDbConfigHandler, IDbConfigParams } from './types/DbConfigHandler';
20
20
  import type { IRWSModel } from './types/IRWSModel';
@@ -29,6 +29,10 @@ export type {
29
29
  IDbConfigHandler,
30
30
  IDbConfigParams,
31
31
  ITimeSeries,
32
+ OrderByType,
33
+ OrderByField,
34
+ OrderByArray,
35
+ SortDirection
32
36
  }
33
37
 
34
38
  export {
@@ -37,7 +41,7 @@ export {
37
41
 
38
42
  DBService,
39
43
 
40
- FindByType,
44
+ FindByType,
41
45
  // TimeSeriesModel,
42
46
 
43
47
  InverseRelation, Relation, TrackType, InverseTimeSeries, IdType,
@@ -179,19 +179,40 @@ class RWSModel<T> implements IModel {
179
179
  const data: any = {};
180
180
  const timeSeriesIds = TimeSeriesUtils.getTimeSeriesModelFields(this);
181
181
  const timeSeriesHydrationFields: string[] = [];
182
+
183
+ // Get relation metadata to determine how to handle each relation
184
+ const classFields = FieldsHelper.getAllClassFields(this.constructor);
185
+ const relOneData = await this.getRelationOneMeta(classFields);
182
186
 
183
187
  for (const key in (this as any)) {
184
- if (await this.hasRelation(key)) {
185
- if (this[key] === null) {
186
- // For null relations, use disconnect or set to null
187
- data[key] = {
188
- disconnect: true
189
- };
190
- } else {
191
- data[key] = this.bindRelation(key, this[key]);
188
+ if (await this.hasRelation(key)) {
189
+ const relationMeta = relOneData[key];
190
+
191
+ if (relationMeta) {
192
+ // Use connect on relations that are either:
193
+ // 1. Required (required: true)
194
+ // 2. Have explicitly set cascade options (metaOpts.cascade)
195
+ const hasExplicitCascade = relationMeta.cascade && Object.keys(relationMeta.cascade).length > 0;
196
+ const shouldUseConnect = relationMeta.required || hasExplicitCascade;
197
+
198
+ if (shouldUseConnect) {
199
+ // Relations with required=true or explicit cascade → use connect
200
+ if (this[key] === null) {
201
+ data[key] = { disconnect: true };
202
+ } else if (this[key] && this[key].id) {
203
+ data[key] = { connect: { id: this[key].id } };
204
+ }
205
+ } else {
206
+ // Simple optional relations → use foreign key field directly
207
+ const foreignKeyField = relationMeta.hydrationField;
208
+ if (this[key] === null) {
209
+ data[foreignKeyField] = null;
210
+ } else if (this[key] && this[key].id) {
211
+ data[foreignKeyField] = this[key].id;
212
+ }
213
+ }
192
214
  }
193
215
 
194
- // Don't try to set the foreign key directly anymore
195
216
  continue;
196
217
  }
197
218
 
@@ -12,7 +12,11 @@ export type RelOneMetaType<T extends IRWSModel> = {
12
12
  key?: string,
13
13
  model: OpModelType<T>,
14
14
  hydrationField: string,
15
- foreignKey: string
15
+ foreignKey: string,
16
+ cascade?: {
17
+ onDelete?: string,
18
+ onUpdate?: string
19
+ }
16
20
  }
17
21
  };
18
22
 
@@ -5,7 +5,7 @@ import { TimeSeriesUtils } from "./TimeSeriesUtils";
5
5
  import { RelationUtils } from "./RelationUtils";
6
6
  import { OpModelType } from "..";
7
7
  import { ModelUtils } from "./ModelUtils";
8
- import { FindByType, IPaginationParams } from "../../types/FindParams";
8
+ import { FindByType, IPaginationParams, OrderByType } from "../../types/FindParams";
9
9
 
10
10
  export class FindUtils {
11
11
  public static async findOneBy<T extends RWSModel<T>>(
@@ -23,7 +23,8 @@ export class RelationUtils {
23
23
  required: resolvedMetadata.required,
24
24
  model: resolvedMetadata.relatedTo,
25
25
  hydrationField: resolvedMetadata.relationField,
26
- foreignKey: resolvedMetadata.relatedToField
26
+ foreignKey: resolvedMetadata.relatedToField,
27
+ cascade: resolvedMetadata.cascade
27
28
  };
28
29
  }
29
30
  }
@@ -4,7 +4,7 @@ import {ITimeSeries} from '../types/ITimeSeries';
4
4
  import { IModel } from '../models/interfaces/IModel';
5
5
  import chalk from 'chalk';
6
6
  import { IDbConfigHandler } from '../types/DbConfigHandler';
7
- import { IPaginationParams } from '../types/FindParams';
7
+ import { IPaginationParams, OrderByType, OrderByField, OrderByArray } from '../types/FindParams';
8
8
  import { OpModelType } from '../models/interfaces/OpModelType';
9
9
 
10
10
  interface IDBClientCreate {
@@ -172,7 +172,7 @@ class DBService {
172
172
  }
173
173
 
174
174
 
175
- async findOneBy(collection: string, conditions: any, fields: string[] | null = null, ordering: { [fieldName: string]: string } = null): Promise<IModel|null>
175
+ async findOneBy(collection: string, conditions: any, fields: string[] | null = null, ordering: OrderByType = null): Promise<IModel|null>
176
176
  {
177
177
  const params: any = { where: conditions };
178
178
 
@@ -184,7 +184,7 @@ class DBService {
184
184
  }
185
185
 
186
186
  if(ordering){
187
- params.orderBy = ordering;
187
+ params.orderBy = this.convertOrderingToPrismaFormat(ordering);
188
188
  }
189
189
 
190
190
  const retData = await this.getCollectionHandler(collection).findFirst(params);
@@ -202,7 +202,7 @@ class DBService {
202
202
  collection: string,
203
203
  conditions: any,
204
204
  fields: string[] | null = null,
205
- ordering: { [fieldName: string]: string } = null,
205
+ ordering: OrderByType = null,
206
206
  pagination: IPaginationParams = null): Promise<IModel[]>
207
207
  {
208
208
  const params: any ={ where: conditions };
@@ -215,8 +215,8 @@ class DBService {
215
215
  }
216
216
 
217
217
  if(ordering){
218
- params.orderBy = ordering;
219
- }
218
+ params.orderBy = this.convertOrderingToPrismaFormat(ordering);
219
+ }
220
220
 
221
221
  if(pagination){
222
222
  const perPage = pagination.per_page || 50;
@@ -283,6 +283,20 @@ class DBService {
283
283
  return (this.client[collection as keyof PrismaClient] as any);
284
284
  }
285
285
 
286
+ private convertOrderingToPrismaFormat(ordering: OrderByType): any {
287
+ if (!ordering) {
288
+ return null;
289
+ }
290
+
291
+ // If it's already an array, return as is (but handle null values for booleans)
292
+ if (Array.isArray(ordering)) {
293
+ return ordering;
294
+ }
295
+
296
+ // If it's a single object, convert to array format
297
+ return [ordering];
298
+ }
299
+
286
300
  private setOpts(opts: IDBClientCreate = null): this
287
301
  {
288
302
  this.opts = opts;
@@ -1,6 +1,16 @@
1
+ export type SortDirection = 'asc' | 'desc';
2
+
3
+ export type OrderByField = {
4
+ [fieldName: string]: SortDirection;
5
+ };
6
+
7
+ export type OrderByArray = OrderByField[];
8
+
9
+ export type OrderByType = OrderByField | OrderByArray;
10
+
1
11
  export type FindByType = {
2
12
  conditions?: any
3
- ordering?: { [fieldName: string]: string }
13
+ ordering?: OrderByType
4
14
  fields?: string[]
5
15
  allowRelations?: boolean
6
16
  fullData?: boolean