Skip to content

Commit

Permalink
feat: Add schema.Query
Browse files Browse the repository at this point in the history
  • Loading branch information
ntucker committed Feb 15, 2024
1 parent dbc825a commit 6430e71
Show file tree
Hide file tree
Showing 22 changed files with 181 additions and 86 deletions.
2 changes: 1 addition & 1 deletion examples/benchmark/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export default function addReducerSuite(suite) {
}
})
.add('getResponse Query-sorted', () => {
return controller.getResponse(ProjectQuerySorted, cachedState);
return controller.query(ProjectQuerySorted, cachedState);
})
.add('getResponse Collection', () => {
return controllerCollection.getResponse(
Expand Down
4 changes: 2 additions & 2 deletions examples/benchmark/schemas.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Entity, schema, Query } from './dist/index.js';
import { Entity, schema } from './dist/index.js';

export class BuildTypeDescription extends Entity {
id = '';
Expand Down Expand Up @@ -100,7 +100,7 @@ export const ProjectSchemaMixin = {
export const ProjectQuery = {
project: new schema.All(ProjectWithBuildTypesDescription),
};
export const ProjectQuerySorted = new Query(
export const ProjectQuerySorted = new schema.Query(
new schema.All(ProjectWithBuildTypesDescription),
entries => {
return [...entries].sort((a, b) => a.internalId - b.internalId);
Expand Down
4 changes: 2 additions & 2 deletions examples/coin-app/src/resources/Currency.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Entity, Query, createResource, schema } from '@data-client/rest';
import { Entity, createResource, schema } from '@data-client/rest';

import { Stats } from './Stats';

Expand Down Expand Up @@ -61,7 +61,7 @@ export const CurrencyResource = createResource({
interface Args {
type?: string;
}
export const queryCurrency = new Query(
export const queryCurrency = new schema.Query(
new schema.All(Currency),
(entries, { type = 'crypto' }: Args) => {
let sorted = entries.filter(
Expand Down
4 changes: 2 additions & 2 deletions examples/coin-app/src/resources/Product.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Entity, Query, createResource, schema } from '@data-client/rest';
import { Entity, createResource, schema } from '@data-client/rest';

import { Stats } from './Stats';

Expand Down Expand Up @@ -34,7 +34,7 @@ export const ProductResource = createResource({
interface Args {
quote_currency?: string;
}
export const queryProduct = new Query(
export const queryProduct = new schema.Query(
new schema.All(Product),
(entries, { quote_currency }: Args) => {
let sorted = entries.filter(product => product.stats);
Expand Down
4 changes: 2 additions & 2 deletions examples/nextjs/resources/TodoResource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Query, schema } from '@data-client/rest';
import { schema } from '@data-client/rest';

import {
createPlaceholderResource,
Expand All @@ -20,7 +20,7 @@ export const TodoResource = createPlaceholderResource({
searchParams: {} as { userId?: string | number } | undefined,
});

export const queryRemainingTodos = new Query(
export const queryRemainingTodos = new schema.Query(
TodoResource.getList.schema,
(entries) => entries && entries.filter((todo) => !todo.completed).length,
);
4 changes: 2 additions & 2 deletions examples/todo-app/src/pages/Home/TodoStats.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useCache } from '@data-client/react';
import { useQuery } from '@data-client/react';
import { queryRemainingTodos } from 'resources/TodoResource';

export default function TodoStats({ userId }: { userId?: number }) {
const remaining = useCache(queryRemainingTodos, { userId });
const remaining = useQuery(queryRemainingTodos, { userId });

return <div>{remaining} tasks remaining</div>;
}
4 changes: 2 additions & 2 deletions examples/todo-app/src/resources/TodoResource.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Query, schema } from '@data-client/rest';
import { schema } from '@data-client/rest';

import {
createPlaceholderResource,
Expand All @@ -20,7 +20,7 @@ export const TodoResource = createPlaceholderResource({
searchParams: {} as { userId?: string | number } | undefined,
});

export const queryRemainingTodos = new Query(
export const queryRemainingTodos = new schema.Query(
TodoResource.getList.schema,
(entries) => entries && entries.filter((todo) => !todo.completed).length,
);
4 changes: 2 additions & 2 deletions examples/todo-app/typetest.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCache, useController, useSuspense } from '@data-client/react';
import { useQuery, useController, useSuspense } from '@data-client/react';

import {
queryRemainingTodos,
Expand All @@ -23,7 +23,7 @@ function useTest() {
);
});

const remaining = useCache(queryRemainingTodos, { userId: 1 });
const remaining = useQuery(queryRemainingTodos, { userId: 1 });

const users = useSuspense(UserResource.getList);
users.map((user) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/controller/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ export default class Controller<
let results;
let resultCache: ResultCache;
if (cacheResults === undefined && endpoint.schema !== undefined) {
if (!this.globalCache.inputEndpointCache[key])
if (!this.globalCache.inputEndpointCache[key] || true)
this.globalCache.inputEndpointCache[key] = inferResults(
endpoint.schema,
args,
Expand Down Expand Up @@ -473,7 +473,7 @@ export default class Controller<
const querySchemaCache = this.globalCache.queries.get(schema) as {
[key: string]: unknown;
};
if (!querySchemaCache[key])
if (!querySchemaCache[key] || true)
querySchemaCache[key] = inferResults(
schema,
args,
Expand Down
1 change: 0 additions & 1 deletion packages/endpoint/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,4 @@ export type {
export { default as Endpoint, ExtendableEndpoint } from './endpoint.js';
export type { KeyofEndpointInstance } from './endpoint.js';
export * from './indexEndpoint.js';
export * from './queryEndpoint.js';
export { default as AbortOptimistic } from './AbortOptimistic.js';
2 changes: 1 addition & 1 deletion packages/endpoint/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type Serializable<
T extends { toJSON(): string } = { toJSON(): string },
> = (value: any) => T;

export interface SchemaSimple<T = any, Args extends any[] = any[]> {
export interface SchemaSimple<T = any, Args extends readonly any[] = any[]> {
normalize(
input: any,
parent: any,
Expand Down
6 changes: 4 additions & 2 deletions packages/endpoint/src/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ import {
PKClass,
} from './schemas/EntitySchema.js';
import { default as Invalidate } from './schemas/Invalidate.js';
import { default as Query } from './schemas/Query.js';
import type {
CollectionConstructor,
SchemaAttributeFunction,
SchemaFunction,
UnionResult,
} from './schemaTypes.js';

export { EntityMap, Invalidate };
export { EntityMap, Invalidate, Query };

export type { SchemaClass };

Expand Down Expand Up @@ -137,7 +138,8 @@ export class All<
): (S extends EntityMap<infer T> ? T : Denormalize<S>)[];

infer(
args: [],
// TODO: hack for now to allow for variable arg combinations with Query
args: [] | [unknown],
indexes: NormalizedIndex,
recurse: (...args: any) => any,
entities: EntityTable,
Expand Down
1 change: 1 addition & 0 deletions packages/endpoint/src/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { default as Object } from './schemas/Object.js';
export { default as Invalidate } from './schemas/Invalidate.js';
export { default as Collection } from './schemas/Collection.js';
export { default as Entity } from './schemas/EntitySchema.js';
export { default as Query } from './schemas/Query.js';
68 changes: 68 additions & 0 deletions packages/endpoint/src/schemas/Query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type {
EntityTable,
NormalizedIndex,
Queryable,
SchemaSimple,
} from '../interface.js';
import type { Denormalize, SchemaArgs } from '../normal.js';

/**
* Programmatic cache reading
* @see https://dataclient.io/rest/api/Query
*/
export default class Query<
S extends Queryable,
P extends (entries: Denormalize<S>, ...args: any) => any = (
entries: Denormalize<S>,
...args: SchemaArgs<S>
) => Denormalize<S>,
> implements SchemaSimple<ReturnType<P> | undefined, ProcessParameters<P, S>>
{
declare schema: S;
declare process: P;
declare thingy: ProcessParameters<P, S>;

constructor(schema: S, process?: P) {
this.schema = schema;
if (process) this.process = process;
// allows for inheritance overrides
else if (!this.process)
this.process = ((entries: Denormalize<S>) => entries) as any;
}

normalize(...args: any) {
return (this.schema as any).normalize(...args);
}

denormalize(input: {}, args: any, unvisit: any): ReturnType<P> | undefined {
const value = unvisit(input, this.schema);
return typeof value === 'symbol' ? undefined : this.process(value, ...args);
}

infer(
args: ProcessParameters<P, S>,
indexes: any,
recurse: (
schema: any,
args: any,
indexes: NormalizedIndex,
entities: EntityTable,
) => any,
entities: EntityTable,
) {
return recurse(this.schema, args, indexes, entities);
}

declare _denormalizeNullable: (
input: {},
args: readonly any[],
unvisit: (input: any, schema: any) => any,
) => ReturnType<P> | undefined;
}

type ProcessParameters<P, S extends Queryable> =
P extends (entries: any, ...args: infer Par) => any ?
Par extends [] ?
SchemaArgs<S>
: Par & SchemaArgs<S>
: SchemaArgs<S>;
1 change: 0 additions & 1 deletion packages/endpoint/src/schemas/__tests__/Collection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ describe(`${schema.Collection.name} normalization`, () => {
() => undefined,
{},
{},
// @ts-expect-error
[],
);
}
Expand Down
Loading

1 comment on commit 6430e71

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 6430e71 Previous: 5771da3 Ratio
normalizeLong 424 ops/sec (±2.14%) 447 ops/sec (±1.68%) 1.05
infer All 9559 ops/sec (±1.42%) 9629 ops/sec (±1.67%) 1.01
denormalizeLong 216 ops/sec (±3.28%) 321 ops/sec (±2.22%) 1.49
denormalizeLong donotcache 836 ops/sec (±1.39%) 888 ops/sec (±0.46%) 1.06
denormalizeShort donotcache 500x 1339 ops/sec (±0.13%) 1351 ops/sec (±0.13%) 1.01
denormalizeShort 500x 676 ops/sec (±3.01%) 958 ops/sec (±0.24%) 1.42
denormalizeLong with mixin Entity 204 ops/sec (±3.08%) 303 ops/sec (±0.26%) 1.49
denormalizeLong withCache 7251 ops/sec (±0.25%) 6836 ops/sec (±0.26%) 0.94
denormalizeLongAndShort withEntityCacheOnly 1517 ops/sec (±0.45%) 1562 ops/sec (±0.31%) 1.03
denormalizeLong All withCache 5972 ops/sec (±0.49%) 6337 ops/sec (±0.17%) 1.06
denormalizeLong Query-sorted withCache 6401 ops/sec (±0.27%) 6647 ops/sec (±0.38%) 1.04
getResponse 4869 ops/sec (±1.08%) 4951 ops/sec (±0.88%) 1.02
getResponse (null) 2994599 ops/sec (±0.24%) 2888601 ops/sec (±0.21%) 0.96
getResponse (clear cache) 196 ops/sec (±2.78%) 292 ops/sec (±1.10%) 1.49
getSmallResponse 2223 ops/sec (±1.33%) 2328 ops/sec (±0.30%) 1.05
getSmallInferredResponse 1774 ops/sec (±0.33%) 1765 ops/sec (±0.34%) 0.99
getResponse Query-sorted 703 ops/sec (±1.31%) 687 ops/sec (±1.09%) 0.98
getResponse Collection 4966 ops/sec (±1.37%) 5124 ops/sec (±1.06%) 1.03
setLong 416 ops/sec (±2.22%) 437 ops/sec (±2.25%) 1.05
setLongWithMerge 162 ops/sec (±1.34%) 189 ops/sec (±0.36%) 1.17
setLongWithSimpleMerge 188 ops/sec (±0.87%) 202 ops/sec (±0.27%) 1.07

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.