objectMetadata.objectMetadataMapItem,
);
- return this.formatResult(
- 'update',
+ return this.formatResult({
+ operation: 'update',
+ objectNameSingular: objectMetadataNameSingular,
+ data: updatedRecord,
+ });
+ }
+
+ async get(request: Request) {
+ const { id: recordId } = parseCorePath(request);
+ const {
+ objectMetadataNameSingular,
+ objectMetadataNamePlural,
+ repository,
+ objectMetadata,
+ objectMetadataItemWithFieldsMaps,
+ } = await this.getRepositoryAndMetadataOrFail(request);
+
+ if (recordId) {
+ return await this.findOne(
+ repository,
+ recordId,
+ objectMetadataNameSingular,
+ );
+ } else {
+ return await this.findMany(
+ request,
+ repository,
+ objectMetadata,
+ objectMetadataNameSingular,
+ objectMetadataNamePlural,
+ objectMetadataItemWithFieldsMaps,
+ );
+ }
+ }
+
+ private async findOne(
+ repository: any,
+ recordId: string,
+ objectMetadataNameSingular: string,
+ ) {
+ const record = await repository.findOne({
+ where: { id: recordId },
+ });
+
+ return this.formatResult({
+ operation: 'findOne',
+ objectNameSingular: objectMetadataNameSingular,
+ data: record,
+ });
+ }
+
+ private async findMany(
+ request: Request,
+ repository: WorkspaceRepository<ObjectLiteral>,
+ objectMetadata: any,
+ objectMetadataNameSingular: string,
+ objectMetadataNamePlural: string,
+ objectMetadataItemWithFieldsMaps:
+ | ObjectMetadataItemWithFieldMaps
+ | undefined,
+ ) {
+ // Get input parameters
+ const inputs = this.getPaginationInputs(request, objectMetadata);
+
+ // Create query builder
+ const qb = repository.createQueryBuilder(objectMetadataNameSingular);
+
+ // Get total count
+ const totalCount = await this.getTotalCount(qb);
+
+ // Apply filters with cursor
+ const { finalQuery } = await this.applyFiltersWithCursor(
+ qb,
objectMetadataNameSingular,
- updatedRecord,
+ objectMetadataItemWithFieldsMaps,
+ inputs,
+ );
+
+ // Get records with pagination
+ const { finalRecords, hasMoreRecords } =
+ await this.getRecordsWithPagination(
+ finalQuery,
+ objectMetadataNameSingular,
+ objectMetadataItemWithFieldsMaps,
+ inputs,
+ );
+
+ // Format and return result
+ return this.formatPaginatedResult(
+ finalRecords,
+ objectMetadataNamePlural,
+ objectMetadataItemWithFieldsMaps,
+ objectMetadata,
+ inputs.isForwardPagination,
+ hasMoreRecords,
+ totalCount,
);
}
- private formatResult<T>(
- operation: 'delete' | 'create' | 'update' | 'find',
- objectNameSingular: string,
- data: T,
+ private getPaginationInputs(request: Request, objectMetadata: any) {
+ const limit = this.limitInputFactory.create(request);
+ const filter = this.filterInputFactory.create(request, objectMetadata);
+ const orderBy = this.orderByInputFactory.create(request, objectMetadata);
+ const endingBefore = this.endingBeforeInputFactory.create(request);
+ const startingAfter = this.startingAfterInputFactory.create(request);
+ const isForwardPagination = !endingBefore;
+
+ return {
+ limit,
+ filter,
+ orderBy,
+ endingBefore,
+ startingAfter,
+ isForwardPagination,
+ };
+ }
+
+ private async applyFiltersWithCursor(
+ qb: SelectQueryBuilder<ObjectLiteral>,
+ objectMetadataNameSingular: string,
+ objectMetadataItemWithFieldsMaps:
+ | ObjectMetadataItemWithFieldMaps
+ | undefined,
+ inputs: {
+ filter: Record<string, FieldValue>;
+ orderBy: any;
+ startingAfter: string | undefined;
+ endingBefore: string | undefined;
+ isForwardPagination: boolean;
+ },
+ ) {
+ const fieldMetadataMapByName =
+ objectMetadataItemWithFieldsMaps?.fieldsByName || {};
+
+ let appliedFilters = inputs.filter;
+
+ // Handle cursor-based filtering
+ if (inputs.startingAfter || inputs.endingBefore) {
+ const cursor = inputs.startingAfter || inputs.endingBefore;
+
+ try {
+ const cursorData = JSON.parse(
+ Buffer.from(cursor ?? '', 'base64').toString(),
+ );
+
+ // We always include ID in the ordering to ensure consistent pagination results
+ // Even if two records have identical values for the user-specified sort fields, their IDs ensures a deterministic order
+ const orderByWithIdCondition = [
+ ...(inputs.orderBy || []),
+ { id: 'ASC' },
+ ];