Skip to content

Commit

Permalink
types(groq-builder): implemented correct types for root and filterByType
Browse files Browse the repository at this point in the history
  • Loading branch information
scottrippey committed Oct 1, 2023
1 parent 9666711 commit 5e81c85
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 16 deletions.
15 changes: 15 additions & 0 deletions packages/nextjs/sanity-studio/builder/commands/filter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createGroqBuilder } from "../groq-builder";
import { SanitySchemaTypes } from "../../sanity-types";
import { expectType } from "../test-utils/expectType";
import { ExtractScope } from "../common-types";
import { SanitySchemaRaw } from "../../sanity.config";
import { Simplify, SimplifyDeep } from "../type-utils";

const q = createGroqBuilder<SanitySchemaTypes>();

describe("filter", () => {
it("", () => {
const res = q.filterByType("flavour");
expectType<ExtractScope<typeof res>>().toStrictEqual<SanitySchemaRaw["flavour"]>();
});
});
9 changes: 6 additions & 3 deletions packages/nextjs/sanity-studio/builder/commands/filter.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { GroqBuilder } from "../groq-builder";
import { StringKeys } from "../common-types";

declare module "../groq-builder" {
export interface GroqBuilder<TSchema, TScope> {
filter<TScopeNew = TScope>(filterString?: string): GroqBuilder<TSchema, TScopeNew>;
filterByType<TType extends StringKeys<keyof TSchema>>(type: TType): GroqBuilder<TSchema, TSchema[TType]>;
filter<TScopeNew extends TScope = TScope>(filterString?: string): GroqBuilder<TSchema, TScopeNew>;
filterByType<TType extends Extract<MaybeArrayItem<TScope>, { _type: any }>["_type"]>(
type: TType
): GroqBuilder<TSchema, Extract<TScope, { type: TType }>>;
}
}

type MaybeArrayItem<T> = T extends Array<infer TItem> ? TItem : T;

GroqBuilder.implement({
filter(this: GroqBuilder<any, any>, filterString = "") {
return this.extend(`[${filterString}]`, null);
Expand Down
42 changes: 42 additions & 0 deletions packages/nextjs/sanity-studio/builder/commands/grab.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { createGroqBuilder } from "../groq-builder";
import { SanitySchemaTypes } from "../../sanity-types";
import { expectType } from "../test-utils/expectType";
import { ExtractScope } from "../common-types";

const q = createGroqBuilder<SanitySchemaTypes>();

describe("grab", () => {
it("grab one property", () => {
const res = q.filterByType("variant").grab({
name: true,
});

expect(res).toMatchObject({
query: "*[_type == 'variant']{name}",
});

expectType<ExtractScope<typeof res>>().toStrictEqual<{
name: string;
}>();
});

it("grab multiple properties", () => {
const res = q.filterByType("variant").grab({
id: true,
name: true,
price: true,
msrp: true,
});

expect(res).toMatchObject({
query: "*[_type == 'variant']{name,price,id,msrp}",
});

expectType<ExtractScope<typeof res>>().toStrictEqual<{
id: string | undefined;
name: string;
price: number;
msrp: number;
}>();
});
});
33 changes: 22 additions & 11 deletions packages/nextjs/sanity-studio/builder/groq-builder.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import { Parser } from "./common-types";

import "./commands";
import { SimplifyDeep } from "./type-utils";

export function createGroqBuilder<TSchema>() {
return new GroqBuilder<TSchema, TSchema[keyof TSchema]>("", null);
type DocumentTypes = SimplifyDeep<TSchema[keyof TSchema]>;
return new GroqBuilder<TSchema, Array<DocumentTypes>>("", null, null);
}

export class GroqBuilder<TSchema, TScope> {
get TScope(): TScope {
return null as any;
}

/**
* Extends the GroqBuilder class by implementing methods.
* This allows for this class to be split across multiple files in the `./commands/` folder.
* @internal
*/
static implement(methods: Partial<GroqBuilder<any, any>>) {
Object.assign(GroqBuilder.prototype, methods);
}

protected readonly root: GroqBuilder<TSchema, TScope>;
constructor(
/**
*
Expand All @@ -15,23 +31,18 @@ export class GroqBuilder<TSchema, TScope> {
/**
*
*/
protected readonly parser: Parser<any, TScope> | null
) {}
protected readonly parser: Parser<any, TScope> | null,

/**
* Extends the GroqBuilder class by implementing methods.
* This allows for this class to be split across multiple files in the `./commands/` folder.
* @internal
*/
static implement(methods: Partial<GroqBuilder<any, any>>) {
Object.assign(GroqBuilder.prototype, methods);
root: GroqBuilder<any, any> | null
) {
this.root = root || this;
}

/**
* This method is for chaining:
*/
protected extend<TScopeNew>(query: string, parser: Parser<any, any> | null) {
return new GroqBuilder<TSchema, TScopeNew>(this.query + query, parser);
return new GroqBuilder<TSchema, TScopeNew>(this.query + query, parser, this.root);
}

public async execute(fetchData: (query: string) => Promise<unknown>): Promise<TScope> {
Expand Down
5 changes: 5 additions & 0 deletions packages/nextjs/sanity-studio/builder/type-utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
export type Simplify<T> = {
[KeyType in keyof T]: T[KeyType];
} & {};

export type SimplifyDeep<T> = T extends object
? T extends infer O
? { [K in keyof O]: SimplifyDeep<O[K]> }
: never
: T;

export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;

export type Override<T, TOverrides> = Omit<T, keyof TOverrides> & TOverrides;
5 changes: 3 additions & 2 deletions packages/nextjs/sanity-studio/sanity-types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { SanitySchemaRaw } from "./sanity.config";
// import { SimplifyDeep } from "./builder/type-utils";

/** Typescript type of all types! */
export type SanitySchemaTypes = SimplifyDeep<SanitySchemaRaw>;
type SimplifyDeep<T> = T extends object ? (T extends infer O ? { [K in keyof O]: SimplifyDeep<O[K]> } : never) : T;
// export type SanitySchemaTypes = SimplifyDeep<SanitySchemaRaw>;
export type SanitySchemaTypes = SanitySchemaRaw;

0 comments on commit 5e81c85

Please sign in to comment.