@algochad/prisma-core
Version:
A comprehensive NestJS library that provides EF-Core-like operations using Prisma and GraphQL. Features LINQ-style query builders, advanced data manipulation, GraphQL integration with genql, and a unified API for both Prisma and GraphQL operations. Includ
832 lines • 28 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InMemoryGraphQLQueryable = exports.GraphQLOrderedQueryable = exports.GraphQLQueryable = exports.GraphQLQueryProvider = void 0;
const async_enumerable_1 = require("../linq/async-enumerable");
const enumerable_1 = require("../linq/enumerable");
const list_1 = require("../linq/list");
class GraphQLQueryProvider {
genqlClient;
operationName;
operationType;
constructor(genqlClient, operationName, operationType = 'query') {
this.genqlClient = genqlClient;
this.operationName = operationName;
this.operationType = operationType;
}
async Execute(expression) {
const query = this.buildGenqlQuery(expression);
let results;
switch (expression.operationType || this.operationType) {
case 'mutation':
if (!this.genqlClient.mutation) {
throw new Error('Mutation not supported by this GraphQL client');
}
results = await this.genqlClient.mutation(query);
break;
case 'subscription':
if (!this.genqlClient.subscription) {
throw new Error('Subscription not supported by this GraphQL client');
}
const subscription = this.genqlClient.subscription(query);
const { value } = await subscription.next();
results = value;
break;
default:
results = await this.genqlClient.query(query);
}
let data = results[this.operationName];
if (expression.inMemoryPredicates &&
expression.inMemoryPredicates.length > 0) {
if (Array.isArray(data)) {
for (const predicate of expression.inMemoryPredicates) {
if (predicate) {
data = data.filter(predicate);
}
}
}
}
return data;
}
buildGenqlQuery(expression) {
const query = {};
const operationQuery = {};
const args = {};
if (expression.where) {
Object.assign(args, expression.where);
}
if (expression.args) {
Object.assign(args, expression.args);
}
if (expression.first !== undefined) {
args.first = expression.first;
}
if (expression.skip !== undefined) {
args.skip = expression.skip;
}
if (expression.orderBy && expression.orderBy.length > 0) {
args.orderBy = expression.orderBy;
}
if (Object.keys(args).length > 0) {
operationQuery.__args = args;
}
if (expression.select) {
Object.assign(operationQuery, expression.select);
}
else {
operationQuery.__scalar = true;
}
query[this.operationName] = operationQuery;
return query;
}
CreateQuery(expression) {
return new GraphQLQueryable(this, expression);
}
}
exports.GraphQLQueryProvider = GraphQLQueryProvider;
class GraphQLQueryable {
provider;
expression;
elementType;
constructor(provider, expression, elementType) {
this.provider = provider;
this.expression = expression || {};
this.elementType = elementType;
}
get Provider() {
return this.provider;
}
get Expression() {
return this.expression;
}
get ElementType() {
return this.elementType;
}
createNew(newExpression) {
const mergedExpression = { ...this.expression, ...newExpression };
return new GraphQLQueryable(this.provider, mergedExpression, this.elementType);
}
WhereFilter(where) {
const existingWhere = this.expression.where;
let finalWhere;
if (existingWhere &&
typeof existingWhere === 'object' &&
typeof where === 'object') {
finalWhere = { ...existingWhere, ...where };
}
else {
finalWhere = where;
}
return this.createNew({ where: finalWhere });
}
SelectFields(select) {
return this.createNew({ select: select });
}
Include(include) {
throw new Error('Include is not supported in GraphQL. Use SelectFields instead to specify the fields you want to retrieve.');
}
OrderBy(orderBy) {
return new GraphQLOrderedQueryable(this.provider, { ...this.expression, orderBy: [orderBy] }, this.elementType);
}
SelectMany(selector) {
const resultData = this.ToArrayAsync().then(async (items) => {
const results = [];
for (const item of items) {
const selected = selector(item);
if ('ToArrayAsync' in selected) {
const subResults = await selected.ToArrayAsync();
results.push(...subResults);
}
else {
for await (const subItem of selected) {
results.push(subItem);
}
}
}
return results;
});
return new InMemoryGraphQLQueryable(resultData);
}
GroupBy(keySelector, elementSelector, resultSelector) {
const resultData = this.ToArrayAsync().then((items) => {
const groups = new Map();
for (const item of items) {
const key = keySelector(item);
const element = elementSelector
? elementSelector(item)
: item;
if (!groups.has(key)) {
groups.set(key, []);
}
groups.get(key).push(element);
}
const results = [];
for (const [key, elements] of groups.entries()) {
if (resultSelector) {
const group = new InMemoryGraphQLQueryable(elements);
results.push(resultSelector(key, group));
}
else {
results.push({ Key: key, Values: elements });
}
}
return results;
});
return new InMemoryGraphQLQueryable(resultData);
}
Join(inner, outerKeySelector, innerKeySelector, resultSelector) {
const resultData = Promise.all([
this.ToArrayAsync(),
'ToArrayAsync' in inner
? inner.ToArrayAsync()
: Promise.resolve([]),
]).then(([outerItems, innerItems]) => {
const results = [];
for (const outerItem of outerItems) {
const outerKey = outerKeySelector(outerItem);
for (const innerItem of innerItems) {
const innerKey = innerKeySelector(innerItem);
if (outerKey === innerKey) {
results.push(resultSelector(outerItem, innerItem));
}
}
}
return results;
});
return new InMemoryGraphQLQueryable(resultData);
}
Union(other) {
const resultData = Promise.all([
this.ToArrayAsync(),
'ToArrayAsync' in other
? other.ToArrayAsync()
: Promise.resolve([]),
]).then(([thisItems, otherItems]) => {
const seen = new Set();
const results = [];
for (const item of [...thisItems, ...otherItems]) {
const key = JSON.stringify(item);
if (!seen.has(key)) {
seen.add(key);
results.push(item);
}
}
return results;
});
return new InMemoryGraphQLQueryable(resultData);
}
Intersect(other) {
const resultData = Promise.all([
this.ToArrayAsync(),
'ToArrayAsync' in other
? other.ToArrayAsync()
: Promise.resolve([]),
]).then(([thisItems, otherItems]) => {
const otherSet = new Set(otherItems.map((item) => JSON.stringify(item)));
const results = [];
const seen = new Set();
for (const item of thisItems) {
const key = JSON.stringify(item);
if (otherSet.has(key) && !seen.has(key)) {
seen.add(key);
results.push(item);
}
}
return results;
});
return new InMemoryGraphQLQueryable(resultData);
}
Except(other) {
const resultData = Promise.all([
this.ToArrayAsync(),
'ToArrayAsync' in other
? other.ToArrayAsync()
: Promise.resolve([]),
]).then(([thisItems, otherItems]) => {
const otherSet = new Set(otherItems.map((item) => JSON.stringify(item)));
const results = [];
const seen = new Set();
for (const item of thisItems) {
const key = JSON.stringify(item);
if (!otherSet.has(key) && !seen.has(key)) {
seen.add(key);
results.push(item);
}
}
return results;
});
return new InMemoryGraphQLQueryable(resultData);
}
Take(count) {
return this.createNew({ first: count });
}
Skip(count) {
return this.createNew({ skip: count });
}
Distinct(keySelector) {
return this.createNew({
distinct: keySelector ? [keySelector] : true,
});
}
Where = this.WhereFilter;
Select = this.SelectFields;
async ExecuteAsync() {
return await this.ToArrayAsync();
}
async ToArrayAsync() {
return await this.provider.Execute(this.expression);
}
async ToListAsync() {
const array = await this.ToArrayAsync();
return new list_1.List(array);
}
async FirstAsync(predicate) {
if (predicate) {
const items = await this.ToArrayAsync();
for (const item of items) {
if (await predicate(item))
return item;
}
throw new Error('No matching element found');
}
else {
const results = await this.createNew({
first: 1,
}).ToArrayAsync();
if (results.length === 0) {
throw new Error('Sequence contains no elements');
}
return results[0];
}
}
async FirstOrDefaultAsync(predicate) {
try {
return await this.FirstAsync(predicate);
}
catch {
return undefined;
}
}
async LastAsync(predicate) {
const items = await this.ToArrayAsync();
if (predicate) {
for (let i = items.length - 1; i >= 0; i--) {
if (await predicate(items[i]))
return items[i];
}
throw new Error('No matching element found');
}
if (items.length === 0) {
throw new Error('Sequence contains no elements');
}
return items[items.length - 1];
}
async LastOrDefaultAsync(predicate) {
try {
return await this.LastAsync(predicate);
}
catch {
return undefined;
}
}
async SingleAsync(predicate) {
const items = await this.ToArrayAsync();
let found;
let count = 0;
for (const item of items) {
if (!predicate || (await predicate(item))) {
found = item;
count++;
if (count > 1) {
throw new Error('Sequence contains more than one element');
}
}
}
if (count === 0) {
throw new Error('Sequence contains no elements');
}
return found;
}
async SingleOrDefaultAsync(predicate) {
try {
return await this.SingleAsync(predicate);
}
catch (error) {
if (error.message.includes('more than one element')) {
throw error;
}
return undefined;
}
}
async CountAsync(predicate) {
if (predicate) {
const items = await this.ToArrayAsync();
let count = 0;
for (const item of items) {
if (await predicate(item))
count++;
}
return count;
}
else {
const items = await this.ToArrayAsync();
return items.length;
}
}
async AnyAsync(predicate) {
if (predicate) {
const items = await this.ToArrayAsync();
for (const item of items) {
if (await predicate(item))
return true;
}
return false;
}
else {
const results = await this.createNew({
first: 1,
}).ToArrayAsync();
return results.length > 0;
}
}
async AllAsync(predicate) {
const items = await this.ToArrayAsync();
for (const item of items) {
if (!(await predicate(item)))
return false;
}
return true;
}
async MinAsync(selector) {
const items = await this.ToArrayAsync();
if (items.length === 0) {
throw new Error('Sequence contains no elements');
}
if (selector) {
return items
.map(selector)
.reduce((min, current) => (current < min ? current : min));
}
return items.reduce((min, current) => (current < min ? current : min));
}
async MaxAsync(selector) {
const items = await this.ToArrayAsync();
if (items.length === 0) {
throw new Error('Sequence contains no elements');
}
if (selector) {
return items
.map(selector)
.reduce((max, current) => (current > max ? current : max));
}
return items.reduce((max, current) => (current > max ? current : max));
}
async SumAsync(selector) {
const items = await this.ToArrayAsync();
return items
.map(selector || ((x) => x))
.reduce((sum, current) => sum + current, 0);
}
async AverageAsync(selector) {
const items = await this.ToArrayAsync();
const values = items.map(selector || ((x) => x));
return (values.reduce((sum, current) => sum + current, 0) / values.length);
}
async LongCountAsync(predicate) {
return await this.CountAsync(predicate);
}
async AggregateAsync(seed, func) {
const items = await this.ToArrayAsync();
let accumulator = seed;
for (const item of items) {
accumulator = await func(accumulator, item);
}
return accumulator;
}
async ContainsAsync(item) {
const items = await this.ToArrayAsync();
return items.includes(item);
}
async ForEachAsync(action) {
const items = await this.ToArrayAsync();
for (const item of items) {
await action(item);
}
}
async ToEnumerable() {
const array = await this.ToArrayAsync();
return new enumerable_1.Enumerable(array);
}
async AsEnumerable() {
return this.ToEnumerable();
}
async AsAsyncEnumerable() {
const array = await this.ToArrayAsync();
return new async_enumerable_1.AsyncEnumerable(array);
}
async ToEnumerableAsync() {
return this.ToEnumerable();
}
async ToAsyncEnumerable() {
return this.AsAsyncEnumerable();
}
}
exports.GraphQLQueryable = GraphQLQueryable;
class GraphQLOrderedQueryable extends GraphQLQueryable {
Take(count) {
return new GraphQLOrderedQueryable(this.provider, { ...this.expression, first: count }, this.elementType);
}
Skip(count) {
return new GraphQLOrderedQueryable(this.provider, { ...this.expression, skip: count }, this.elementType);
}
Distinct(keySelector) {
return new GraphQLOrderedQueryable(this.provider, {
...this.expression,
distinct: keySelector ? [keySelector] : true,
}, this.elementType);
}
ThenBy(orderBy) {
const currentOrderBy = this.expression.orderBy || [];
return new GraphQLOrderedQueryable(this.provider, {
...this.expression,
orderBy: [...currentOrderBy, orderBy],
}, this.elementType);
}
ThenByDescending(orderBy) {
const currentOrderBy = this.expression.orderBy || [];
return new GraphQLOrderedQueryable(this.provider, {
...this.expression,
orderBy: [...currentOrderBy, orderBy],
}, this.elementType);
}
}
exports.GraphQLOrderedQueryable = GraphQLOrderedQueryable;
class InMemoryGraphQLQueryable {
data;
constructor(data) {
this.data = data;
}
get Provider() {
throw new Error('InMemoryGraphQLQueryable does not support Provider');
}
get Expression() {
return null;
}
get ElementType() {
return null;
}
WhereFilter(where) {
throw new Error('WhereFilter not supported in InMemoryGraphQLQueryable');
}
SelectFields(select) {
throw new Error('SelectFields not supported in InMemoryGraphQLQueryable');
}
Include(include) {
throw new Error('Include is not supported in GraphQL. Use SelectFields instead to specify the fields you want to retrieve.');
}
OrderBy(orderBy) {
throw new Error('OrderBy not supported in InMemoryGraphQLQueryable');
}
SelectMany(selector) {
const newData = this.resolveData().then(async (items) => {
const results = [];
for (const item of items) {
const result = selector(item);
if (result &&
typeof result.ToArrayAsync === 'function') {
const arr = await result.ToArrayAsync();
results.push(...arr);
}
else if (result &&
typeof result.ToArrayAsync === 'function') {
const arr = await result.ToArrayAsync();
results.push(...arr);
}
}
return results;
});
return new InMemoryGraphQLQueryable(newData);
}
GroupBy(keySelector, elementSelector, resultSelector) {
const newData = this.resolveData().then((items) => {
const groups = new Map();
for (const item of items) {
const key = keySelector(item);
const value = elementSelector
? elementSelector(item)
: item;
if (!groups.has(key))
groups.set(key, []);
groups.get(key).push(value);
}
const result = [];
for (const [key, group] of groups.entries()) {
if (resultSelector) {
const groupQueryable = new InMemoryGraphQLQueryable(group);
result.push(resultSelector(key, groupQueryable));
}
else {
result.push({ key, group });
}
}
return result;
});
return new InMemoryGraphQLQueryable(newData);
}
Join(inner, outerKeySelector, innerKeySelector, resultSelector) {
const newData = this.resolveData().then(async (outerItems) => {
const innerItems = await inner.ToArrayAsync();
const results = [];
for (const o of outerItems) {
const oKey = outerKeySelector(o);
for (const i of innerItems) {
if (oKey === innerKeySelector(i)) {
results.push(resultSelector(o, i));
}
}
}
return results;
});
return new InMemoryGraphQLQueryable(newData);
}
Take(count) {
const newData = this.resolveData().then((items) => items.slice(0, count));
return new InMemoryGraphQLQueryable(newData);
}
Skip(count) {
const newData = this.resolveData().then((items) => items.slice(count));
return new InMemoryGraphQLQueryable(newData);
}
Distinct(keySelector) {
const newData = this.resolveData().then((items) => {
if (keySelector) {
const seen = new Set();
return items.filter((item) => {
const key = keySelector(item);
if (seen.has(key))
return false;
seen.add(key);
return true;
});
}
else {
return Array.from(new Set(items));
}
});
return new InMemoryGraphQLQueryable(newData);
}
Union(other) {
const newData = this.resolveData().then(async (arr1) => {
const arr2 = await other.ToArrayAsync();
return Array.from(new Set([...arr1, ...arr2]));
});
return new InMemoryGraphQLQueryable(newData);
}
Intersect(other) {
const newData = this.resolveData().then(async (arr1) => {
const arr2 = await other.ToArrayAsync();
return arr1.filter((x) => arr2.includes(x));
});
return new InMemoryGraphQLQueryable(newData);
}
Except(other) {
const newData = this.resolveData().then(async (arr1) => {
const arr2 = await other.ToArrayAsync();
return arr1.filter((x) => !arr2.includes(x));
});
return new InMemoryGraphQLQueryable(newData);
}
Where = this.WhereFilter;
Select = this.SelectFields;
async ToArrayAsync() {
return await this.resolveData();
}
async ToListAsync() {
const array = await this.ToArrayAsync();
return new list_1.List(array);
}
async FirstAsync(predicate) {
const items = await this.resolveData();
if (predicate) {
for (const item of items) {
if (await predicate(item))
return item;
}
throw new Error('No matching element found');
}
if (items.length === 0) {
throw new Error('Sequence contains no elements');
}
return items[0];
}
async FirstOrDefaultAsync(predicate) {
try {
return await this.FirstAsync(predicate);
}
catch {
return undefined;
}
}
async LastAsync(predicate) {
const items = await this.resolveData();
if (predicate) {
for (let i = items.length - 1; i >= 0; i--) {
if (await predicate(items[i]))
return items[i];
}
throw new Error('No matching element found');
}
if (items.length === 0) {
throw new Error('Sequence contains no elements');
}
return items[items.length - 1];
}
async LastOrDefaultAsync(predicate) {
try {
return await this.LastAsync(predicate);
}
catch {
return undefined;
}
}
async SingleAsync(predicate) {
const items = await this.resolveData();
let found;
let count = 0;
for (const item of items) {
if (!predicate || (await predicate(item))) {
found = item;
count++;
if (count > 1) {
throw new Error('Sequence contains more than one element');
}
}
}
if (count === 0) {
throw new Error('Sequence contains no elements');
}
return found;
}
async SingleOrDefaultAsync(predicate) {
try {
return await this.SingleAsync(predicate);
}
catch (error) {
if (error.message.includes('more than one element')) {
throw error;
}
return undefined;
}
}
async CountAsync(predicate) {
const items = await this.resolveData();
if (predicate) {
let count = 0;
for (const item of items) {
if (await predicate(item))
count++;
}
return count;
}
return items.length;
}
async AnyAsync(predicate) {
const items = await this.resolveData();
if (predicate) {
for (const item of items) {
if (await predicate(item))
return true;
}
return false;
}
return items.length > 0;
}
async AllAsync(predicate) {
const items = await this.resolveData();
for (const item of items) {
if (!(await predicate(item)))
return false;
}
return true;
}
async MinAsync(selector) {
const items = await this.resolveData();
if (items.length === 0) {
throw new Error('Sequence contains no elements');
}
if (selector) {
return items
.map(selector)
.reduce((min, current) => (current < min ? current : min));
}
return items.reduce((min, current) => (current < min ? current : min));
}
async MaxAsync(selector) {
const items = await this.resolveData();
if (items.length === 0) {
throw new Error('Sequence contains no elements');
}
if (selector) {
return items
.map(selector)
.reduce((max, current) => (current > max ? current : max));
}
return items.reduce((max, current) => (current > max ? current : max));
}
async SumAsync(selector) {
const items = await this.resolveData();
return items
.map(selector || ((x) => x))
.reduce((sum, current) => sum + current, 0);
}
async AverageAsync(selector) {
const items = await this.resolveData();
const values = items.map(selector || ((x) => x));
return (values.reduce((sum, current) => sum + current, 0) / values.length);
}
async AggregateAsync(seed, func) {
const items = await this.resolveData();
let accumulator = seed;
for (const item of items) {
accumulator = await func(accumulator, item);
}
return accumulator;
}
async ContainsAsync(item) {
const items = await this.resolveData();
return items.includes(item);
}
async ToEnumerable() {
const array = await this.ToArrayAsync();
return new enumerable_1.Enumerable(array);
}
async AsEnumerable() {
return this.ToEnumerable();
}
async AsAsyncEnumerable() {
const array = await this.ToArrayAsync();
return new async_enumerable_1.AsyncEnumerable(array);
}
async ToEnumerableAsync() {
return this.ToEnumerable();
}
async ToAsyncEnumerable() {
return this.AsAsyncEnumerable();
}
async ExecuteAsync() {
return await this.ToArrayAsync();
}
async LongCountAsync(predicate) {
return await this.CountAsync(predicate);
}
async ForEachAsync(action) {
const items = await this.resolveData();
for (const item of items) {
await action(item);
}
}
async resolveData() {
return Array.isArray(this.data) ? this.data : await this.data;
}
}
exports.InMemoryGraphQLQueryable = InMemoryGraphQLQueryable;
//# sourceMappingURL=graphql-queryable.js.map