@eleven-am/nestjs-graphql-crud
Version:
nestjs-graphql-crud is a library that aims to reduce the boilerplate code needed to create a GraphQL CRUD API.
234 lines • 11 kB
JavaScript
"use strict";
/**
* @module createBaseCrudService
* @description Creates a service class that implements CRUD operations using a data provider
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createBaseCrudService = createBaseCrudService;
const common_1 = require("@nestjs/common");
const internalTypes_1 = require("./internalTypes");
const decorators_1 = require("./decorators");
const graphql_subscriptions_1 = require("graphql-subscriptions");
const core_1 = require("@nestjs/core");
/**
* Creates a service class with standard CRUD operations for a specific model
*
* @template Item - The entity type this service will manage
* @template CreateInput - The input type for create operations
* @template UpdateInput - The input type for update operations
* @template UpdateManyInput - The input type for update many operations
* @template WhereInput - The input type for query filters
* @template Target - The related entity type for one-to-many relations
* @template TargetWhereInput - The input type for query filters for the related entity
* @template TResolver - The type of the resolver class
*
* @param {string} modelName - The name of the model
* @param {symbol} dataProviderToken - Symbol for the data provider token
* @param {symbol} fieldSelectionToken - Symbol for the field selection provider token
* @returns {Type} A dynamically generated service class with CRUD operations
*/
function createBaseCrudService(modelName, dataProviderToken, fieldSelectionToken) {
let BaseCrudService = class BaseCrudService {
constructor(moduleRef, pubSub, dataProvider, fieldSelectionProvider) {
this.moduleRef = moduleRef;
this.pubSub = pubSub;
this.dataProvider = dataProvider;
this.fieldSelectionProvider = fieldSelectionProvider;
}
/**
* Create a new entity
*
* @param {CreateInput} data - The data to create the entity with
* @param {any} select - Fields to select in the result
* @returns {Promise<Item>} The newly created entity
*/
async create(data, select) {
const res = await this.dataProvider.create(modelName, data, select);
await this.publish(internalTypes_1.CrudAction.CREATE, res);
return res;
}
/**
* Delete an entity by ID
*
* @param {any} ability - The user's ability for authorization
* @param {string} whereId - The ID of the entity to delete
* @param {any} select - Fields to select in the result
* @returns {Promise<Item>} The deleted entity
*/
async delete(ability, whereId, select) {
const res = await this.dataProvider.delete(modelName, ability, whereId, select);
await this.publish(internalTypes_1.CrudAction.DELETE, res);
return res;
}
/**
* Delete multiple entities matching criteria
*
* @param {any} ability - The user's ability for authorization
* @param {WhereInput} where - Filter criteria for entities to delete
* @param {any} select - Fields to select in the result
* @returns {Promise<Item[]>} Array of deleted entities
*/
async deleteMany(ability, where, select) {
const gotDeleted = await this.dataProvider.findMany(modelName, ability, { where }, select);
await this.dataProvider.deleteMany(modelName, ability, where, select);
await this.publish(internalTypes_1.CrudAction.DELETE_MANY, gotDeleted);
return gotDeleted;
}
/**
* Find multiple entities matching criteria
* Now supports both custom FindManyArgs and default FindManyContract
*
* @param {any} ability - The user's ability for authorization
* @param {any} args - Filter and pagination criteria (can be custom or default format)
* @param {any} select - Fields to select in the result
* @returns {Promise<Item[]>} Array of matched entities
*/
async findMany(ability, args, select) {
// Normalize args to handle both custom FindManyArgs and default FindManyContract
let normalizedArgs;
if (args.where !== undefined || args.pagination !== undefined) {
// Default FindManyContract format { where?: WhereInput, pagination?: PaginationContract }
normalizedArgs = {
where: args.where || {},
pagination: args.pagination,
orderBy: undefined // Default doesn't support orderBy
};
}
else {
// Custom FindManyArgs format (like prisma-nest-graphql generates)
// Extract fields directly from the args object
normalizedArgs = {
where: args.where || {},
pagination: {
take: args.take,
skip: args.skip
},
orderBy: args.orderBy,
cursor: args.cursor,
distinct: args.distinct
};
}
return this.dataProvider.findMany(modelName, ability, normalizedArgs, select);
}
/**
* Find a single entity by criteria
*
* @param {any} ability - The user's ability for authorization
* @param {WhereInput} where - Filter criteria
* @param {any} select - Fields to select in the result
* @returns {Promise<Item | null>} The found entity or null
*/
async findOne(ability, where, select) {
return this.dataProvider.findOne(modelName, ability, where, select);
}
/**
* Update a single entity by ID
*
* @param {any} ability - The user's ability for authorization
* @param {UpdateInput} data - The data to update
* @param {string} whereId - The ID of the entity to update
* @param {any} select - Fields to select in the result
* @returns {Promise<Item>} The updated entity
*/
async update(ability, data, whereId, select) {
const res = await this.dataProvider.update(modelName, ability, data, whereId, select);
await this.publish(internalTypes_1.CrudAction.UPDATE, res);
return res;
}
/**
* Update multiple entities matching criteria
*
* @param {any} ability - The user's ability for authorization
* @param {UpdateManyInput} data - The data to update
* @param {WhereInput} where - Filter criteria for entities to update
* @param {any} select - Fields to select in the result
* @returns {Promise<Item[]>} Array of updated entities
*/
async updateMany(ability, data, where, select) {
const gotUpdated = await this.dataProvider.findMany(modelName, ability, { where }, select);
await this.dataProvider.updateMany(modelName, ability, data, where, select);
await this.publish(internalTypes_1.CrudAction.UPDATE_MANY, gotUpdated);
return gotUpdated;
}
/**
* Resolve a one-to-one relation
*
* @param {any} ability - The user's ability for authorization
* @param {string} targetModel - The name of the target model
* @param {string} itemId - The ID of the related item
* @param {any} select - Fields to select in the result
* @returns {Promise<unknown>} The related entity or null
*/
resolveOneToOne(ability, targetModel, itemId, select) {
return this.dataProvider.findOne(targetModel, ability, { id: itemId }, select);
}
/**
* Resolve a one-to-many relation
*
* @param {any} ability - The user's ability for authorization
* @param {string} targetModel - The name of the target model
* @param {string} foreignKey - The foreign key field name
* @param {string} itemId - The ID of the related item
* @param {any} select - Fields to select in the result
* @param {any} [where] - Optional filter criteria for the related entities
*/
resolveOneToMany(ability, targetModel, foreignKey, itemId, select, where) {
return this.dataProvider.findMany(targetModel, ability, {
where: {
...(where?.where || {}),
[foreignKey]: itemId
},
pagination: where?.pagination
}, select);
}
/**
* Get the factory for a specific resolver
*
* @param {Type<TResolver>} constructor - The constructor of the resolver
*/
getFactory(constructor) {
return this.moduleRef.get(constructor, { strict: false });
}
/**
* Publish changes to subscribers
*
* @private
* @param {CrudAction} action - The type of action that occurred
* @param {any} data - The data to publish
* @returns {Promise<void>}
*/
async publish(action, data) {
const arrayData = Array.isArray(data) ? data : [data];
await this.pubSub.publish(modelName, {
action,
data: arrayData,
});
}
};
BaseCrudService = __decorate([
(0, common_1.Injectable)(),
__param(1, (0, decorators_1.CurrentPubSub)()),
__param(2, (0, common_1.Inject)(dataProviderToken)),
__param(3, (0, common_1.Inject)(fieldSelectionToken)),
__metadata("design:paramtypes", [core_1.ModuleRef,
graphql_subscriptions_1.PubSub, Object, Object])
], BaseCrudService);
Object.defineProperty(BaseCrudService, 'name', {
value: `${(0, decorators_1.firstLetterUppercase)(modelName)}Service`,
writable: false,
});
return BaseCrudService;
}
//# sourceMappingURL=createBaseCrudService.js.map