AsyncCollection Usage Examples¶
Real-world examples of using AsyncCollection with different data sources and patterns.
Table of Contents¶
- Basic In-Memory Example
- Prisma ORM Integration
- TypeORM Integration
- Sequelize Integration
- Mongoose Integration
- REST API Wrapper
- GraphQL Query Builder
- Redis Cache Layer
- Custom Validators
- Complex Query Chains
- Error Handling Patterns
- Performance Optimization
Basic In-Memory Example¶
Simple executor for filtering in-memory data:
import AsyncCollection from "@arcaelas/collection/async";
interface User {
id: number;
name: string;
email: string;
age: number;
status: 'active' | 'inactive';
}
const data: User[] = [
{ id: 1, name: "Alice", email: "alice@example.com", age: 25, status: "active" },
{ id: 2, name: "Bob", email: "bob@example.com", age: 30, status: "inactive" },
{ id: 3, name: "Charlie", email: "charlie@example.com", age: 35, status: "active" }
];
const users = new AsyncCollection<User>(async ({ operations }) => {
let results = [...data];
operations.forEach(([method, ...args]) => {
if (method === 'where') {
const [key, operator, value] = args.length === 3
? args
: [args[0], '=', args[1]];
results = results.filter(item => {
const itemValue = item[key as keyof User];
switch (operator) {
case '=': return itemValue === value;
case '!=': return itemValue !== value;
case '>': return itemValue > value;
case '<': return itemValue < value;
case '>=': return itemValue >= value;
case '<=': return itemValue <= value;
default: return true;
}
});
}
if (method === 'sort') {
const [key, direction = 'asc'] = args;
results.sort((a, b) => {
const aVal = a[key as keyof User];
const bVal = b[key as keyof User];
const comparison = aVal > bVal ? 1 : aVal < bVal ? -1 : 0;
return direction === 'desc' ? -comparison : comparison;
});
}
if (method === 'first') {
results = results.length > 0 ? [results[0]] : [];
}
if (method === 'slice') {
const [start, end] = args;
results = results.slice(start, end);
}
});
return results;
});
// Usage
const activeUsers = await users.where('status', 'active');
// [{ id: 1, ... }, { id: 3, ... }]
const firstAdult = await users.where('age', '>=', 25).first();
// { id: 1, name: "Alice", ... }
const sorted = await users.sort('age', 'desc');
// [{ id: 3, ... }, { id: 2, ... }, { id: 1, ... }]
Prisma ORM Integration¶
Complete Prisma integration with advanced query building:
import AsyncCollection from "@arcaelas/collection/async";
import { PrismaClient, User, Prisma } from "@prisma/client";
const prisma = new PrismaClient();
const users = new AsyncCollection<User>(async ({ operations, metadata }) => {
let where: Prisma.UserWhereInput = {};
let orderBy: Prisma.UserOrderByWithRelationInput | undefined;
let take: number | undefined;
let skip: number | undefined;
let select: Prisma.UserSelect | undefined;
console.log(`Building Prisma query with ${metadata.operation_count} operations`);
operations.forEach(([method, ...args]) => {
if (method === 'where') {
const [key, operator, value] = args.length === 3
? args
: [args[0], '=', args[1]];
const condition = buildWhereCondition(key, operator, value);
where = { ...where, ...condition };
}
if (method === 'whereNot') {
const [key, operator, value] = args.length === 3
? args
: [args[0], '=', args[1]];
const condition = buildWhereCondition(key, operator, value);
where = { ...where, NOT: condition };
}
if (method === 'sort') {
const [key, direction = 'asc'] = args;
orderBy = { [key]: direction };
}
if (method === 'slice') {
const [start, end] = args;
skip = start;
take = end ? end - start : undefined;
}
if (method === 'paginate') {
const [page = 1, perPage = 20] = args;
skip = (page - 1) * perPage;
take = perPage;
}
if (method === 'forget') {
// Build select excluding specified fields
select = buildSelectExcluding(args);
}
});
// Check for terminal operations
const lastOp = operations[operations.length - 1];
if (lastOp && lastOp[0] === 'first') {
const result = await prisma.user.findFirst({
where,
orderBy,
select,
});
return result ? [result] : [];
}
if (lastOp && lastOp[0] === 'last') {
const results = await prisma.user.findMany({
where,
orderBy: orderBy ? { [Object.keys(orderBy)[0]]: 'desc' } : undefined,
select,
take: 1,
});
return results;
}
return await prisma.user.findMany({
where,
orderBy,
select,
take,
skip,
});
});
function buildWhereCondition(
key: string,
operator: string,
value: any
): Prisma.UserWhereInput {
switch (operator) {
case '=':
return { [key]: value };
case '!=':
return { [key]: { not: value } };
case '>':
return { [key]: { gt: value } };
case '<':
return { [key]: { lt: value } };
case '>=':
return { [key]: { gte: value } };
case '<=':
return { [key]: { lte: value } };
case 'in':
return { [key]: { in: value } };
case 'includes':
return { [key]: { contains: value } };
default:
return { [key]: value };
}
}
function buildSelectExcluding(excludeKeys: string[]): Prisma.UserSelect {
// Get all User fields and exclude specified ones
const allFields = ['id', 'name', 'email', 'password', 'createdAt', 'updatedAt'];
const select: any = {};
allFields.forEach(field => {
if (!excludeKeys.includes(field)) {
select[field] = true;
}
});
return select;
}
// Usage examples
const activeVerified = await users
.where('status', 'active')
.where('verified', true)
.where('age', '>=', 18)
.sort('createdAt', 'desc')
.slice(0, 10);
const firstUser = await users
.where('email', 'includes', '@example.com')
.first();
const page2 = await users
.where('status', 'active')
.paginate(2, 50);
const withoutPassword = await users
.forget('password', 'token')
.where('active', true);
TypeORM Integration¶
Building TypeORM QueryBuilder from operations:
import AsyncCollection from "@arcaelas/collection/async";
import { getRepository, SelectQueryBuilder } from "typeorm";
import { User } from "./entities/User";
const users = new AsyncCollection<User>(async ({ operations }) => {
const qb = getRepository(User).createQueryBuilder('user');
let paramIndex = 0;
operations.forEach(([method, ...args]) => {
if (method === 'where') {
const [key, operator, value] = args.length === 3
? args
: [args[0], '=', args[1]];
const paramKey = `param${paramIndex++}`;
const column = `user.${key}`;
switch (operator) {
case '=':
qb.andWhere(`${column} = :${paramKey}`, { [paramKey]: value });
break;
case '!=':
qb.andWhere(`${column} != :${paramKey}`, { [paramKey]: value });
break;
case '>':
qb.andWhere(`${column} > :${paramKey}`, { [paramKey]: value });
break;
case '<':
qb.andWhere(`${column} < :${paramKey}`, { [paramKey]: value });
break;
case '>=':
qb.andWhere(`${column} >= :${paramKey}`, { [paramKey]: value });
break;
case '<=':
qb.andWhere(`${column} <= :${paramKey}`, { [paramKey]: value });
break;
case 'in':
qb.andWhere(`${column} IN (:...${paramKey})`, { [paramKey]: value });
break;
case 'includes':
qb.andWhere(`${column} LIKE :${paramKey}`, { [paramKey]: `%${value}%` });
break;
}
}
if (method === 'whereNot') {
const [key, operator, value] = args.length === 3
? args
: [args[0], '=', args[1]];
const paramKey = `param${paramIndex++}`;
const column = `user.${key}`;
qb.andWhere(`${column} != :${paramKey}`, { [paramKey]: value });
}
if (method === 'sort') {
const [key, direction = 'asc'] = args;
qb.orderBy(`user.${key}`, direction.toUpperCase() as 'ASC' | 'DESC');
}
if (method === 'slice') {
const [start, end] = args;
qb.skip(start);
if (end !== undefined) qb.take(end - start);
}
if (method === 'paginate') {
const [page = 1, perPage = 20] = args;
qb.skip((page - 1) * perPage);
qb.take(perPage);
}
if (method === 'forget') {
// Select all except specified fields
const allColumns = qb.connection.getMetadata(User).columns.map(c => c.propertyName);
const selectFields = allColumns.filter(col => !args.includes(col));
qb.select(selectFields.map(f => `user.${f}`));
}
});
// Handle terminal operations
const lastOp = operations[operations.length - 1];
if (lastOp && lastOp[0] === 'first') {
const result = await qb.getOne();
return result ? [result] : [];
}
if (lastOp && lastOp[0] === 'last') {
// Reverse order and get first
const orderBy = qb.expressionMap.orderBys[0];
if (orderBy) {
const [column, order] = Object.entries(orderBy)[0];
qb.orderBy(column, order === 'ASC' ? 'DESC' : 'ASC');
}
const result = await qb.getOne();
return result ? [result] : [];
}
return await qb.getMany();
});
// Usage
const results = await users
.where('age', '>=', 21)
.where('country', 'USA')
.whereNot('deleted', true)
.sort('createdAt', 'desc')
.slice(0, 20);
const firstActive = await users
.where('status', 'active')
.first();
Sequelize Integration¶
Working with Sequelize ORM:
import AsyncCollection from "@arcaelas/collection/async";
import { Op, Model } from "sequelize";
import { User } from "./models/User";
const users = new AsyncCollection<User>(async ({ operations }) => {
const where: any = {};
let order: any[] = [];
let limit: number | undefined;
let offset: number | undefined;
let attributes: { exclude?: string[] } | undefined;
operations.forEach(([method, ...args]) => {
if (method === 'where') {
const [key, operator, value] = args.length === 3
? args
: [args[0], '=', args[1]];
const condition = buildSequelizeCondition(operator, value);
if (where[key]) {
where[key] = { [Op.and]: [where[key], condition] };
} else {
where[key] = condition;
}
}
if (method === 'sort') {
const [key, direction = 'asc'] = args;
order.push([key, direction.toUpperCase()]);
}
if (method === 'slice') {
const [start, end] = args;
offset = start;
limit = end ? end - start : undefined;
}
if (method === 'paginate') {
const [page = 1, perPage = 20] = args;
offset = (page - 1) * perPage;
limit = perPage;
}
if (method === 'forget') {
attributes = { exclude: args };
}
});
const lastOp = operations[operations.length - 1];
if (lastOp && lastOp[0] === 'first') {
const result = await User.findOne({ where, order, attributes });
return result ? [result] : [];
}
if (lastOp && lastOp[0] === 'last') {
const result = await User.findOne({
where,
order: order.map(([col, dir]) => [col, dir === 'ASC' ? 'DESC' : 'ASC']),
attributes,
});
return result ? [result] : [];
}
return await User.findAll({
where,
order,
limit,
offset,
attributes,
});
});
function buildSequelizeCondition(operator: string, value: any) {
switch (operator) {
case '=': return value;
case '!=': return { [Op.ne]: value };
case '>': return { [Op.gt]: value };
case '<': return { [Op.lt]: value };
case '>=': return { [Op.gte]: value };
case '<=': return { [Op.lte]: value };
case 'in': return { [Op.in]: value };
case 'includes': return { [Op.like]: `%${value}%` };
default: return value;
}
}
// Usage
const results = await users
.where('status', 'active')
.where('age', '>=', 18)
.sort('name', 'asc')
.paginate(1, 20);
Mongoose Integration¶
MongoDB queries with Mongoose:
import AsyncCollection from "@arcaelas/collection/async";
import mongoose, { Model, Query } from "mongoose";
import { IUser, UserModel } from "./models/User";
const users = new AsyncCollection<IUser>(async ({ operations }) => {
let query = UserModel.find();
let sortObj: any = {};
let selectObj: any = {};
operations.forEach(([method, ...args]) => {
if (method === 'where') {
const [key, operator, value] = args.length === 3
? args
: [args[0], '=', args[1]];
const condition = buildMongoCondition(key, operator, value);
query = query.where(condition);
}
if (method === 'sort') {
const [key, direction = 'asc'] = args;
sortObj[key] = direction === 'desc' ? -1 : 1;
}
if (method === 'slice') {
const [start, end] = args;
query = query.skip(start);
if (end) query = query.limit(end - start);
}
if (method === 'paginate') {
const [page = 1, perPage = 20] = args;
query = query.skip((page - 1) * perPage).limit(perPage);
}
if (method === 'forget') {
args.forEach(key => {
selectObj[key] = 0;
});
}
});
if (Object.keys(sortObj).length > 0) {
query = query.sort(sortObj);
}
if (Object.keys(selectObj).length > 0) {
query = query.select(selectObj);
}
const lastOp = operations[operations.length - 1];
if (lastOp && lastOp[0] === 'first') {
const result = await query.findOne();
return result ? [result] : [];
}
return await query.exec();
});
function buildMongoCondition(key: string, operator: string, value: any) {
const conditions: any = {};
switch (operator) {
case '=':
conditions[key] = value;
break;
case '!=':
conditions[key] = { $ne: value };
break;
case '>':
conditions[key] = { $gt: value };
break;
case '<':
conditions[key] = { $lt: value };
break;
case '>=':
conditions[key] = { $gte: value };
break;
case '<=':
conditions[key] = { $lte: value };
break;
case 'in':
conditions[key] = { $in: value };
break;
case 'includes':
conditions[key] = { $regex: value, $options: 'i' };
break;
default:
conditions[key] = value;
}
return conditions;
}
// Usage
const activeUsers = await users
.where('status', 'active')
.where('age', '>=', 18)
.sort('createdAt', 'desc')
.forget('password', '__v');
REST API Wrapper¶
Creating an API client with AsyncCollection:
import AsyncCollection from "@arcaelas/collection/async";
interface ApiUser {
id: number;
name: string;
email: string;
}
const apiUsers = new AsyncCollection<ApiUser>(async ({ operations }) => {
const params = new URLSearchParams();
let endpoint = '/api/users';
operations.forEach(([method, ...args]) => {
if (method === 'where') {
const [key, operator, value] = args.length === 3
? args
: [args[0], '=', args[1]];
if (operator === '=') {
params.append(key, String(value));
} else if (operator === 'includes') {
params.append(`${key}_like`, String(value));
} else if (operator === '>=') {
params.append(`${key}_gte`, String(value));
}
}
if (method === 'sort') {
const [key, direction = 'asc'] = args;
params.append('_sort', key);
params.append('_order', direction);
}
if (method === 'slice') {
const [start, end] = args;
params.append('_start', String(start));
if (end) params.append('_end', String(end));
}
if (method === 'paginate') {
const [page = 1, perPage = 20] = args;
params.append('_page', String(page));
params.append('_limit', String(perPage));
}
});
const url = `${endpoint}?${params.toString()}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`API request failed: ${response.statusText}`);
}
const data = await response.json();
const lastOp = operations[operations.length - 1];
if (lastOp && lastOp[0] === 'first') {
return Array.isArray(data) ? [data[0]] : [data];
}
return Array.isArray(data) ? data : [data];
});
// Usage
const users = await apiUsers
.where('status', 'active')
.where('name', 'includes', 'John')
.sort('createdAt', 'desc')
.paginate(1, 20);
const firstUser = await apiUsers
.where('email', 'john@example.com')
.first();
GraphQL Query Builder¶
Building GraphQL queries dynamically:
import AsyncCollection from "@arcaelas/collection/async";
import { GraphQLClient } from "graphql-request";
const client = new GraphQLClient('https://api.example.com/graphql');
interface GQLUser {
id: string;
name: string;
email: string;
}
const gqlUsers = new AsyncCollection<GQLUser>(async ({ operations }) => {
const filters: string[] = [];
let orderBy: string | undefined;
let limit: number | undefined;
let offset: number | undefined;
operations.forEach(([method, ...args]) => {
if (method === 'where') {
const [key, operator, value] = args.length === 3
? args
: [args[0], '=', args[1]];
const gqlOperator = mapToGQLOperator(operator);
filters.push(`${key}: { ${gqlOperator}: "${value}" }`);
}
if (method === 'sort') {
const [key, direction = 'asc'] = args;
orderBy = `${key}: ${direction.toUpperCase()}`;
}
if (method === 'slice') {
const [start, end] = args;
offset = start;
limit = end ? end - start : undefined;
}
if (method === 'paginate') {
const [page = 1, perPage = 20] = args;
offset = (page - 1) * perPage;
limit = perPage;
}
});
const whereClause = filters.length > 0 ? `where: { ${filters.join(', ')} }` : '';
const orderClause = orderBy ? `orderBy: { ${orderBy} }` : '';
const limitClause = limit ? `take: ${limit}` : '';
const offsetClause = offset ? `skip: ${offset}` : '';
const args = [whereClause, orderClause, limitClause, offsetClause]
.filter(Boolean)
.join(', ');
const query = `
query {
users${args ? `(${args})` : ''} {
id
name
email
createdAt
}
}
`;
const response = await client.request<{ users: GQLUser[] }>(query);
const lastOp = operations[operations.length - 1];
if (lastOp && lastOp[0] === 'first') {
return response.users.length > 0 ? [response.users[0]] : [];
}
return response.users;
});
function mapToGQLOperator(operator: string): string {
const mapping: Record<string, string> = {
'=': 'equals',
'!=': 'not',
'>': 'gt',
'<': 'lt',
'>=': 'gte',
'<=': 'lte',
'in': 'in',
'includes': 'contains',
};
return mapping[operator] || 'equals';
}
// Usage
const users = await gqlUsers
.where('status', 'active')
.where('age', '>=', 18)
.sort('name', 'asc')
.paginate(1, 10);
Redis Cache Layer¶
Using AsyncCollection with Redis caching:
import AsyncCollection from "@arcaelas/collection/async";
import Redis from "ioredis";
const redis = new Redis();
interface CachedUser {
id: number;
name: string;
email: string;
}
const cachedUsers = new AsyncCollection<CachedUser>(async ({ operations }) => {
// Build cache key from operations
const cacheKey = `users:${JSON.stringify(operations)}`;
// Check cache
const cached = await redis.get(cacheKey);
if (cached) {
console.log('Cache hit');
return JSON.parse(cached);
}
console.log('Cache miss - fetching from database');
// Fetch from database (example with fetch)
const params = new URLSearchParams();
operations.forEach(([method, ...args]) => {
if (method === 'where') {
const [key, value] = args.length === 2 ? args : [args[0], args[2]];
params.append(key, value);
}
});
const response = await fetch(`/api/users?${params}`);
const data = await response.json();
// Cache for 5 minutes
await redis.setex(cacheKey, 300, JSON.stringify(data));
return data;
});
// Usage
const users = await cachedUsers.where('status', 'active');
// Second call will use cache
const cachedResult = await cachedUsers.where('status', 'active');
Custom Validators¶
Advanced custom validator patterns:
import AsyncCollection from "@arcaelas/collection/async";
const customValidators = {
// Date validators
$isPast(ref: string, value: boolean) {
return (item: any) => {
const date = new Date(item[ref]);
const isPast = date < new Date();
return value ? isPast : !isPast;
};
},
$isFuture(ref: string, value: boolean) {
return (item: any) => {
const date = new Date(item[ref]);
const isFuture = date > new Date();
return value ? isFuture : !isFuture;
};
},
// Numeric validators
$between(ref: string, range: [number, number]) {
return (item: any) => {
const val = item[ref];
return val >= range[0] && val <= range[1];
};
},
// String validators
$matches(ref: string, regex: RegExp) {
return (item: any) => {
return regex.test(String(item[ref]));
};
},
// Array validators
$hasLength(ref: string, length: number) {
return (item: any) => {
return Array.isArray(item[ref]) && item[ref].length === length;
};
},
};
const items = new AsyncCollection(
async ({ operations, validators }) => {
let results = [...data];
operations.forEach(([method, ...args]) => {
if (method === 'filter' && typeof args[0] === 'object') {
const query = args[0];
results = results.filter(item => {
return Object.entries(query).every(([key, condition]) => {
if (typeof condition === 'object') {
return Object.entries(condition).every(([operator, value]) => {
if (validators && operator in validators) {
const validator = validators[operator];
const validatorFn = validator(key, value);
return validatorFn(item);
}
return true;
});
}
return item[key] === condition;
});
});
}
});
return results;
},
customValidators
);
// Usage
const results = await items.filter({
eventDate: { $isPast: true },
score: { $between: [50, 100] },
email: { $matches: /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i },
tags: { $hasLength: 3 },
});
Complex Query Chains¶
Building complex, multi-step queries:
import AsyncCollection from "@arcaelas/collection/async";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
// Complex user search with multiple conditions
const userSearch = new AsyncCollection(async ({ operations, metadata }) => {
console.log(`Building complex query: ${metadata.operation_count} operations`);
// Extract and organize operations
const where_ops = operations.filter(([m]) => m === 'where' || m === 'whereNot');
const sort_ops = operations.filter(([m]) => m === 'sort');
const slice_ops = operations.filter(([m]) => m === 'slice' || m === 'paginate');
const terminal_ops = operations.filter(([m]) => ['first', 'last'].includes(m));
// Build where conditions
const where: any = { AND: [] };
where_ops.forEach(([method, ...args]) => {
if (method === 'where') {
const condition = buildPrismaCondition(args);
where.AND.push(condition);
} else if (method === 'whereNot') {
const condition = buildPrismaCondition(args);
where.AND.push({ NOT: condition });
}
});
// Build order
const orderBy = sort_ops.map(([_, key, direction]) => ({
[key]: direction || 'asc',
}));
// Build pagination
let take: number | undefined;
let skip: number | undefined;
slice_ops.forEach(([method, ...args]) => {
if (method === 'slice') {
const [start, end] = args;
skip = start;
take = end ? end - start : undefined;
} else if (method === 'paginate') {
const [page = 1, perPage = 20] = args;
skip = (page - 1) * perPage;
take = perPage;
}
});
// Execute query based on terminal operation
if (terminal_ops.length > 0 && terminal_ops[0][0] === 'first') {
const result = await prisma.user.findFirst({
where: where.AND.length > 0 ? where : undefined,
orderBy,
});
return result ? [result] : [];
}
return await prisma.user.findMany({
where: where.AND.length > 0 ? where : undefined,
orderBy,
take,
skip,
});
});
// Usage: Complex search
const results = await userSearch
.where('status', 'active')
.where('verified', true)
.where('age', '>=', 18)
.where('age', '<=', 65)
.whereNot('deleted', true)
.whereNot('banned', true)
.sort('score', 'desc')
.sort('createdAt', 'desc')
.paginate(1, 20);
Error Handling Patterns¶
Robust error handling in executors:
import AsyncCollection from "@arcaelas/collection/async";
class QueryError extends Error {
constructor(message: string, public code: string) {
super(message);
this.name = 'QueryError';
}
}
const users = new AsyncCollection(async ({ operations, metadata }) => {
try {
// Validate operations
const unsupported = operations.find(([method]) =>
!['where', 'sort', 'first', 'slice'].includes(method)
);
if (unsupported) {
throw new QueryError(
`Unsupported operation: ${unsupported[0]}`,
'UNSUPPORTED_OPERATION'
);
}
// Build query
const query = buildQuery(operations);
// Execute with timeout
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify(query),
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new QueryError(
`API error: ${response.statusText}`,
'API_ERROR'
);
}
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
throw new QueryError('Query timeout exceeded', 'TIMEOUT');
}
throw error;
}
} catch (error) {
console.error('Query execution failed:', {
error,
operations,
metadata,
});
if (error instanceof QueryError) {
throw error;
}
throw new QueryError(
`Unexpected error: ${error.message}`,
'UNEXPECTED_ERROR'
);
}
});
// Usage with error handling
try {
const results = await users
.where('age', '>=', 18)
.sort('name', 'asc');
} catch (error) {
if (error instanceof QueryError) {
switch (error.code) {
case 'TIMEOUT':
console.error('Query took too long');
break;
case 'UNSUPPORTED_OPERATION':
console.error('Invalid operation used');
break;
case 'API_ERROR':
console.error('API returned an error');
break;
}
}
}
Performance Optimization¶
Optimizing query execution:
import AsyncCollection from "@arcaelas/collection/async";
const optimizedUsers = new AsyncCollection(async ({ operations, metadata }) => {
console.log(`Optimizing ${metadata.operation_count} operations`);
// Group related operations
const operation_groups = {
filters: operations.filter(([m]) => ['where', 'whereNot', 'filter'].includes(m)),
sorting: operations.filter(([m]) => m === 'sort'),
pagination: operations.filter(([m]) => ['slice', 'paginate'].includes(m)),
terminal: operations.filter(([m]) => ['first', 'last'].includes(m)),
};
// Optimize: If terminal operation is 'first', limit to 1
const shouldLimitOne = operation_groups.terminal.some(([m]) => m === 'first');
// Build optimized query
const query = {
where: buildOptimizedWhere(operation_groups.filters),
orderBy: buildOrderBy(operation_groups.sorting),
...(shouldLimitOne
? { take: 1 }
: buildPagination(operation_groups.pagination)),
};
// Execute with connection pooling
const results = await executeWithPool(query);
// Return based on terminal operation
if (shouldLimitOne) {
return results.length > 0 ? [results[0]] : [];
}
return results;
});
function buildOptimizedWhere(filters: any[]) {
// Combine multiple where clauses on same field
const grouped = filters.reduce((acc, [method, ...args]) => {
const key = args[0];
if (!acc[key]) acc[key] = [];
acc[key].push({ method, args });
return acc;
}, {});
// Build optimized conditions
return Object.entries(grouped).map(([key, conditions]: [string, any]) => {
if (conditions.length === 1) {
return buildSingleCondition(conditions[0]);
}
return { AND: conditions.map(buildSingleCondition) };
});
}