Skip to content

Commit

Permalink
feature(variables): support deeply-nested parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
scottrippey committed Feb 6, 2024
1 parent 2072a0d commit e615ccd
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 22 deletions.
61 changes: 54 additions & 7 deletions packages/groq-builder/src/types/groq-expressions.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, expectTypeOf, it } from "vitest";
import { Expressions } from "./groq-expressions";
import { QueryConfig, RootQueryConfig } from "./schema-types";
import { Simplify } from "./utils";

describe("Expressions", () => {
it("literal values are properly escaped", () => {
Expand Down Expand Up @@ -117,22 +118,30 @@ describe("Expressions", () => {
type ManyParameters = {
str1: string;
str2: string;
num: number;
num1: number;
bool: boolean;
};

it("we can extract parameters based on their type", () => {
type ParameterEntries = Expressions.ParameterEntries<ManyParameters>;
expectTypeOf<Simplify<ParameterEntries>>().toEqualTypeOf<{
$str1: string;
$str2: string;
$num1: number;
$bool: boolean;
}>();

expectTypeOf<
Expressions.ParametersOfType<ManyParameters, string>
Expressions.StringKeysWithType<ParameterEntries, string>
>().toEqualTypeOf<"$str1" | "$str2">();
expectTypeOf<
Expressions.ParametersOfType<ManyParameters, "LITERAL">
Expressions.StringKeysWithType<ParameterEntries, "LITERAL">
>().toEqualTypeOf<"$str1" | "$str2">();
expectTypeOf<
Expressions.ParametersOfType<ManyParameters, number>
>().toEqualTypeOf<"$num">();
Expressions.StringKeysWithType<ParameterEntries, number>
>().toEqualTypeOf<"$num1">();
expectTypeOf<
Expressions.ParametersOfType<ManyParameters, boolean>
Expressions.StringKeysWithType<ParameterEntries, boolean>
>().toEqualTypeOf<"$bool">();
});

Expand All @@ -144,13 +153,51 @@ describe("Expressions", () => {
| "foo == $str2"
| "foo == (string)"
| `foo == "${string}"`
| "bar == $num"
| "bar == $num1"
| "bar == (number)"
| `bar == ${number}`
| "baz == $bool"
| "baz == true"
| "baz == false"
>();
});

type NestedParameters = {
nested: {
str1: string;
deep: {
str2: string;
num1: number;
};
};
};
it("should work with deeply-nested parameters", () => {
type Item = { foo: string; bar: number; baz: boolean };
type Res = Expressions.Equality<Item, WithVars<NestedParameters>>;

type StandardSuggestions =
| `foo == (string)`
| `foo == "${string}"`
| `bar == (number)`
| `bar == ${number}`
| "baz == true"
| "baz == false";
expectTypeOf<Exclude<Res, StandardSuggestions>>().toEqualTypeOf<
| "foo == $nested.str1"
| "foo == $nested.deep.str2"
| "bar == $nested.deep.num1"
>();
});

it("we can extract parameters based on their type", () => {
type ParameterEntries = Expressions.ParameterEntries<NestedParameters>;
expectTypeOf<Simplify<ParameterEntries>>().toEqualTypeOf<{
$nested: NestedParameters["nested"];
"$nested.str1": string;
"$nested.deep": NestedParameters["nested"]["deep"];
"$nested.deep.str2": string;
"$nested.deep.num1": number;
}>();
});
});
});
36 changes: 21 additions & 15 deletions packages/groq-builder/src/types/groq-expressions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { QueryConfig } from "./schema-types";
import type { IsLiteral, LiteralUnion } from "type-fest";
import { UndefinedToNull, ValueOf } from "./utils";
import { StringKeys, UndefinedToNull, ValueOf } from "./utils";
import { Path, PathValue } from "./path-types";

// eslint-disable-next-line @typescript-eslint/no-namespace
Expand Down Expand Up @@ -31,12 +31,13 @@ export namespace Expressions {

export type Equality<
TResultItem,
TQueryConfig extends QueryConfig
TQueryConfig extends QueryConfig,
_ParameterEntries = ParameterEntries<TQueryConfig["parameters"]>
> = ValueOf<{
[Key in SuggestedKeys<TResultItem>]: `${Key} == ${
// First, suggest parameters:
| ParametersOfType<
TQueryConfig["parameters"],
| StringKeysWithType<
_ParameterEntries,
SuggestedKeysValue<TResultItem, Key>
>
// Next, make some literal suggestions:
Expand Down Expand Up @@ -70,15 +71,20 @@ export namespace Expressions {
TKey extends SuggestedKeys<TResultItem>
> = UndefinedToNull<PathValue<TResultItem, TKey>>;

export type ParametersOfType<TParameters, TType> = `$${AsString<
KeysOfType<TParameters, TType>
>}`;
type KeysOfType<TObject, TType> = ValueOf<{
[P in keyof TObject]: TObject[P] extends TType
? P
: TType extends TObject[P]
? P
: never;
}>;
type AsString<T> = Extract<T, string>;
export type ParameterEntries<TParameters> = {
[P in Path<TParameters> as `$${P}`]: PathValue<TParameters, P>;
};

/**
* Finds all (string) keys of TObject where the value matches the given TType
*/
export type StringKeysWithType<TObject, TType> = StringKeys<
ValueOf<{
[P in keyof TObject]: TObject[P] extends TType
? P
: TType extends TObject[P]
? P
: never;
}>
>;
}

0 comments on commit e615ccd

Please sign in to comment.