Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/language/src/validators/datamodel-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ export default class DataModelValidator implements AstValidator<DataModel> {
invariant(model.baseModel.ref, 'baseModel must be resolved');

// check if the base model is a delegate model
if (!isDelegateModel(model.baseModel.ref)) {
if (!isDelegateModel(model.baseModel.ref!)) {
accept('error', `Model ${model.baseModel.$refText} cannot be extended because it's not a delegate model`, {
node: model,
property: 'baseModel',
Expand Down
53 changes: 30 additions & 23 deletions packages/runtime/src/client/crud-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,14 +437,6 @@ export type SelectIncludeOmit<Schema extends SchemaDef, Model extends GetModels<
omit?: OmitInput<Schema, Model>;
};

type Distinct<Schema extends SchemaDef, Model extends GetModels<Schema>> = {
distinct?: OrArray<NonRelationFields<Schema, Model>>;
};

type Cursor<Schema extends SchemaDef, Model extends GetModels<Schema>> = {
cursor?: WhereUniqueInput<Schema, Model>;
};

export type SelectInput<
Schema extends SchemaDef,
Model extends GetModels<Schema>,
Expand Down Expand Up @@ -621,25 +613,34 @@ type OppositeRelationAndFK<

//#region Find args

type FilterArgs<Schema extends SchemaDef, Model extends GetModels<Schema>> = {
where?: WhereInput<Schema, Model>;
};

type SortAndTakeArgs<Schema extends SchemaDef, Model extends GetModels<Schema>> = {
skip?: number;
take?: number;
orderBy?: OrArray<OrderBy<Schema, Model, true, false>>;
cursor?: WhereUniqueInput<Schema, Model>;
};

export type FindArgs<
Schema extends SchemaDef,
Model extends GetModels<Schema>,
Collection extends boolean,
AllowFilter extends boolean = true,
> = (Collection extends true
? {
skip?: number;
take?: number;
orderBy?: OrArray<OrderBy<Schema, Model, true, false>>;
} & Distinct<Schema, Model> &
Cursor<Schema, Model>
: {}) &
(AllowFilter extends true
? {
where?: WhereInput<Schema, Model>;
}
: {}) &
SelectIncludeOmit<Schema, Model, Collection>;
> =
ProviderSupportsDistinct<Schema> extends true
? (Collection extends true
? SortAndTakeArgs<Schema, Model> & {
distinct?: OrArray<NonRelationFields<Schema, Model>>;
}
: {}) &
(AllowFilter extends true ? FilterArgs<Schema, Model> : {}) &
SelectIncludeOmit<Schema, Model, Collection>
: (Collection extends true ? SortAndTakeArgs<Schema, Model> : {}) &
(AllowFilter extends true ? FilterArgs<Schema, Model> : {}) &
SelectIncludeOmit<Schema, Model, Collection>;

export type FindManyArgs<Schema extends SchemaDef, Model extends GetModels<Schema>> = FindArgs<Schema, Model, true>;
export type FindFirstArgs<Schema extends SchemaDef, Model extends GetModels<Schema>> = FindArgs<Schema, Model, false>;
Expand Down Expand Up @@ -1259,6 +1260,12 @@ type HasToManyRelations<Schema extends SchemaDef, Model extends GetModels<Schema
? false
: true;

type ProviderSupportsCaseSensitivity<Schema extends SchemaDef> = Schema['provider'] extends 'postgresql' ? true : false;
type ProviderSupportsCaseSensitivity<Schema extends SchemaDef> = Schema['provider']['type'] extends 'postgresql'
? true
: false;

type ProviderSupportsDistinct<Schema extends SchemaDef> = Schema['provider']['type'] extends 'postgresql'
? true
: false;

// #endregion
92 changes: 91 additions & 1 deletion packages/runtime/src/client/crud/dialects/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
aggregate,
buildFieldRef,
buildJoinPairs,
ensureArray,
flattenCompoundUniqueFilters,
getDelegateDescendantModels,
getIdFields,
Expand Down Expand Up @@ -58,6 +59,54 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
return result;
}

buildFilterSortTake(
model: GetModels<Schema>,
args: FindArgs<Schema, GetModels<Schema>, true>,
query: SelectQueryBuilder<any, any, {}>,
) {
let result = query;

// where
if (args.where) {
result = result.where((eb) => this.buildFilter(eb, model, model, args?.where));
}

// skip && take
let negateOrderBy = false;
const skip = args.skip;
let take = args.take;
if (take !== undefined && take < 0) {
negateOrderBy = true;
take = -take;
}
result = this.buildSkipTake(result, skip, take);

// orderBy
result = this.buildOrderBy(
result,
model,
model,
args.orderBy,
skip !== undefined || take !== undefined,
negateOrderBy,
);

// distinct
if ('distinct' in args && (args as any).distinct) {
const distinct = ensureArray((args as any).distinct) as string[];
if (this.supportsDistinctOn) {
result = result.distinctOn(distinct.map((f) => sql.ref(`${model}.${f}`)));
} else {
throw new QueryError(`"distinct" is not supported by "${this.schema.provider.type}" provider`);
}
}

if (args.cursor) {
result = this.buildCursorFilter(model, result, args.cursor, args.orderBy, negateOrderBy);
}
return result;
}

buildFilter(
eb: ExpressionBuilder<any, any>,
model: string,
Expand Down Expand Up @@ -117,6 +166,47 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
return result;
}

private buildCursorFilter(
model: string,
query: SelectQueryBuilder<any, any, any>,
cursor: FindArgs<Schema, GetModels<Schema>, true>['cursor'],
orderBy: FindArgs<Schema, GetModels<Schema>, true>['orderBy'],
negateOrderBy: boolean,
) {
const _orderBy = orderBy ?? makeDefaultOrderBy(this.schema, model);

const orderByItems = ensureArray(_orderBy).flatMap((obj) => Object.entries<SortOrder>(obj));

const eb = expressionBuilder<any, any>();
const cursorFilter = this.buildFilter(eb, model, model, cursor);

let result = query;
const filters: ExpressionWrapper<any, any, any>[] = [];

for (let i = orderByItems.length - 1; i >= 0; i--) {
const andFilters: ExpressionWrapper<any, any, any>[] = [];

for (let j = 0; j <= i; j++) {
const [field, order] = orderByItems[j]!;
const _order = negateOrderBy ? (order === 'asc' ? 'desc' : 'asc') : order;
const op = j === i ? (_order === 'asc' ? '>=' : '<=') : '=';
andFilters.push(
eb(
eb.ref(`${model}.${field}`),
op,
eb.selectFrom(model).select(`${model}.${field}`).where(cursorFilter),
),
);
}

filters.push(eb.and(andFilters));
}

result = result.where((eb) => eb.or(filters));

return result;
}

private isLogicalCombinator(key: string): key is (typeof LOGICAL_COMBINATORS)[number] {
return LOGICAL_COMBINATORS.includes(key as any);
}
Expand Down Expand Up @@ -722,7 +812,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
// aggregations
if (['_count', '_avg', '_sum', '_min', '_max'].includes(field)) {
invariant(value && typeof value === 'object', `invalid orderBy value for field "${field}"`);
for (const [k, v] of Object.entries<string>(value)) {
for (const [k, v] of Object.entries<SortOrder>(value)) {
invariant(v === 'asc' || v === 'desc', `invalid orderBy value for field "${field}"`);
result = result.orderBy(
(eb) =>
Expand Down
26 changes: 1 addition & 25 deletions packages/runtime/src/client/crud/dialects/postgresql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,31 +91,7 @@ export class PostgresCrudDialect<Schema extends SchemaDef> extends BaseCrudDiale
);

if (payload && typeof payload === 'object') {
if (payload.where) {
subQuery = subQuery.where((eb) =>
this.buildFilter(eb, relationModel, relationModel, payload.where),
);
}

// skip & take
const skip = payload.skip;
let take = payload.take;
let negateOrderBy = false;
if (take !== undefined && take < 0) {
negateOrderBy = true;
take = -take;
}
subQuery = this.buildSkipTake(subQuery, skip, take);

// orderBy
subQuery = this.buildOrderBy(
subQuery,
relationModel,
relationModel,
payload.orderBy,
skip !== undefined || take !== undefined,
negateOrderBy,
);
subQuery = this.buildFilterSortTake(relationModel, payload, subQuery);
}

// add join conditions
Expand Down
27 changes: 2 additions & 25 deletions packages/runtime/src/client/crud/dialects/sqlite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,31 +85,8 @@ export class SqliteCrudDialect<Schema extends SchemaDef> extends BaseCrudDialect
);

if (payload && typeof payload === 'object') {
if (payload.where) {
subQuery = subQuery.where((eb) =>
this.buildFilter(eb, relationModel, relationModel, payload.where),
);
}

// skip & take
const skip = payload.skip;
let take = payload.take;
let negateOrderBy = false;
if (take !== undefined && take < 0) {
negateOrderBy = true;
take = -take;
}
subQuery = this.buildSkipTake(subQuery, skip, take);

// orderBy
subQuery = this.buildOrderBy(
subQuery,
relationModel,
relationModel,
payload.orderBy,
skip !== undefined || take !== undefined,
negateOrderBy,
);
// take care of where, orderBy, skip, take, cursor, and distinct
subQuery = this.buildFilterSortTake(relationModel, payload, subQuery);
}

// join conditions
Expand Down
Loading