From 00716340ac84de64fa36e5ffd95dcb1e4abd2790 Mon Sep 17 00:00:00 2001 From: scottrippey Date: Sun, 1 Oct 2023 07:55:03 -0600 Subject: [PATCH] types(groq-builder): use TRootConfig instead of TSchema --- .../sanity-studio/builder/commands/deref.ts | 10 +++---- .../sanity-studio/builder/commands/field.ts | 10 ++++--- .../builder/commands/filter.test.ts | 30 +++++++++++++++---- .../sanity-studio/builder/commands/filter.ts | 11 ++++--- .../builder/commands/grab.test.ts | 4 +-- .../sanity-studio/builder/commands/grab.ts | 6 ++-- .../sanity-studio/builder/common-types.ts | 28 ++++++++--------- .../builder/groq-builder.test.ts | 4 +-- .../sanity-studio/builder/groq-builder.ts | 15 ++++++---- .../builder/test-utils/expectType.ts | 2 ++ .../sanity-studio/builder/type-utils.ts | 7 +++++ packages/nextjs/sanity-studio/sanity-types.ts | 3 ++ 12 files changed, 82 insertions(+), 48 deletions(-) diff --git a/packages/nextjs/sanity-studio/builder/commands/deref.ts b/packages/nextjs/sanity-studio/builder/commands/deref.ts index 7ef5f939..441b5ebf 100644 --- a/packages/nextjs/sanity-studio/builder/commands/deref.ts +++ b/packages/nextjs/sanity-studio/builder/commands/deref.ts @@ -1,16 +1,16 @@ -import { GroqBuilder } from "../groq-builder"; +import { GroqBuilder, RootConfig } from "../groq-builder"; import { ExtractRefType } from "../common-types"; declare module "../groq-builder" { - export interface GroqBuilder { + export interface GroqBuilder { deref(): TScope extends Array - ? Array> - : ExtractRefType; + ? Array> + : ExtractRefType; } } GroqBuilder.implement({ - deref(this: GroqBuilder): any { + deref(this: GroqBuilder): any { return this.extend("->", null); }, }); diff --git a/packages/nextjs/sanity-studio/builder/commands/field.ts b/packages/nextjs/sanity-studio/builder/commands/field.ts index 66231e4f..9d99d04a 100644 --- a/packages/nextjs/sanity-studio/builder/commands/field.ts +++ b/packages/nextjs/sanity-studio/builder/commands/field.ts @@ -1,10 +1,12 @@ -import { GroqBuilder } from "../groq-builder"; +import { GroqBuilder, RootConfig } from "../groq-builder"; import { StringKeys } from "../common-types"; declare module "../groq-builder" { - export interface GroqBuilder { - field(all: "*"): GroqBuilder; - field>(fieldName: TFieldName): GroqBuilder; + export interface GroqBuilder { + field(all: "*"): GroqBuilder; + field>( + fieldName: TFieldName + ): GroqBuilder; } } diff --git a/packages/nextjs/sanity-studio/builder/commands/filter.test.ts b/packages/nextjs/sanity-studio/builder/commands/filter.test.ts index 5f04ee46..7760223d 100644 --- a/packages/nextjs/sanity-studio/builder/commands/filter.test.ts +++ b/packages/nextjs/sanity-studio/builder/commands/filter.test.ts @@ -1,15 +1,33 @@ import { createGroqBuilder } from "../groq-builder"; -import { SanitySchemaTypes } from "../../sanity-types"; +import { SanitySchemaTypes, SchemaConfig } 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(); +const q = createGroqBuilder(); describe("filter", () => { it("", () => { - const res = q.filterByType("flavour"); - expectType>().toStrictEqual(); + const res = q.filter(); + expectType().toStrictEqual(); + expect(q).toMatchObject({ + query: `[]`, + }); + }); + it("", () => { + const res = q.filter(`_type == 'flavour'`); + expectType().toStrictEqual(); + expect(q).toMatchObject({ + query: `[_type == 'flavour']`, + }); + }); +}); + +describe("filterByType", () => { + it("", () => { + const res = q.field("*").filterByType("flavour"); + expectType>().toStrictEqual>(); + expect(q).toMatchObject({ + query: `*[_type == 'flavour']`, + }); }); }); diff --git a/packages/nextjs/sanity-studio/builder/commands/filter.ts b/packages/nextjs/sanity-studio/builder/commands/filter.ts index 86f2123b..a08b9735 100644 --- a/packages/nextjs/sanity-studio/builder/commands/filter.ts +++ b/packages/nextjs/sanity-studio/builder/commands/filter.ts @@ -1,16 +1,15 @@ import { GroqBuilder } from "../groq-builder"; +import { ArrayItem } from "../type-utils"; declare module "../groq-builder" { - export interface GroqBuilder { - filter(filterString?: string): GroqBuilder; - filterByType, { _type: any }>["_type"]>( + export interface GroqBuilder { + filter(filterString?: string): GroqBuilder; + filterByType, { _type: any }>["_type"]>( type: TType - ): GroqBuilder>; + ): GroqBuilder, { _type: TType }>>, TRootConfig>; } } -type MaybeArrayItem = T extends Array ? TItem : T; - GroqBuilder.implement({ filter(this: GroqBuilder, filterString = "") { return this.extend(`[${filterString}]`, null); diff --git a/packages/nextjs/sanity-studio/builder/commands/grab.test.ts b/packages/nextjs/sanity-studio/builder/commands/grab.test.ts index 3ada391f..a114499b 100644 --- a/packages/nextjs/sanity-studio/builder/commands/grab.test.ts +++ b/packages/nextjs/sanity-studio/builder/commands/grab.test.ts @@ -1,9 +1,9 @@ import { createGroqBuilder } from "../groq-builder"; -import { SanitySchemaTypes } from "../../sanity-types"; +import { SchemaConfig } from "../../sanity-types"; import { expectType } from "../test-utils/expectType"; import { ExtractScope } from "../common-types"; -const q = createGroqBuilder(); +const q = createGroqBuilder(); describe("grab", () => { it("grab one property", () => { diff --git a/packages/nextjs/sanity-studio/builder/commands/grab.ts b/packages/nextjs/sanity-studio/builder/commands/grab.ts index 82c84dae..33fd851f 100644 --- a/packages/nextjs/sanity-studio/builder/commands/grab.ts +++ b/packages/nextjs/sanity-studio/builder/commands/grab.ts @@ -3,14 +3,14 @@ import { GroqBuilder } from "../groq-builder"; import { ExpectedTypeError, Parser } from "../common-types"; declare module "../groq-builder" { - export interface GroqBuilder { + export interface GroqBuilder { grab< TGrab extends { [P in keyof TScope & string]?: GrabFieldConfig; } >( grab: TGrab - ): GroqBuilder>>; + ): GroqBuilder>, TRootConfig>; } export type GrabFieldConfig = true | Parser | GroqBuilder; @@ -18,7 +18,7 @@ declare module "../groq-builder" { export type ExtractGrabResult = { [P in keyof TGrab /* Extract type from GroqBuilder: - */]: TGrab[P] extends GroqBuilder + */]: TGrab[P] extends GroqBuilder ? TValue : /* Extract type from 'true': */ TGrab[P] extends boolean diff --git a/packages/nextjs/sanity-studio/builder/common-types.ts b/packages/nextjs/sanity-studio/builder/common-types.ts index bb7aea75..3a1d0ed3 100644 --- a/packages/nextjs/sanity-studio/builder/common-types.ts +++ b/packages/nextjs/sanity-studio/builder/common-types.ts @@ -1,6 +1,4 @@ -import { GroqBuilder } from "./groq-builder"; - -export declare const _referenced: unique symbol; +import { GroqBuilder, RootConfig } from "./groq-builder"; /** * A generic "parser" which can take any input and output a parsed type. @@ -8,17 +6,19 @@ export declare const _referenced: unique symbol; */ export type Parser = { parse(input: TInput): TOutput }; -export type RefType = { - [_referenced]: TType; +export type RefType = { + [P in referencedSymbol]: TType; }; -export type ExtractRefType = TScope extends RefType - ? Get - : ExpectError<{ - Error: "Expected the object to be a reference type"; - Expected: RefType; - Actual: TScope; - }>; +export type ExtractRefType = + // + TScope extends RefType + ? Get + : ExpectError<{ + Error: "Expected the object to be a reference type"; + Expected: RefType; + Actual: TScope; + }>; export type Get = TKey extends keyof TObj ? TObj[TKey] @@ -33,8 +33,8 @@ export type ExpectError = Exclude; export type ExtractScope> = TGroqBuilder extends GroqBuilder< - any, - infer TScope + infer TScope, + infer TRootConfig > ? TScope : never; diff --git a/packages/nextjs/sanity-studio/builder/groq-builder.test.ts b/packages/nextjs/sanity-studio/builder/groq-builder.test.ts index 8b25444e..1c6ae650 100644 --- a/packages/nextjs/sanity-studio/builder/groq-builder.test.ts +++ b/packages/nextjs/sanity-studio/builder/groq-builder.test.ts @@ -1,6 +1,6 @@ import { createGroqBuilder } from "./groq-builder"; -import { SanitySchemaTypes } from "../sanity-types"; -const q = createGroqBuilder(); +import { SchemaConfig } from "../sanity-types"; +const q = createGroqBuilder(); describe("filterByType", () => { it("", () => { diff --git a/packages/nextjs/sanity-studio/builder/groq-builder.ts b/packages/nextjs/sanity-studio/builder/groq-builder.ts index b598f303..31f93c47 100644 --- a/packages/nextjs/sanity-studio/builder/groq-builder.ts +++ b/packages/nextjs/sanity-studio/builder/groq-builder.ts @@ -3,12 +3,15 @@ import { Parser } from "./common-types"; import "./commands"; import { SimplifyDeep } from "./type-utils"; -export function createGroqBuilder() { - type DocumentTypes = SimplifyDeep; - return new GroqBuilder>("", null, null); +export type RootConfig = { TSchema: any; referenced: symbol }; + +export function createGroqBuilder() { + type TSchema = TRootConfig["TSchema"]; + type RootDocumentTypes = Array>; + return new GroqBuilder("", null, null); } -export class GroqBuilder { +export class GroqBuilder { get TScope(): TScope { return null as any; } @@ -22,7 +25,7 @@ export class GroqBuilder { Object.assign(GroqBuilder.prototype, methods); } - protected readonly root: GroqBuilder; + protected readonly root: GroqBuilder; constructor( /** * @@ -42,7 +45,7 @@ export class GroqBuilder { * This method is for chaining: */ protected extend(query: string, parser: Parser | null) { - return new GroqBuilder(this.query + query, parser, this.root); + return new GroqBuilder(this.query + query, parser, this.root); } public async execute(fetchData: (query: string) => Promise): Promise { diff --git a/packages/nextjs/sanity-studio/builder/test-utils/expectType.ts b/packages/nextjs/sanity-studio/builder/test-utils/expectType.ts index 57aec62b..24c212c6 100644 --- a/packages/nextjs/sanity-studio/builder/test-utils/expectType.ts +++ b/packages/nextjs/sanity-studio/builder/test-utils/expectType.ts @@ -4,6 +4,7 @@ export type IsEqual = (() => G extends A ? 1 : 2) extends () => G ex // declare const RECEIVED: unique symbol; +declare const EXPECTED: unique symbol; type Negate = Value extends true ? false : true; @@ -76,6 +77,7 @@ type TypeMatchers = { Expected extends IsEqual extends Negate ? any : { + [EXPECTED]: Expected; [RECEIVED]: Received; } >( diff --git a/packages/nextjs/sanity-studio/builder/type-utils.ts b/packages/nextjs/sanity-studio/builder/type-utils.ts index 6a35f542..5dfbde46 100644 --- a/packages/nextjs/sanity-studio/builder/type-utils.ts +++ b/packages/nextjs/sanity-studio/builder/type-utils.ts @@ -1,3 +1,5 @@ +import { ExpectedTypeError } from "./common-types"; + export type Simplify = { [KeyType in keyof T]: T[KeyType]; } & {}; @@ -11,3 +13,8 @@ export type SimplifyDeep = T extends object export type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; export type Override = Omit & TOverrides; + +export type MaybeArrayItem = T extends Array ? TItem : T; +export type ArrayItem = T extends Array + ? TItem + : ExpectedTypeError<{ error: "Expected an array"; expected: Array; actual: T }>; diff --git a/packages/nextjs/sanity-studio/sanity-types.ts b/packages/nextjs/sanity-studio/sanity-types.ts index b1c8d096..ae1413a4 100644 --- a/packages/nextjs/sanity-studio/sanity-types.ts +++ b/packages/nextjs/sanity-studio/sanity-types.ts @@ -1,6 +1,9 @@ import { SanitySchemaRaw } from "./sanity.config"; // import { SimplifyDeep } from "./builder/type-utils"; +import { _referenced } from "@sanity-typed/types"; /** Typescript type of all types! */ // export type SanitySchemaTypes = SimplifyDeep; export type SanitySchemaTypes = SanitySchemaRaw; + +export type SchemaConfig = { TSchema: SanitySchemaRaw; referenced: typeof _referenced };