@loomcore/api 0.0.49 → 0.0.51
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.
|
@@ -3,6 +3,7 @@ import { Application } from 'express';
|
|
|
3
3
|
import { IUser, IUserContext, IEntity, IAuditable } from '@loomcore/common/models';
|
|
4
4
|
import { GenericApiService } from '../services/generic-api.service.js';
|
|
5
5
|
import { ApiController } from '../controllers/api.controller.js';
|
|
6
|
+
import { MultiTenantApiService } from '../services/multi-tenant-api.service.js';
|
|
6
7
|
declare function initialize(database: Db): void;
|
|
7
8
|
declare function createIndexes(db: Db): Promise<void>;
|
|
8
9
|
declare function createMetaOrg(): Promise<void>;
|
|
@@ -59,6 +60,14 @@ export declare class ProductService extends GenericApiService<IProduct> {
|
|
|
59
60
|
export declare class ProductsController extends ApiController<IProduct> {
|
|
60
61
|
constructor(app: Application, db: Db);
|
|
61
62
|
}
|
|
63
|
+
export declare class MultiTenantProductService extends MultiTenantApiService<IProduct> {
|
|
64
|
+
constructor(db: Db);
|
|
65
|
+
protected getAdditionalPipelineStages(): any[];
|
|
66
|
+
transformSingle(single: any): any;
|
|
67
|
+
}
|
|
68
|
+
export declare class MultiTenantProductsController extends ApiController<IProduct> {
|
|
69
|
+
constructor(app: Application, db: Db);
|
|
70
|
+
}
|
|
62
71
|
declare function getTestUser(): Partial<IUser>;
|
|
63
72
|
declare function configureJwtSecret(): void;
|
|
64
73
|
declare function loginWithTestUser(agent: any): Promise<string>;
|
|
@@ -9,6 +9,7 @@ import { AuthService } from '../services/auth.service.js';
|
|
|
9
9
|
import { GenericApiService } from '../services/generic-api.service.js';
|
|
10
10
|
import { ApiController } from '../controllers/api.controller.js';
|
|
11
11
|
import { entityUtils } from '@loomcore/common/utils';
|
|
12
|
+
import { MultiTenantApiService } from '../services/multi-tenant-api.service.js';
|
|
12
13
|
let db;
|
|
13
14
|
let collections = {};
|
|
14
15
|
let deviceIdCookie;
|
|
@@ -242,6 +243,49 @@ export class ProductsController extends ApiController {
|
|
|
242
243
|
super('products', app, productService, 'product', ProductSpec, PublicAggregatedProductSchema);
|
|
243
244
|
}
|
|
244
245
|
}
|
|
246
|
+
export class MultiTenantProductService extends MultiTenantApiService {
|
|
247
|
+
constructor(db) {
|
|
248
|
+
super(db, 'products', 'product', ProductSpec);
|
|
249
|
+
}
|
|
250
|
+
getAdditionalPipelineStages() {
|
|
251
|
+
return [
|
|
252
|
+
{
|
|
253
|
+
$lookup: {
|
|
254
|
+
from: 'categories',
|
|
255
|
+
localField: 'categoryId',
|
|
256
|
+
foreignField: '_id',
|
|
257
|
+
as: 'category'
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
$unwind: {
|
|
262
|
+
path: '$category',
|
|
263
|
+
preserveNullAndEmptyArrays: true
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
];
|
|
267
|
+
}
|
|
268
|
+
transformSingle(single) {
|
|
269
|
+
if (single && single.category) {
|
|
270
|
+
const categoryService = new CategoryService(this.db);
|
|
271
|
+
single.category = categoryService.transformSingle(single.category);
|
|
272
|
+
}
|
|
273
|
+
return super.transformSingle(single);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
export class MultiTenantProductsController extends ApiController {
|
|
277
|
+
constructor(app, db) {
|
|
278
|
+
const productService = new MultiTenantProductService(db);
|
|
279
|
+
const AggregatedProductSchema = Type.Intersect([
|
|
280
|
+
ProductSpec.fullSchema,
|
|
281
|
+
Type.Partial(Type.Object({
|
|
282
|
+
category: CategorySpec.fullSchema
|
|
283
|
+
}))
|
|
284
|
+
]);
|
|
285
|
+
const PublicAggregatedProductSchema = Type.Omit(AggregatedProductSchema, ['internalNumber']);
|
|
286
|
+
super('multi-tenant-products', app, productService, 'product', ProductSpec, PublicAggregatedProductSchema);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
245
289
|
function getTestUser() {
|
|
246
290
|
return testUser;
|
|
247
291
|
}
|
|
@@ -122,25 +122,35 @@ export class GenericApiService {
|
|
|
122
122
|
return pagedResult;
|
|
123
123
|
}
|
|
124
124
|
async getById(userContext, id) {
|
|
125
|
+
console.log(`--- GenericApiService.getById ENTER ---`);
|
|
126
|
+
console.log(`ID received: ${id}`);
|
|
125
127
|
if (!entityUtils.isValidObjectId(id)) {
|
|
126
128
|
throw new BadRequestError('id is not a valid ObjectId');
|
|
127
129
|
}
|
|
128
130
|
const baseQuery = { _id: new ObjectId(id) };
|
|
129
131
|
const query = this.prepareQuery(userContext, baseQuery);
|
|
132
|
+
console.log('Constructed query:', JSON.stringify(query, null, 2));
|
|
130
133
|
let entity = null;
|
|
131
134
|
if (this.getAdditionalPipelineStages().length > 0) {
|
|
135
|
+
console.log('Branch: Executing with aggregation pipeline.');
|
|
132
136
|
const pipeline = [
|
|
133
137
|
{ $match: query },
|
|
134
138
|
...this.getAdditionalPipelineStages()
|
|
135
139
|
];
|
|
140
|
+
console.log('Aggregation Pipeline:', JSON.stringify(pipeline, null, 2));
|
|
136
141
|
entity = await this.collection.aggregate(pipeline).next();
|
|
137
142
|
}
|
|
138
143
|
else {
|
|
144
|
+
console.log('Branch: Executing with findOne.');
|
|
139
145
|
entity = await this.collection.findOne(query);
|
|
140
146
|
}
|
|
147
|
+
console.log('IMMEDIATE DB RESULT (entity):', JSON.stringify(entity, null, 2));
|
|
141
148
|
if (!entity) {
|
|
149
|
+
console.log('Entity not found, throwing IdNotFoundError.');
|
|
142
150
|
throw new IdNotFoundError();
|
|
143
151
|
}
|
|
152
|
+
console.log('Entity before transformSingle:', JSON.stringify(entity, null, 2));
|
|
153
|
+
console.log(`--- GenericApiService.getById EXIT ---`);
|
|
144
154
|
return this.transformSingle(entity);
|
|
145
155
|
}
|
|
146
156
|
async getCount(userContext) {
|
|
@@ -361,12 +371,14 @@ export class GenericApiService {
|
|
|
361
371
|
return list.map(item => this.transformSingle(item));
|
|
362
372
|
}
|
|
363
373
|
transformSingle(single) {
|
|
374
|
+
console.log('Starting base class transformSingle, entity:', JSON.stringify(single, null, 2));
|
|
364
375
|
if (!single)
|
|
365
376
|
return single;
|
|
366
377
|
if (!this.modelSpec?.fullSchema) {
|
|
367
378
|
throw new ServerError(`Cannot transform entity: No model specification with schema provided for ${this.pluralResourceName}`);
|
|
368
379
|
}
|
|
369
380
|
const transformedEntity = dbUtils.convertObjectIdsToStrings(single, this.modelSpec.fullSchema);
|
|
381
|
+
console.log('Leaving base class transformSingle, transformedEntity:', JSON.stringify(transformedEntity, null, 2));
|
|
370
382
|
return transformedEntity;
|
|
371
383
|
}
|
|
372
384
|
stripSenderProvidedSystemProperties(userContext, doc, allowId = false) {
|