Skip to content

Commit

Permalink
simplify query type generics
Browse files Browse the repository at this point in the history
  • Loading branch information
wernst committed May 20, 2024
1 parent 1dd74f5 commit f826e50
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 100 deletions.
8 changes: 8 additions & 0 deletions .changeset/two-tomatoes-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@triplit/client': patch
'@triplit/svelte': patch
'@triplit/react': patch
'@triplit/db': patch
---

Simplify query builder and query generics
3 changes: 2 additions & 1 deletion packages/client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type {
ReturnTypeFromQuery,
ModelFromModels,
FetchByIdQueryParams,
QueryBuilder,
} from '@triplit/db';
export { Schema } from '@triplit/db';
export * from './triplit-client.js';
Expand All @@ -15,7 +16,7 @@ export * from './transport/transport.js';
export type {
ClientFetchResult,
ClientQuery,
ClientQueryBuilder,
ClientQueryDefault,
ClientSchema,
Entity,
} from './utils/query.js';
7 changes: 4 additions & 3 deletions packages/client/src/remote-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
RemoteClientQueryBuilder,
prepareFetchByIdQuery,
prepareFetchOneQuery,
remoteClientQueryBuilder,
} from './utils/query.js';

function parseError(error: string) {
Expand Down Expand Up @@ -97,7 +98,7 @@ export class RemoteClient<M extends ClientSchema | undefined> {
return deserializeHTTPFetchResult(query, data.result, await this.schema());
}

private async queryTriples<CQ extends ClientQuery<M, any>>(
private async queryTriples<CQ extends ClientQuery<M, any, any, any>>(
query: CQ
): Promise<TripleRow[]> {
const { data, error } = await this.sendRequest('/queryTriples', 'POST', {
Expand Down Expand Up @@ -277,8 +278,8 @@ export class RemoteClient<M extends ClientSchema | undefined> {

query<CN extends CollectionNameFromModels<M>>(
collectionName: CN
): RemoteClientQueryBuilder<M, CN> {
return RemoteClientQueryBuilder<M, CN>(collectionName);
): ReturnType<typeof remoteClientQueryBuilder<M, CN>> {
return remoteClientQueryBuilder<M, CN>(collectionName);
}
}

Expand Down
8 changes: 4 additions & 4 deletions packages/client/src/triplit-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import {
ClientFetchResult,
ClientFetchResultEntity,
ClientQuery,
ClientQueryBuilder,
ClientSchema,
clientQueryBuilder,
prepareFetchByIdQuery,
prepareFetchOneQuery,
} from './utils/query.js';
Expand Down Expand Up @@ -277,8 +277,8 @@ export class TriplitClient<M extends ClientSchema | undefined = undefined> {

query<CN extends CollectionNameFromModels<M>>(
collectionName: CN
): ReturnType<typeof ClientQueryBuilder<M, CN>> {
return ClientQueryBuilder<M, CN>(collectionName);
): ReturnType<typeof clientQueryBuilder<M, CN>> {
return clientQueryBuilder<M, CN>(collectionName);
}

async fetch<CQ extends ClientQuery<M, any>>(
Expand Down Expand Up @@ -465,7 +465,7 @@ export class TriplitClient<M extends ClientSchema | undefined = undefined> {
}

// TODO: refactor so some logic is shared across policies (ex starting a local and remote sub is verbose and repetitive)
subscribe<CQ extends ClientQuery<M, any>>(
subscribe<CQ extends ClientQuery<M, any, any, any>>(
query: CQ,
onResults: (
results: ClientFetchResult<CQ>,
Expand Down
60 changes: 27 additions & 33 deletions packages/client/src/utils/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,38 +55,44 @@ export type ClientQuery<
// - DB builder returns specific type QueryBuilder<...Params>
// - The client builder needs to return ClientQueryBuilder<...Params>
// - cant return 'this' because we need to update generics
// TODO: fix this
class ClientQueryBuilderClass<
M extends ClientSchema | undefined,
CN extends CollectionNameFromModels<M>,
CQ extends ClientQuery<M, CN, any, any>
> extends QueryBuilder<M, CN, CQ> {
export class ClientQueryBuilder<
CQ extends ClientQuery<any, any, any, any>
> extends QueryBuilder<CQ> {
constructor(query: CQ) {
super(query);
}

syncStatus(status: SyncStatus) {
this.query.syncStatus = status;
return this as ClientQueryBuilderClass<M, CN, CQ>;
return this as ClientQueryBuilder<CQ>;
}
}

export function ClientQueryBuilder<
export type ClientQueryDefault<
M extends ClientSchema | undefined,
CN extends CollectionNameFromModels<M>
> = ClientQuery<M, CN, QuerySelectionValue<M, CN>, {}>;

export function clientQueryBuilder<
M extends ClientSchema | undefined,
CN extends CollectionNameFromModels<M>
>(collectionName: CN, params?: Omit<ClientQuery<M, CN>, 'collectionName'>) {
const query: ClientQuery<M, CN> = {
const query = {
collectionName,
...params,
};
return new ClientQueryBuilderClass<
M,
CN,
ClientQuery<M, CN, QuerySelectionValue<M, CN>, {}>
>(query);
return new ClientQueryBuilder<ClientQueryDefault<M, CN>>(query);
}

export class RemoteClientQueryBuilder<
CQ extends CollectionQuery<any, any, any, any>
> extends QueryBuilder<CQ> {
constructor(query: CQ) {
super(query);
}
}

export function RemoteClientQueryBuilder<
export function remoteClientQueryBuilder<
M extends ClientSchema | undefined,
CN extends CollectionNameFromModels<M>
// syncStatus doesn't apply for the remote client
Expand All @@ -95,19 +101,11 @@ export function RemoteClientQueryBuilder<
collectionName,
...params,
};
return new QueryBuilder<M, CN, CollectionQuery<M, CN>>(query);
return new QueryBuilder<
CollectionQuery<M, CN, QuerySelectionValue<M, CN>, {}>
>(query);
}

export type ClientQueryBuilder<
M extends ClientSchema | undefined,
CN extends CollectionNameFromModels<M>
> = ReturnType<typeof ClientQueryBuilder<M, CN>>;

export type RemoteClientQueryBuilder<
M extends ClientSchema | undefined,
CN extends CollectionNameFromModels<M>
> = ReturnType<typeof RemoteClientQueryBuilder<M, CN>>;

export function prepareFetchOneQuery<CQ extends ClientQuery<any, any>>(
query: CQ
): CQ {
Expand All @@ -117,12 +115,8 @@ export function prepareFetchOneQuery<CQ extends ClientQuery<any, any>>(
export function prepareFetchByIdQuery<
M extends ClientSchema | undefined,
CN extends CollectionNameFromModels<M>
>(
collectionName: CN,
id: string,
queryParams?: FetchByIdQueryParams<M, CN>
): ClientQuery<M, CN> {
let query = ClientQueryBuilder(collectionName).entityId(id);
>(collectionName: CN, id: string, queryParams?: FetchByIdQueryParams<M, CN>) {
let query = clientQueryBuilder<M, CN>(collectionName).entityId(id);
if (queryParams?.include) {
for (const [relation, subquery] of Object.entries(queryParams.include)) {
if (subquery) {
Expand All @@ -134,5 +128,5 @@ export function prepareFetchByIdQuery<
}
}
}
return query.build() as ClientQuery<M, CN>;
return query.build();
}
5 changes: 3 additions & 2 deletions packages/client/src/worker-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
ClientQuery,
ClientQueryBuilder,
ClientSchema,
clientQueryBuilder,
} from './utils/query.js';
import { ConnectionStatus } from './index.js';

Expand Down Expand Up @@ -53,8 +54,8 @@ export class WorkerClient<M extends ClientSchema | undefined = undefined> {

query<CN extends CollectionNameFromModels<M>>(
collectionName: CN
): ClientQueryBuilder<M, CN> {
return ClientQueryBuilder<M, CN>(collectionName);
): ReturnType<typeof clientQueryBuilder<M, CN>> {
return clientQueryBuilder<M, CN>(collectionName);
}

async fetch<CQ extends ClientQuery<M, any>>(
Expand Down
2 changes: 0 additions & 2 deletions packages/db/src/collection-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ export default function CollectionQueryBuilder<
...params,
};
return new QueryBuilder<
M,
CN,
CollectionQuery<M, CN, QuerySelectionValue<M, CN>, {}>
>(query);
}
Expand Down
33 changes: 21 additions & 12 deletions packages/db/src/query/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import {
QueryClauseFormattingError,
} from '../errors.js';
import {
ExtractCollectionQueryCollectionName,
ExtractCollectionQueryInclusion,
ExtractCollectionQueryModels,
ExtractCollectionQuerySelection,
} from './types';

Expand All @@ -34,10 +36,11 @@ export type BuilderBase<
} & { build: () => T };

export class QueryBuilder<
M extends Models<any, any> | undefined,
CN extends CollectionNameFromModels<M>,
Q extends CollectionQuery<M, CN, any, any>
> implements BuilderBase<CollectionQuery<M, CN>, 'collectionName'>
Q extends CollectionQuery<any, any, any, any>,
M extends Models<any, any> | undefined = ExtractCollectionQueryModels<Q>,
// @ts-expect-error
CN extends CollectionNameFromModels<M> = ExtractCollectionQueryCollectionName<Q>
> implements BuilderBase<CollectionQuery<any, any>, 'collectionName'>
{
protected query: Q;
constructor(query: Q) {
Expand All @@ -55,24 +58,31 @@ export class QueryBuilder<

// TODO: I think this is going to break higher level builders, ensure it doenst (@triplit/react probably has error)
return this as QueryBuilder<
M,
CN,
CollectionQuery<M, CN, Selection, ExtractCollectionQueryInclusion<Q>>
>;
}

where(...args: FilterInput<M, CN, any>) {
this.query = {
...this.query,
where: QUERY_INPUT_TRANSFORMERS<M, CN>().where(this.query, ...args),
where: QUERY_INPUT_TRANSFORMERS<M, CN>().where(
// @ts-expect-error
this.query,
...args
),
};
return this;
}

order(...args: OrderInput<M, CN>) {
this.query = {
...this.query,
order: QUERY_INPUT_TRANSFORMERS<M, CN>().order(this.query, ...args),
order: QUERY_INPUT_TRANSFORMERS<M, CN>().order(
// @ts-expect-error

this.query,
...args
),
};
return this;
}
Expand All @@ -81,6 +91,8 @@ export class QueryBuilder<
this.query = {
...this.query,
after: QUERY_INPUT_TRANSFORMERS<M, CN>().after(
// @ts-expect-error

this.query,
after,
inclusive
Expand All @@ -93,8 +105,6 @@ export class QueryBuilder<
relationName: RName,
query: RelationSubquery<M, any>
): QueryBuilder<
M,
CN,
CollectionQuery<
M,
CN,
Expand All @@ -113,8 +123,6 @@ export class QueryBuilder<
ModelFromModels<M, CN>['properties'][RName]['query']['collectionName']
>
): QueryBuilder<
M,
CN,
CollectionQuery<
M,
CN,
Expand All @@ -129,6 +137,7 @@ export class QueryBuilder<
this.query = {
...this.query,
include: QUERY_INPUT_TRANSFORMERS<M, CN>().include(
// @ts-expect-error
this.query,
relationName,
query
Expand Down
2 changes: 1 addition & 1 deletion packages/db/src/query/types/collection-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type ExtractCollectionQueryModels<Q extends BaseCollectionQuery> =
*/
export type ExtractCollectionQueryCollectionName<
Q extends BaseCollectionQuery
> = Q extends CollectionQuery<any, infer CN, any, any> ? CN : never;
> = Q extends CollectionQuery<infer M, infer CN, any, any> ? CN : never;

/**
* Extracts the selection of a collection query.
Expand Down
13 changes: 7 additions & 6 deletions packages/react/src/use-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
SubscriptionOptions,
ReturnTypeFromQuery,
FetchByIdQueryParams,
ClientQuery,
ClientQueryDefault,
} from '@triplit/client';
import { useQuery } from './use-query.js';

Expand All @@ -22,28 +22,29 @@ export function useEntity<
fetching: boolean;
fetchingRemote: boolean;
fetchingLocal: boolean;
results: ReturnTypeFromQuery<ClientQuery<M, CN>> | undefined;
results: ReturnTypeFromQuery<ClientQueryDefault<M, CN>> | undefined;
error: any;
} {
// @ts-ignore
let query = client.query(collectionName).where('id', '=', id).limit(1);
let builder = client.query(collectionName).where('id', '=', id).limit(1);
if (queryParams?.include) {
for (const [relation, subquery] of Object.entries(queryParams.include)) {
if (subquery) {
// @ts-expect-error
query = query.include(relation, subquery);
builder = builder.include(relation, subquery);
} else {
// @ts-expect-error TODO: fixup builder type
query = query.include(
builder = builder.include(
// @ts-expect-error expecting typed as relationship from schema
relation
);
}
}
}
// const query = builder.build();
const { fetching, fetchingRemote, fetchingLocal, results, error } = useQuery(
client,
query,
builder,
options
);
return {
Expand Down

0 comments on commit f826e50

Please sign in to comment.