From b789b282c6b56ebd3f4d0f12a00dbf0c27f7770e Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Fri, 21 Oct 2022 16:07:27 -0700 Subject: [PATCH] Build --- _generate/FILES.ts | 1 + _generate/builders.ts | 12 +- _generate/cli.ts | 69 ++- _generate/codecToType.ts | 148 ------ _generate/commandutil.ts | 4 +- _generate/edgeql-js.ts | 226 +++++++++- _generate/edgeql-js/generateCastMaps.ts | 26 +- _generate/edgeql-js/generateFunctionTypes.ts | 20 +- _generate/edgeql-js/generateGlobals.ts | 10 +- _generate/edgeql-js/generateIndex.ts | 139 ++++++ _generate/edgeql-js/generateInterfaces.ts | 202 +++++++++ _generate/edgeql-js/generateObjectTypes.ts | 347 +++++++------- _generate/edgeql-js/generateOperatorTypes.ts | 43 +- _generate/edgeql-js/generateRuntimeSpec.ts | 10 +- _generate/edgeql-js/generateScalars.ts | 6 +- _generate/edgeql-js/generateSetImpl.ts | 15 +- _generate/funcoputil.ts | 9 +- _generate/generate.ts | 447 ------------------- _generate/genutil.ts | 101 ++++- _generate/interfaces.ts | 79 ++++ _generate/prettyPrint.ts | 68 --- _generate/queries.ts | 54 ++- generate.ts | 2 +- 23 files changed, 1078 insertions(+), 960 deletions(-) create mode 100644 _generate/FILES.ts delete mode 100644 _generate/codecToType.ts create mode 100644 _generate/edgeql-js/generateIndex.ts create mode 100644 _generate/edgeql-js/generateInterfaces.ts delete mode 100644 _generate/generate.ts create mode 100644 _generate/interfaces.ts delete mode 100644 _generate/prettyPrint.ts diff --git a/_generate/FILES.ts b/_generate/FILES.ts new file mode 100644 index 0000000..d6a04fa --- /dev/null +++ b/_generate/FILES.ts @@ -0,0 +1 @@ +export const syntax: {[k: string]: {path: string; content: string}[]} = {"deno":[{"path":"__spec__.ts","content":"export declare const spec: Map;\n"},{"path":"cardinality.ts","content":"import {Cardinality} from \"edgedb/_src/reflection/index.ts\";\nimport type {TypeSet} from \"./typesystem.ts\";\n\n// Computing cardinality of path\n// From base set cadinality and pointer cardinality\n// Used in path expressions\n// Cardinality Empty AtMostOne One Many AtLeastOne\n// Empty 0 0 0 0 0\n// AtMostOne 0 AtMostOne AtMostOne Many Many\n// One 0 AtMostOne One Many AtLeastOne\n// Many 0 Many Many Many Many\n// AtLeastOne 0 Many AtLeastOne Many AtLeastOne\nexport namespace cardutil {\n export type multiplyCardinalities<\n C1 extends Cardinality,\n C2 extends Cardinality\n > = C1 extends Cardinality.Empty\n ? Cardinality.Empty\n : C1 extends Cardinality.One\n ? C2\n : C1 extends Cardinality.AtMostOne\n ? C2 extends Cardinality.One\n ? Cardinality.AtMostOne\n : C2 extends Cardinality.AtLeastOne\n ? Cardinality.Many\n : C2\n : C1 extends Cardinality.Many\n ? C2 extends Cardinality.Empty\n ? Cardinality.Empty\n : Cardinality.Many\n : C1 extends Cardinality.AtLeastOne\n ? C2 extends Cardinality.AtMostOne\n ? Cardinality.Many\n : C2 extends Cardinality.One\n ? Cardinality.AtLeastOne\n : C2\n : never;\n\n export function multiplyCardinalities(\n c1: Cardinality,\n c2: Cardinality\n ): Cardinality {\n if (c1 === Cardinality.Empty) return Cardinality.Empty;\n\n if (c1 === Cardinality.One) return c2;\n if (c1 === Cardinality.AtMostOne) {\n if (c2 === Cardinality.One) return Cardinality.AtMostOne;\n if (c2 === Cardinality.AtLeastOne) return Cardinality.Many;\n return c2;\n }\n if (c1 === Cardinality.Many) {\n if (c2 === Cardinality.Empty) return Cardinality.Empty;\n return Cardinality.Many;\n }\n if (c1 === Cardinality.AtLeastOne) {\n if (c2 === Cardinality.AtMostOne) return Cardinality.Many;\n if (c2 === Cardinality.One) return Cardinality.AtLeastOne;\n return c2;\n }\n throw new Error(`Invalid Cardinality ${c1}`);\n }\n\n type _multiplyCardinalitiesVariadic<\n Cards extends [Cardinality, ...Cardinality[]]\n > = Cards extends [infer Card]\n ? Card\n : Cards extends [infer A, infer B, ...infer Rest]\n ? A extends Cardinality\n ? B extends Cardinality\n ? Rest extends Cardinality[]\n ? multiplyCardinalities extends Cardinality\n ? _multiplyCardinalitiesVariadic<\n [multiplyCardinalities, ...Rest]\n >\n : never\n : never\n : never\n : never\n : never;\n\n export type multiplyCardinalitiesVariadic<\n Cards extends [Cardinality, ...Cardinality[]]\n > = _multiplyCardinalitiesVariadic extends Cardinality\n ? _multiplyCardinalitiesVariadic\n : never;\n\n export function multiplyCardinalitiesVariadic<\n Cards extends [Cardinality, ...Cardinality[]]\n >(cards: Cards): multiplyCardinalitiesVariadic {\n if (cards.length === 0) throw new Error(\"Empty tuple not allowed\");\n if (cards.length === 1) return cards[0] as any;\n return cards.reduce(\n (product, card) => multiplyCardinalities(product, card),\n Cardinality.One\n ) as any;\n }\n\n // Merging two sets\n // Used in set constructor\n // Cardinality Empty AtMostOne One Many AtLeastOne\n // Empty Empty AtMostOne One Many AtLeastOne\n // AtMostOne AtMostOne Many AtLeastOne Many AtLeastOne\n // One One AtLeastOne AtLeastOne AtLeastOne AtLeastOne\n // Many Many Many AtLeastOne Many AtLeastOne\n // AtLeastOne AtLeastOne AtLeastOne AtLeastOne AtLeastOne AtLeastOne\n\n export type mergeCardinalities<\n A extends Cardinality,\n B extends Cardinality\n > = A extends Cardinality.Empty\n ? B\n : B extends Cardinality.Empty\n ? A\n : A extends Cardinality.AtLeastOne\n ? Cardinality.AtLeastOne\n : B extends Cardinality.AtLeastOne\n ? Cardinality.AtLeastOne\n : A extends Cardinality.One\n ? Cardinality.AtLeastOne\n : B extends Cardinality.One\n ? Cardinality.AtLeastOne\n : Cardinality.Many;\n\n export function mergeCardinalities<\n A extends Cardinality,\n B extends Cardinality\n >(a: A, b: B): mergeCardinalities {\n if (a === Cardinality.Empty) return b as any;\n if (b === Cardinality.Empty) return a as any;\n if (a === Cardinality.AtLeastOne) return Cardinality.AtLeastOne as any;\n if (b === Cardinality.AtLeastOne) return Cardinality.AtLeastOne as any;\n if (a === Cardinality.One) return Cardinality.AtLeastOne as any;\n if (b === Cardinality.One) return Cardinality.AtLeastOne as any;\n return Cardinality.Many as any;\n }\n\n type _mergeCardinalitiesVariadic<\n Cards extends [Cardinality, ...Cardinality[]]\n > = Cards extends [infer Card]\n ? Card\n : Cards extends [infer A, infer B, ...infer Rest]\n ? A extends Cardinality\n ? B extends Cardinality\n ? Rest extends Cardinality[]\n ? mergeCardinalities extends Cardinality\n ? _mergeCardinalitiesVariadic<[mergeCardinalities, ...Rest]>\n : never\n : never\n : never\n : never\n : never;\n\n export type mergeCardinalitiesVariadic<\n Cards extends [Cardinality, ...Cardinality[]]\n > = _mergeCardinalitiesVariadic extends Cardinality\n ? _mergeCardinalitiesVariadic\n : never;\n export function mergeCardinalitiesVariadic<\n Cards extends [Cardinality, ...Cardinality[]]\n >(cards: Cards): mergeCardinalitiesVariadic {\n if (cards.length === 0) throw new Error(\"Empty tuple not allowed\");\n if (cards.length === 1) return cards[0] as any;\n const [first, second, ...rest] = cards;\n if (cards.length === 2) return mergeCardinalities(first, second) as any;\n return mergeCardinalitiesVariadic([\n mergeCardinalities(first, second),\n ...rest\n ]);\n }\n\n // 'or' cardinalities together\n // used in the IF ELSE operator, for expr (a IF bool ELSE b)\n // result cardinality is 'a' cardinality *or* 'b' cardinality\n // Cardinality Empty AtMostOne One Many AtLeastOne\n // Empty 0 AtMostOne AtMostOne Many Many\n // AtMostOne AtMostOne AtMostOne AtMostOne Many Many\n // One AtMostOne AtMostOne One Many AtLeastOne\n // Many Many Many Many Many Many\n // AtLeastOne Many Many AtLeastOne Many AtLeastOne\n\n export type orCardinalities<\n C1 extends Cardinality,\n C2 extends Cardinality\n > = C1 extends C2\n ? C1\n : C1 extends Cardinality.Many\n ? C1\n : C1 extends Cardinality.AtMostOne\n ? C2 extends Cardinality.Many\n ? C2\n : C2 extends Cardinality.AtLeastOne\n ? Cardinality.Many\n : C1\n : C1 extends Cardinality.AtLeastOne\n ? C2 extends Cardinality.One\n ? Cardinality.AtLeastOne\n : Cardinality.Many\n : C1 extends Cardinality.Empty\n ? C2 extends Cardinality.AtMostOne\n ? Cardinality.AtMostOne\n : C2 extends Cardinality.One\n ? Cardinality.AtMostOne\n : Cardinality.Many\n : C2 extends Cardinality.Empty\n ? Cardinality.AtMostOne\n : C2;\n\n export function orCardinalities(\n c1: Cardinality,\n c2: Cardinality\n ): Cardinality {\n if (c1 === c2 || c1 === Cardinality.Many) return c1;\n if (c1 === Cardinality.AtLeastOne) {\n if (c2 === Cardinality.One) return Cardinality.AtLeastOne;\n return Cardinality.Many;\n }\n if (c1 === Cardinality.AtMostOne) {\n if (c2 === Cardinality.Many || c2 === Cardinality.AtLeastOne) {\n return Cardinality.Many;\n }\n return c1;\n }\n if (c1 === Cardinality.Empty) {\n if (c2 === Cardinality.AtMostOne || c2 === Cardinality.One) {\n return Cardinality.AtMostOne;\n }\n return Cardinality.Many;\n }\n if (c2 === Cardinality.Empty) return Cardinality.AtMostOne;\n return c2;\n }\n\n // Empty AtMostOne One Many AtLeastOne\n // One One One One AtLeastOne AtLeastOne\n // Zero 0 AtMostOne AtMostOne Many Many\n\n export type overrideLowerBound<\n C extends Cardinality,\n O extends \"One\" | \"Zero\"\n > = O extends \"One\"\n ? C extends Cardinality.Many\n ? Cardinality.AtLeastOne\n : C extends Cardinality.AtLeastOne\n ? Cardinality.AtLeastOne\n : Cardinality.One\n : C extends Cardinality.Empty\n ? Cardinality.Empty\n : C extends Cardinality.Many\n ? Cardinality.Many\n : C extends Cardinality.AtLeastOne\n ? Cardinality.Many\n : Cardinality.AtMostOne;\n\n export function overrideLowerBound<\n C extends Cardinality,\n O extends \"One\" | \"Zero\"\n >(card: C, override: O): overrideLowerBound {\n if (override === \"One\") {\n if (card === Cardinality.Many || card === Cardinality.AtLeastOne) {\n return Cardinality.AtLeastOne as any;\n } else {\n return Cardinality.One as any;\n }\n } else {\n if (card === Cardinality.Many || card === Cardinality.AtLeastOne) {\n return Cardinality.Many as any;\n } else if (card === Cardinality.Empty) {\n return Cardinality.Empty as any;\n } else {\n return Cardinality.AtMostOne as any;\n }\n }\n }\n\n // Empty AtMostOne One Many AtLeastOne\n // One AtMostOne AtMostOne One AtMostOne One\n // Many Many Many AtLeastOne Many AtLeastOne\n\n export type overrideUpperBound<\n C extends Cardinality,\n O extends \"One\" | \"Many\"\n > = O extends \"One\"\n ? C extends Cardinality.Many\n ? Cardinality.AtMostOne\n : C extends Cardinality.AtLeastOne\n ? Cardinality.One\n : C extends Cardinality.Empty\n ? Cardinality.AtMostOne\n : C\n : C extends Cardinality.One\n ? Cardinality.AtLeastOne\n : C extends Cardinality.AtMostOne\n ? Cardinality.Many\n : C extends Cardinality.Empty\n ? Cardinality.Many\n : C;\n\n export function overrideUpperBound<\n C extends Cardinality,\n O extends \"One\" | \"Many\"\n >(card: C, override: O): overrideUpperBound {\n if (override === \"One\") {\n if (card === Cardinality.One || card === Cardinality.AtLeastOne) {\n return Cardinality.One as any;\n } else {\n return Cardinality.AtMostOne as any;\n }\n } else {\n if (card === Cardinality.One || card === Cardinality.AtLeastOne) {\n return Cardinality.AtLeastOne as any;\n } else {\n return Cardinality.Many as any;\n }\n }\n }\n\n export type paramCardinality

= [P] extends [TypeSet]\n ? // default to one\n // fixes multiplyCardinalities bug for func with optional args\n [Cardinality] extends [P[\"__cardinality__\"]]\n ? Cardinality.One\n : P[\"__cardinality__\"]\n : Cardinality.One;\n\n export type optionalParamCardinality

= overrideLowerBound<\n paramCardinality

,\n \"One\"\n >;\n\n type _paramArrayCardinality = {\n [K in keyof T]: T[K] extends TypeSet\n ? T[K][\"__cardinality__\"]\n : Cardinality.One;\n };\n\n export type paramArrayCardinality =\n multiplyCardinalitiesVariadic<_paramArrayCardinality>;\n\n export type assignable = C extends Cardinality.Empty\n ? Cardinality.Empty\n : C extends Cardinality.One\n ? Cardinality.One\n : C extends Cardinality.AtMostOne\n ? Cardinality.One | Cardinality.AtMostOne | Cardinality.Empty\n : C extends Cardinality.AtLeastOne\n ? Cardinality.One | Cardinality.AtLeastOne | Cardinality.Many\n : C extends Cardinality.Many\n ? Cardinality\n : never;\n}\n"},{"path":"cast.ts","content":"import {ExpressionKind, Cardinality} from \"edgedb/_src/reflection/index.ts\";\nimport type {Expression, BaseType, TypeSet} from \"./typesystem.ts\";\nimport {$expressionify} from \"./path.ts\";\nimport type {orScalarLiteral} from \"./castMaps.ts\";\nimport {literalToTypeSet} from \"./castMaps.ts\";\n\nexport function cast(\n target: Target,\n arg: null\n): $expr_Cast;\nexport function cast(\n target: Target,\n expr: orScalarLiteral\n): $expr_Cast<\n Target,\n Cardinality extends Expr[\"__cardinality__\"]\n ? Cardinality.One\n : Expr[\"__cardinality__\"]\n>;\nexport function cast(target: BaseType, expr: any) {\n const cleanedExpr = expr === null ? null : literalToTypeSet(expr);\n return $expressionify({\n __element__: target,\n __cardinality__:\n cleanedExpr === null ? Cardinality.Empty : cleanedExpr.__cardinality__,\n __expr__: cleanedExpr,\n __kind__: ExpressionKind.Cast\n }) as any;\n}\n\nexport type $expr_Cast<\n Target extends BaseType = BaseType,\n Card extends Cardinality = Cardinality\n> = Expression<{\n __element__: Target;\n __cardinality__: Card;\n __kind__: ExpressionKind.Cast;\n __expr__: TypeSet | null;\n}>;\n"},{"path":"castMaps.ts","content":"export type scalarCastableFrom = any;\nexport type scalarAssignableBy = any;\nexport type orScalarLiteral = any;\nexport type scalarLiterals = any;\nexport type literalToScalarType = any;\ntype literalToTypeSet = any;\nexport type mapLiteralToTypeSet = {\n [k in keyof T]: literalToTypeSet;\n};\ndeclare function literalToTypeSet(t: any): any;\nexport {literalToTypeSet};\nexport declare function isImplicitlyCastableTo(\n from: string,\n to: string\n): boolean;\nexport function getSharedParentScalar(a: any, b: any): any {}\nexport type getSharedParentScalar = any;\n"},{"path":"casting.ts","content":"import type {Cardinality} from \"edgedb/_src/reflection/index.ts\";\nimport type {\n ArrayType,\n BaseType,\n BaseTypeTuple,\n BaseTypeToTsType,\n EnumType,\n LinkDesc,\n NamedTupleType,\n ObjectType,\n ObjectTypeSet,\n PrimitiveTypeSet,\n PropertyDesc,\n ScalarType,\n TupleType,\n TypeSet,\n RangeType\n} from \"./typesystem.ts\";\nimport type {cardutil} from \"./cardinality.ts\";\n\nimport type {scalarCastableFrom, scalarAssignableBy} from \"./castMaps.ts\";\n\nexport type anonymizeObject = ObjectType<\n string,\n T[\"__pointers__\"],\n any\n>;\n\n////////////////\n// ASSIGNABLE\n////////////////\n\ntype assignableTuple = {\n [k in keyof Items]: Items[k] extends BaseType\n ? assignableBy\n : never;\n} extends infer NewItems\n ? NewItems extends BaseTypeTuple\n ? NewItems\n : never\n : never;\n\nexport type assignableBy = T extends ScalarType\n ? scalarAssignableBy\n : T extends ObjectType\n ? anonymizeObject\n : T extends EnumType\n ? T\n : T extends ArrayType\n ? ArrayType>\n : T extends TupleType\n ? TupleType>\n : T extends NamedTupleType\n ? NamedTupleType<{\n [k in keyof T[\"__shape__\"]]: assignableBy;\n }>\n : T extends RangeType\n ? RangeType<\n scalarAssignableBy extends ScalarType\n ? scalarAssignableBy\n : never\n >\n : never;\n\nexport type pointerToAssignmentExpression<\n Pointer extends PropertyDesc | LinkDesc,\n IsSetModifier extends boolean = false\n> = setToAssignmentExpression<\n TypeSet,\n IsSetModifier\n>;\n\nexport type setToAssignmentExpression<\n Set extends TypeSet,\n IsSetModifier extends boolean\n> = [Set] extends [PrimitiveTypeSet]\n ?\n | TypeSet<\n assignableBy,\n cardutil.assignable<\n // Set[\"__cardinality__\"]\n cardutil.overrideLowerBound\n >\n >\n | getAssignmentLiteral\n : [Set] extends [ObjectTypeSet]\n ? TypeSet<\n ObjectType<\n // anonymize the object type\n string,\n Set[\"__element__\"][\"__pointers__\"]\n >,\n cardutil.assignable<\n // Allow expressions with AtMostOne or Many cardinality in\n // insert/update shape even when link is required since EdgeDB will\n // assert cardinality at runtime\n cardutil.overrideLowerBound\n >\n >\n : never;\n\ntype getAssignmentLiteral<\n Set extends PrimitiveTypeSet,\n IsSetModifier extends boolean\n> = BaseTypeToTsType extends infer TsType\n ?\n | TsType\n | (Set[\"__cardinality__\"] extends Cardinality.Many\n ? TsType[]\n : Set[\"__cardinality__\"] extends Cardinality.AtLeastOne\n ? IsSetModifier extends true\n ? TsType[]\n : [TsType, ...TsType[]]\n : never)\n : never;\n\n////////////////\n// CASTABLES\n////////////////\n\ntype castableTuple = {\n [k in keyof Items]: Items[k] extends BaseType\n ? castableFrom\n : never;\n} extends infer NewItems\n ? NewItems extends BaseTypeTuple\n ? NewItems\n : never\n : never;\n\nexport type castableFrom = T extends ScalarType\n ? scalarCastableFrom\n : T extends ObjectType\n ? anonymizeObject\n : T extends ArrayType\n ? ArrayType>\n : T extends TupleType\n ? TupleType>\n : T extends NamedTupleType\n ? NamedTupleType<{\n [k in keyof T[\"__shape__\"]]: castableFrom;\n }>\n : never;\n\nexport type pointerToCastableExpression<\n Pointer extends PropertyDesc | LinkDesc\n> = [Pointer] extends [PropertyDesc]\n ? {\n __element__: castableFrom;\n __cardinality__: cardutil.assignable;\n }\n : [Pointer] extends [LinkDesc]\n ? TypeSet<\n ObjectType<\n // anonymize the object type\n string,\n Pointer[\"target\"][\"__pointers__\"]\n >,\n cardutil.assignable\n >\n : never;\n"},{"path":"collections.ts","content":"import {\n Cardinality,\n ExpressionKind,\n TypeKind,\n typeutil\n} from \"edgedb/_src/reflection/index.ts\";\nimport {cardutil} from \"./cardinality.ts\";\nimport type {\n $expr_Array,\n $expr_NamedTuple,\n $expr_Tuple,\n $expr_TuplePath,\n ArrayType,\n BaseType,\n getPrimitiveBaseType,\n NamedTupleLiteralShape,\n NamedTupleShape,\n NamedTupleType,\n NonArrayType,\n TupleType,\n TypeSet\n} from \"./typesystem.ts\";\n\nimport {$expressionify, ExpressionRoot} from \"./path.ts\";\nimport type {getCardsFromExprs} from \"./set.ts\";\nimport {\n literalToScalarType,\n literalToTypeSet,\n mapLiteralToTypeSet,\n orScalarLiteral,\n scalarLiterals\n} from \"./castMaps.ts\";\n\nconst indexSliceRegx = /^(-?\\d+)(?:(:)(-?\\d+)?)?|:(-?\\d+)$/;\n\nconst arrayLikeProxyHandlers: ProxyHandler = {\n get(target: ExpressionRoot, prop: string | symbol, proxy: any) {\n const match = typeof prop === \"string\" ? prop.match(indexSliceRegx) : null;\n if (match) {\n const start = match[1];\n const end = match[3] ?? match[4];\n const isIndex = start && !match[2];\n return $expressionify({\n __kind__: ExpressionKind.Operator,\n __element__:\n target.__element__.__kind__ === TypeKind.array && isIndex\n ? (target.__element__ as ArrayType).__element__\n : target.__element__,\n __cardinality__: target.__cardinality__,\n __name__: \"[]\",\n __opkind__: \"Infix\",\n __args__: [\n proxy,\n isIndex\n ? literalToTypeSet(Number(start))\n : [\n start && literalToTypeSet(Number(start)),\n end && literalToTypeSet(Number(end))\n ]\n ]\n }) as any;\n }\n return (target as any)[prop];\n }\n};\n\nfunction arrayLikeIndex(this: ExpressionRoot, index: any) {\n const indexTypeSet = literalToTypeSet(index);\n return $expressionify({\n __kind__: ExpressionKind.Operator,\n __element__:\n this.__element__.__kind__ === TypeKind.array\n ? (this.__element__ as ArrayType).__element__\n : this.__element__,\n __cardinality__: cardutil.multiplyCardinalities(\n this.__cardinality__,\n indexTypeSet.__cardinality__\n ),\n __name__: \"[]\",\n __opkind__: \"Infix\",\n __args__: [this, indexTypeSet]\n }) as any;\n}\n\nfunction arrayLikeSlice(this: ExpressionRoot, start: any, end: any) {\n const startTypeSet = start && literalToTypeSet(start);\n const endTypeSet = end && literalToTypeSet(end);\n return $expressionify({\n __kind__: ExpressionKind.Operator,\n __element__: this.__element__,\n __cardinality__: cardutil.multiplyCardinalities(\n cardutil.multiplyCardinalities(\n this.__cardinality__,\n startTypeSet?.__cardinality__ ?? Cardinality.One\n ),\n endTypeSet?.__cardinality__ ?? Cardinality.One\n ),\n __name__: \"[]\",\n __opkind__: \"Infix\",\n __args__: [this, [startTypeSet, endTypeSet]]\n }) as any;\n}\n\nexport function $arrayLikeIndexify(_expr: ExpressionRoot) {\n if (\n _expr.__element__.__kind__ === TypeKind.array ||\n (_expr.__element__.__kind__ === TypeKind.scalar &&\n (_expr.__element__.__name__ === \"std::str\" ||\n _expr.__element__.__name__ === \"std::bytes\"))\n ) {\n const expr = new Proxy(_expr, arrayLikeProxyHandlers) as any;\n\n expr.index = arrayLikeIndex.bind(expr);\n expr.slice = arrayLikeSlice.bind(expr);\n\n return expr;\n }\n\n return _expr;\n}\n\n// ARRAY\nexport function array(\n element: Element\n): ArrayType;\nexport function array<\n Expr extends TypeSet | scalarLiterals,\n Exprs extends orScalarLiteral<\n TypeSet<\n Expr extends TypeSet\n ? getPrimitiveBaseType\n : getPrimitiveBaseType>\n >\n >[]\n>(\n arg: [Expr, ...Exprs]\n): $expr_Array<\n ArrayType<\n Expr extends TypeSet\n ? getPrimitiveBaseType\n : getPrimitiveBaseType>\n >,\n cardutil.multiplyCardinalitiesVariadic<\n getCardsFromExprs>\n >\n>;\nexport function array(arg: any) {\n if (Array.isArray(arg)) {\n const items = arg.map(a => literalToTypeSet(a));\n return $expressionify({\n __kind__: ExpressionKind.Array,\n __cardinality__: cardutil.multiplyCardinalitiesVariadic(\n items.map(item => item.__cardinality__) as any\n ),\n __element__: {\n __kind__: TypeKind.array,\n __name__: `array<${items[0].__element__.__name__}>`,\n __element__: items[0].__element__\n } as any,\n __items__: items\n });\n }\n if (arg.__kind__) {\n return {\n __kind__: TypeKind.array,\n __name__: `array<${arg.__name__}>`,\n __element__: arg\n } as any;\n }\n\n throw new Error(\"Invalid array input.\");\n}\n\n// TUPLE\n\nconst tupleProxyHandlers: ProxyHandler = {\n get(target: ExpressionRoot, prop: string | symbol, proxy: any) {\n const type = target.__element__;\n const items =\n type.__kind__ === TypeKind.tuple\n ? (type as TupleType).__items__\n : type.__kind__ === TypeKind.namedtuple\n ? (type as NamedTupleType).__shape__\n : null;\n return items?.hasOwnProperty(prop)\n ? tuplePath(proxy, (items as any)[prop], prop as any)\n : (target as any)[prop];\n }\n};\n\nexport function $tuplePathify(expr: ExpressionRoot) {\n if (\n expr.__element__.__kind__ !== TypeKind.tuple &&\n expr.__element__.__kind__ !== TypeKind.namedtuple\n ) {\n return expr;\n }\n\n return new Proxy(expr, tupleProxyHandlers);\n}\n\nfunction tuplePath(\n parent: $expr_Tuple | $expr_TuplePath,\n itemType: BaseType,\n index: string\n): $expr_TuplePath {\n return $expressionify({\n __kind__: ExpressionKind.TuplePath,\n __element__: itemType,\n __cardinality__: parent.__cardinality__,\n __parent__: parent,\n __index__: index\n }) as any;\n}\n\nfunction makeTupleType(name: string, items: BaseType[]) {\n return {\n __kind__: TypeKind.tuple,\n __name__: name,\n __items__: items\n } as any;\n}\n\nconst typeKinds = new Set(Object.values(TypeKind));\n\nexport function tuple>(\n items: Items\n): TupleType;\nexport function tuple<\n Item extends TypeSet | scalarLiterals,\n Items extends typeutil.tupleOf\n>(\n items: Items\n): $expr_Tuple<\n Items extends typeutil.tupleOf ? mapLiteralToTypeSet : never\n>;\nexport function tuple(\n shape: Shape\n): NamedTupleType;\nexport function tuple(\n shape: Shape\n): $expr_NamedTuple>;\nexport function tuple(input: any) {\n if (Array.isArray(input)) {\n // is tuple\n if (input.every(item => typeKinds.has(item.__kind__))) {\n const typeItems = input as BaseType[];\n const typeName = `tuple<${typeItems\n .map(item => item.__name__)\n .join(\", \")}>`;\n return makeTupleType(typeName, typeItems);\n }\n\n const items = input.map(item => literalToTypeSet(item));\n const name = `tuple<${items\n .map(item => item.__element__.__name__)\n .join(\", \")}>`;\n return $expressionify({\n __kind__: ExpressionKind.Tuple,\n __element__: makeTupleType(\n name,\n items.map(item => item.__element__)\n ),\n __cardinality__: cardutil.multiplyCardinalitiesVariadic(\n items.map(i => i.__cardinality__) as any\n ),\n __items__: items\n }) as any;\n } else {\n // is named tuple\n if (Object.values(input).every((el: any) => typeKinds.has(el.__kind__))) {\n const typeName = `tuple<${Object.entries(input)\n .map(([key, val]: [string, any]) => `${key}: ${val.__name__}`)\n .join(\", \")}>`;\n return {\n __kind__: TypeKind.namedtuple,\n __name__: typeName,\n __shape__: input\n } as any;\n }\n\n const exprShape: NamedTupleLiteralShape = {};\n const typeShape: NamedTupleShape = {};\n for (const [key, val] of Object.entries(input)) {\n exprShape[key] = literalToTypeSet(val);\n typeShape[key] = exprShape[key].__element__;\n }\n const name = `tuple<${Object.entries(exprShape)\n .map(([key, val]) => `${key}: ${val.__element__.__name__}`)\n .join(\", \")}>`;\n return $expressionify({\n __kind__: ExpressionKind.NamedTuple,\n __element__: {\n __kind__: TypeKind.namedtuple,\n __name__: name,\n __shape__: typeShape\n } as any,\n __cardinality__: cardutil.multiplyCardinalitiesVariadic(\n Object.values(exprShape).map(val => val.__cardinality__) as any\n ),\n __shape__: exprShape\n }) as any;\n }\n}\n\n// export type {\n// ArrayType as $Array,\n// NamedTupleType as $NamedTuple,\n// TupleType as $Tuple\n// } from \"edgedb/_src/reflection/index.ts\";\n"},{"path":"detached.ts","content":"import {ExpressionKind} from \"edgedb/_src/reflection/index.ts\";\nimport type {Expression, TypeSet} from \"./typesystem.ts\";\nimport {$expressionify} from \"./path.ts\";\n\nexport function detached(\n expr: Expr\n): $expr_Detached {\n return $expressionify({\n __element__: expr.__element__,\n __cardinality__: expr.__cardinality__,\n __expr__: expr,\n __kind__: ExpressionKind.Detached\n }) as any;\n}\n\nexport type $expr_Detached = Expression<{\n __element__: Expr[\"__element__\"];\n __cardinality__: Expr[\"__cardinality__\"];\n __kind__: ExpressionKind.Detached;\n __expr__: TypeSet;\n}>;\n"},{"path":"external.ts","content":"import type {TypeSet, setToTsType} from \"./typesystem.ts\";\n\nexport {literal} from \"./literal.ts\";\nexport {} from \"./path.ts\";\nexport {set} from \"./set.ts\";\nexport {cast} from \"./cast.ts\";\nexport {\n ASC,\n DESC,\n EMPTY_FIRST,\n EMPTY_LAST,\n is,\n delete,\n select\n} from \"./select.ts\";\nexport {update} from \"./update.ts\";\nexport {insert} from \"./insert.ts\";\nexport {array, tuple} from \"./collections.ts\";\nexport {} from \"./funcops.ts\";\nexport {for} from \"./for.ts\";\nexport {alias, with} from \"./with.ts\";\nexport {optional, params} from \"./params.ts\";\nexport {detached} from \"./detached.ts\";\nexport {} from \"./toEdgeQL.ts\";\n\nexport type $infer = setToTsType;\n"},{"path":"for.ts","content":"import {Cardinality, ExpressionKind} from \"edgedb/_src/reflection/index.ts\";\nimport {cardutil} from \"./cardinality.ts\";\nimport type {Expression, BaseType, BaseTypeSet} from \"./typesystem.ts\";\nimport {$expressionify} from \"./path.ts\";\n\nexport type $expr_For<\n El extends BaseType = BaseType,\n Card extends Cardinality = Cardinality\n // IterSet extends BaseTypeSet = BaseTypeSet,\n // Expr extends BaseTypeSet = BaseTypeSet\n> = Expression<{\n __element__: El;\n __cardinality__: Card;\n __kind__: ExpressionKind.For;\n __iterSet__: BaseTypeSet;\n __forVar__: $expr_ForVar;\n __expr__: BaseTypeSet;\n}>;\n\nexport type $expr_ForVar = Expression<{\n __element__: Type;\n __cardinality__: Cardinality.One;\n __kind__: ExpressionKind.ForVar;\n}>;\n\nfunction _for(\n set: IteratorSet,\n expr: (variable: $expr_ForVar) => Expr\n): $expr_For<\n Expr[\"__element__\"],\n cardutil.multiplyCardinalities<\n IteratorSet[\"__cardinality__\"],\n Expr[\"__cardinality__\"]\n >\n> {\n const forVar = $expressionify({\n __kind__: ExpressionKind.ForVar,\n __element__: set.__element__,\n __cardinality__: Cardinality.One\n }) as $expr_ForVar;\n\n const returnExpr = expr(forVar);\n\n return $expressionify({\n __kind__: ExpressionKind.For,\n __element__: returnExpr.__element__,\n __cardinality__: cardutil.multiplyCardinalities(\n set.__cardinality__,\n returnExpr.__cardinality__\n ),\n __iterSet__: set,\n __expr__: returnExpr,\n __forVar__: forVar\n }) as any;\n}\n\nexport {_for as for};\n"},{"path":"funcops.ts","content":"import {Cardinality, introspect, TypeKind} from \"edgedb/_src/reflection/index.ts\";\nimport {cardutil} from \"./cardinality.ts\";\nimport {makeType} from \"./hydrate.ts\";\nimport type {\n BaseType,\n BaseTypeSet,\n ArrayType,\n ObjectType,\n TypeSet,\n RangeType,\n Expression\n} from \"./typesystem.ts\";\nimport {cast} from \"./cast.ts\";\nimport {isImplicitlyCastableTo, literalToTypeSet} from \"./castMaps.ts\";\nimport {literal} from \"./literal.ts\";\n\nimport type {ExpressionKind, OperatorKind} from \"edgedb/_src/reflection/index.ts\";\n\nexport type $expr_Function<\n // Name extends string = string,\n // Args extends (BaseTypeSet | undefined)[] = (BaseTypeSet | undefined)[],\n // NamedArgs extends {[key: string]: BaseTypeSet} = {\n // [key: string]: BaseTypeSet;\n // },\n // ReturnType extends BaseTypeSet = BaseTypeSet,\n El extends BaseType = BaseType,\n Card extends Cardinality = Cardinality\n> = Expression<{\n __element__: El;\n __cardinality__: Card;\n __kind__: ExpressionKind.Function;\n __name__: string;\n __args__: (BaseTypeSet | undefined)[];\n __namedargs__: {[key: string]: BaseTypeSet};\n}>;\n\nexport type $expr_Operator<\n // Name extends string = string,\n // OpKind extends OperatorKind = OperatorKind,\n // Args extends TypeSet[] = TypeSet[],\n // ReturnType extends TypeSet = TypeSet,\n El extends BaseType = BaseType,\n Card extends Cardinality = Cardinality\n> = Expression<{\n __element__: El;\n __cardinality__: Card;\n __kind__: ExpressionKind.Operator;\n __name__: string;\n __opkind__: OperatorKind;\n __args__: TypeSet[];\n}>;\n\ninterface OverloadFuncArgDef {\n typeId: string;\n optional?: boolean;\n setoftype?: boolean;\n variadic?: boolean;\n}\n\ninterface OverloadFuncDef {\n kind?: string;\n args: OverloadFuncArgDef[];\n namedArgs?: {[key: string]: OverloadFuncArgDef};\n returnTypeId: string;\n returnTypemod?: \"SetOfType\" | \"OptionalType\";\n preservesOptionality?: boolean;\n}\n\nfunction mapLiteralToTypeSet(literals: any[]): TypeSet[];\nfunction mapLiteralToTypeSet(literals: {[key: string]: any}): {\n [key: string]: TypeSet;\n};\nfunction mapLiteralToTypeSet(literals: any[] | {[key: string]: any}) {\n if (Array.isArray(literals)) {\n return literals.map(lit => (lit != null ? literalToTypeSet(lit) : lit));\n }\n const obj: {[key: string]: TypeSet} = {};\n for (const key of Object.keys(literals)) {\n obj[key] =\n literals[key] != null ? literalToTypeSet(literals[key]) : literals[key];\n }\n return obj;\n}\n\nexport function $resolveOverload(\n funcName: string,\n args: any[],\n typeSpec: introspect.Types,\n funcDefs: OverloadFuncDef[]\n) {\n const positionalArgs: (TypeSet | undefined)[] = [];\n let namedArgs: {[key: string]: TypeSet} | undefined;\n if (args.length) {\n if (args[0] !== undefined) {\n try {\n positionalArgs.push(literalToTypeSet(args[0]));\n } catch {\n // first arg is not a expr or literal type, so assume named args object\n namedArgs = mapLiteralToTypeSet(args[0] as object);\n }\n } else {\n positionalArgs.push(undefined);\n }\n positionalArgs.push(...mapLiteralToTypeSet(args.slice(1)));\n }\n\n for (const def of funcDefs) {\n const resolvedOverload = _tryOverload(\n funcName,\n positionalArgs,\n namedArgs,\n typeSpec,\n def\n );\n if (resolvedOverload !== null) {\n return resolvedOverload;\n }\n }\n\n throw new Error(\n `No function overload found for ${\n funcName.includes(\"::\")\n ? `'e.${funcName.split(\"::\")[1]}()'`\n : `operator '${funcName}'`\n } with args: ${args.map(arg => `${arg}`).join(\", \")}`\n );\n}\n\nconst ANYTYPE_ARG = Symbol();\n\nfunction _tryOverload(\n funcName: string,\n args: (BaseTypeSet | undefined)[],\n namedArgs: {[key: string]: BaseTypeSet} | undefined,\n typeSpec: introspect.Types,\n funcDef: OverloadFuncDef\n): {\n kind?: string;\n returnType: BaseType;\n cardinality: Cardinality;\n args: BaseTypeSet[];\n namedArgs: {[key: string]: BaseTypeSet};\n} | null {\n if (\n (funcDef.namedArgs === undefined && namedArgs !== undefined) ||\n (namedArgs === undefined &&\n funcDef.namedArgs &&\n Object.values(funcDef.namedArgs).some(arg => !arg.optional))\n ) {\n return null;\n }\n\n const lastParamVariadic = funcDef.args[funcDef.args.length - 1]?.variadic;\n if (!lastParamVariadic && args.length > funcDef.args.length) {\n return null;\n }\n\n const paramCardinalities: [Cardinality, ...Cardinality[]] = [\n Cardinality.One\n ];\n\n if (namedArgs) {\n for (const [key, value] of Object.entries(namedArgs)) {\n const argDef = funcDef.namedArgs?.[key];\n if (\n !argDef ||\n !compareType(typeSpec, argDef.typeId, value.__element__).match\n ) {\n return null;\n }\n\n paramCardinalities.push(\n argDef.setoftype\n ? funcDef.preservesOptionality\n ? cardutil.overrideUpperBound(value.__cardinality__, \"One\")\n : Cardinality.One\n : argDef.optional\n ? cardutil.overrideLowerBound(value.__cardinality__, \"One\")\n : value.__cardinality__\n );\n }\n }\n\n let positionalArgs: BaseTypeSet[] = [];\n\n let returnAnytype: BaseType | undefined;\n let needsAnytypeReplacement = false;\n\n for (let i = 0; i < funcDef.args.length; i++) {\n const argDef = funcDef.args[i];\n const arg = args[i];\n\n if (arg === undefined) {\n if (!argDef.optional) {\n return null;\n }\n\n if (i < args.length) {\n // arg is explicitly undefined, inject empty set\n const argTypeName = typeSpec.get(argDef.typeId).name;\n if (\n argTypeName.includes(\"anytype\") ||\n argTypeName.includes(\"std::anypoint\")\n ) {\n if (!returnAnytype) {\n positionalArgs.push(ANYTYPE_ARG as any);\n needsAnytypeReplacement = true;\n } else {\n positionalArgs.push(cast(returnAnytype, null));\n }\n } else {\n const argType = makeType(typeSpec, argDef.typeId, literal);\n positionalArgs.push(cast(argType, null));\n }\n }\n } else {\n const {match, anytype} = compareType(\n typeSpec,\n argDef.typeId,\n arg.__element__\n );\n\n if (!match) {\n return null;\n }\n if (!returnAnytype && anytype) {\n returnAnytype = anytype;\n }\n\n positionalArgs.push(\n ...(argDef.variadic ? (args.slice(i) as BaseTypeSet[]) : [arg])\n );\n if (argDef.setoftype) {\n paramCardinalities.push(\n funcDef.preservesOptionality\n ? cardutil.overrideUpperBound(arg.__cardinality__, \"One\")\n : Cardinality.One\n );\n } else {\n const card = argDef.variadic\n ? cardutil.multiplyCardinalitiesVariadic(\n (args.slice(i) as BaseTypeSet[]).map(\n el => el.__cardinality__\n ) as [Cardinality, ...Cardinality[]]\n )\n : arg.__cardinality__;\n\n paramCardinalities.push(\n argDef.optional ? cardutil.overrideLowerBound(card, \"One\") : card\n );\n }\n }\n }\n\n let cardinality: Cardinality;\n if (funcName === \"if_else\") {\n cardinality = cardutil.multiplyCardinalities(\n cardutil.orCardinalities(\n positionalArgs[0].__cardinality__,\n positionalArgs[2].__cardinality__\n ),\n positionalArgs[1].__cardinality__\n );\n } else if (funcName === \"std::assert_exists\") {\n cardinality = cardutil.overrideLowerBound(\n positionalArgs[0].__cardinality__,\n \"One\"\n );\n } else if (funcName === \"union\") {\n cardinality = cardutil.mergeCardinalities(\n positionalArgs[0].__cardinality__,\n positionalArgs[1].__cardinality__\n );\n } else if (funcName === \"??\") {\n cardinality = cardutil.orCardinalities(\n positionalArgs[0].__cardinality__,\n positionalArgs[1].__cardinality__\n );\n } else if (funcName === \"distinct\") {\n cardinality = positionalArgs[0].__cardinality__;\n } else {\n cardinality =\n funcDef.returnTypemod === \"SetOfType\"\n ? Cardinality.Many\n : cardutil.multiplyCardinalitiesVariadic(paramCardinalities);\n\n if (\n funcDef.returnTypemod === \"OptionalType\" &&\n !funcDef.preservesOptionality\n ) {\n cardinality = cardutil.overrideLowerBound(cardinality, \"Zero\");\n }\n }\n\n if (needsAnytypeReplacement) {\n if (!returnAnytype) {\n throw new Error(`could not resolve anytype for ${funcName}`);\n }\n positionalArgs = positionalArgs.map(arg =>\n (arg as any) === ANYTYPE_ARG ? cast(returnAnytype!, null) : arg\n );\n }\n\n return {\n kind: funcDef.kind,\n returnType: makeType(\n typeSpec,\n funcDef.returnTypeId,\n literal,\n returnAnytype\n ),\n cardinality,\n args: positionalArgs,\n namedArgs: namedArgs ?? {}\n };\n}\n\nconst nameRemapping: {[key: string]: string} = {\n \"std::int16\": \"std::number\",\n \"std::int32\": \"std::number\",\n \"std::int64\": \"std::number\",\n \"std::float32\": \"std::number\",\n \"std::float64\": \"std::number\"\n};\nconst descendantCache = new Map();\nfunction getDescendantNames(typeSpec: introspect.Types, typeId: string) {\n if (descendantCache.has(typeId)) {\n return descendantCache.get(typeId)!;\n }\n const descendants: string[] = [\n ...new Set(\n [...typeSpec.values()]\n .filter(\n type =>\n type.kind === \"scalar\" && type.bases.some(({id}) => id === typeId)\n )\n .flatMap(type =>\n type.is_abstract\n ? getDescendantNames(typeSpec, type.id)\n : [nameRemapping[type.name], type.name]\n )\n )\n ];\n descendantCache.set(typeId, descendants);\n return descendants;\n}\n\nfunction compareType(\n typeSpec: introspect.Types,\n typeId: string,\n arg: BaseType\n): {match: boolean; anytype?: BaseType} {\n const type = typeSpec.get(typeId);\n\n if (type.name === \"anytype\") {\n return {match: true, anytype: arg};\n }\n\n if (type.name === \"std::anypoint\") {\n const descendants = getDescendantNames(typeSpec, typeId);\n if (descendants.includes(arg.__name__)) {\n return {match: true, anytype: arg};\n }\n }\n\n if (type.name === \"std::anyenum\") {\n return {match: arg.__kind__ === TypeKind.enum};\n }\n\n if (type.kind === \"scalar\") {\n arg = (arg as any).__casttype__ ?? arg;\n return {\n match:\n (arg.__kind__ === TypeKind.scalar || arg.__kind__ === TypeKind.enum) &&\n (arg.__name__ === type.name ||\n isImplicitlyCastableTo(arg.__name__, type.name))\n };\n }\n if (type.kind === \"array\") {\n if (arg.__kind__ === TypeKind.array) {\n return compareType(\n typeSpec,\n type.array_element_id,\n (arg as any as ArrayType).__element__ as BaseType\n );\n }\n }\n if (type.kind === \"range\") {\n if (arg.__kind__ === TypeKind.range) {\n return compareType(\n typeSpec,\n type.range_element_id,\n (arg as any as RangeType).__element__ as BaseType\n );\n }\n }\n if (type.kind === \"object\") {\n if (arg.__kind__ !== TypeKind.object) return {match: false};\n\n const objectArg = arg as ObjectType;\n let match = true;\n\n // shape comparison\n for (const ptr of type.pointers) {\n if (objectArg.__pointers__[ptr.name]) {\n const argPtr = objectArg.__pointers__[ptr.name];\n const ptrTarget = typeSpec.get(ptr.target_id);\n if (\n ptrTarget.name !== argPtr.target.__name__ ||\n ptr.card !== argPtr.cardinality\n ) {\n match = false;\n }\n }\n }\n\n return {\n match\n };\n }\n if (type.kind === \"tuple\") {\n const items =\n arg.__kind__ === TypeKind.tuple\n ? (arg as any).__items__\n : arg.__kind__ === TypeKind.namedtuple\n ? (arg as any).__shape__\n : null;\n if (items) {\n const keys = Object.keys(items);\n\n if (keys.length === type.tuple_elements.length) {\n let anytype: BaseType | undefined;\n for (let i = 0; i < keys.length; i++) {\n if (keys[i] !== type.tuple_elements[i].name) {\n return {match: false};\n }\n const {match: m, anytype: a} = compareType(\n typeSpec,\n type.tuple_elements[i].target_id,\n (items as any)[keys[i]]\n );\n if (!m) {\n return {match: false};\n }\n if (a) anytype = a;\n }\n return {match: true, anytype};\n }\n }\n }\n\n return {match: false};\n}\n"},{"path":"globals.ts","content":"import {ExpressionKind, Cardinality} from \"edgedb/_src/reflection/index.ts\";\nimport type {Expression, BaseType} from \"./typesystem.ts\";\nimport {$expressionify} from \"./path.ts\";\n\nexport function makeGlobal<\n // Name extends string,\n Type extends BaseType,\n Card extends Cardinality\n>(name: string, type: Type, card: Card): $expr_Global {\n return $expressionify({\n __name__: name,\n __element__: type,\n __cardinality__: card,\n __kind__: ExpressionKind.Global\n });\n}\n\nexport type $expr_Global<\n // Name extends string = string,\n Type extends BaseType = BaseType,\n Card extends Cardinality = Cardinality\n> = Expression<{\n __name__: string;\n __element__: Type;\n __cardinality__: Card;\n __kind__: ExpressionKind.Global;\n}>;\n"},{"path":"group.ts","content":"import type {\n Expression,\n ObjectType,\n ObjectTypeSet,\n TypeSet,\n BaseType,\n $scopify,\n PropertyDesc,\n LinkDesc\n} from \"./typesystem.ts\";\nimport {\n Cardinality,\n ExpressionKind,\n TypeKind\n} from \"edgedb/_src/reflection/index.ts\";\nimport {makeType} from \"./hydrate.ts\";\n\nimport {$expressionify, $getScopedExpr} from \"./path.ts\";\n// @ts-ignore\nimport type {$FreeObjectλShape, $str} from \"./modules/std.ts\";\nimport {spec} from \"./__spec__.ts\";\nimport {literal} from \"./literal.ts\";\nimport {resolveShapeElement} from \"./select.ts\";\nimport type {\n normaliseShape,\n // normaliseElement,\n objectTypeToSelectShape\n} from \"./select.ts\";\n\ntype SingletonSet = Expression<\n TypeSet\n>;\ntype SimpleGroupElements = {[k: string]: SingletonSet};\ntype GroupModifiers = {by: SimpleGroupElements};\ntype NestedGroupElements = {\n [k: string]: SingletonSet | GroupingSet;\n};\n\nexport type GroupingSet = {\n __kind__: \"groupingset\";\n __settype__: \"set\" | \"tuple\" | \"rollup\" | \"cube\";\n __elements__: NestedGroupElements;\n __exprs__: [string, SingletonSet][];\n};\nexport function isGroupingSet(arg: any): arg is GroupingSet {\n return arg.__kind__ === \"groupingset\";\n}\n\n// result is partial to prevent \"X is specified more than once\" errors\n// the return type is a lie, this function returns a grouping set\n// but it pretends to return a SimpleGroupElements\n// to make the static computatation of `key` easier\nconst makeGroupingSet =\n (prefix: string) =>\n (grps: T): {[k in keyof T]?: T[k]} => {\n const seenKeys = new Map();\n const unfiltered = Object.entries(grps as NestedGroupElements).flatMap(\n ([k, grp]) =>\n isGroupingSet(grp)\n ? grp.__exprs__\n : ([[k, grp]] as [string, SingletonSet][])\n );\n const filtered = unfiltered.filter(([k, expr]) => {\n if (!seenKeys.has(k)) {\n seenKeys.set(k, expr);\n return true;\n }\n\n if (expr !== seenKeys.get(k)) {\n throw new Error(\n `Cannot override pre-existing expression with key \"${k}\"`\n );\n }\n\n return false;\n });\n\n return {\n [`${Math.round(1000000 * Math.random())}___`]: {\n __kind__: \"groupingset\",\n __settype__: prefix,\n __elements__: grps,\n __exprs__: filtered\n } as GroupingSet\n } as any;\n };\nconst set = makeGroupingSet(\"set\");\nconst tuple = makeGroupingSet(\"tuple\");\nconst rollup = makeGroupingSet(\"rollup\");\nconst cube = makeGroupingSet(\"cube\");\n\nconst setFuncs = {set, tuple, rollup, cube};\n\nexport type $expr_Group<\n Expr extends ObjectTypeSet = ObjectTypeSet,\n Mods extends GroupModifiers = GroupModifiers,\n Shape extends object = {id: true}\n> = Expression<{\n __element__: ObjectType<\n \"std::FreeObject\",\n $FreeObjectλShape & {\n // adding free shape elements into __pointers__\n // because objectTypeToSelectShape doesn't allow shapes on computeds\n // and setToTsType can't handle that currently\n grouping: PropertyDesc<$str, Cardinality.Many, false, true, true, false>;\n key: LinkDesc<\n ObjectType<\n \"std::FreeObject\",\n {\n // tslint:disable-next-line\n [k in keyof Mods[\"by\"]]: Mods[\"by\"][k][\"__element__\"] extends ObjectType\n ? never\n : PropertyDesc<\n Mods[\"by\"][k][\"__element__\"],\n Cardinality.AtMostOne\n >;\n }\n >,\n Cardinality.One,\n {},\n false,\n true,\n true,\n false\n >;\n elements: LinkDesc<\n Expr[\"__element__\"],\n Cardinality.Many,\n {},\n false,\n true,\n true,\n false\n >;\n },\n {\n // grouping: true;\n // key: {[k in keyof Mods[\"by\"]]: true};\n // elements: normaliseShape;\n grouping: TypeSet<$str, Cardinality.Many>;\n key: Expression<{\n __element__: ObjectType<\n \"std::FreeObject\",\n $FreeObjectλShape,\n {\n [k in keyof Mods[\"by\"]]: Expression<{\n __element__: Mods[\"by\"][k][\"__element__\"];\n __cardinality__: Cardinality.AtMostOne;\n }>;\n }\n >;\n __cardinality__: Cardinality.One;\n }>;\n elements: Expression<{\n __element__: ObjectType<\n Expr[\"__element__\"][\"__name__\"],\n Expr[\"__element__\"][\"__pointers__\"],\n // Omit, \"by\">\n normaliseShape\n >;\n __cardinality__: Cardinality.Many;\n }>;\n }\n >;\n __cardinality__: Cardinality.Many;\n // bit of a lie, this is a GroupingSet at runtime\n __modifiers__: Mods;\n __kind__: ExpressionKind.Group;\n __expr__: ObjectTypeSet;\n __scope__: ObjectTypeSet;\n}>;\n\n// type modifierKeys = \"by\";\ntype noUndefined = T extends undefined ? never : T;\ntype groupFunc = <\n Expr extends ObjectTypeSet,\n // Shape extends GroupModifiers\n // Grps extends SimpleGroupElements,\n Shape extends {by?: SimpleGroupElements} & objectTypeToSelectShape<\n Expr[\"__element__\"]\n >\n // Mods extends GroupModifiers = {by: Shape[\"by\"]}\n>(\n expr: Expr,\n getter: (arg: $scopify) => Readonly\n) => $expr_Group<\n Expr,\n {by: noUndefined},\n normaliseShape\n>;\n\nconst groupFunc: groupFunc = (expr, getter) => {\n const {shape, scope, modifiers} = resolveShape(getter, expr);\n // const scope = $getScopedExpr(expr as any);\n // const rawGroupings = getter(scope);\n const groupSet = tuple(modifiers.by);\n\n // only one key in object returned from makeGroupingSet\n const key = Object.keys(groupSet)[0];\n const grouping = groupSet[key] as any as GroupingSet;\n const keyShape: any = {};\n const keyPointers: any = {};\n const keyShapeElement: any = {};\n\n for (const [k, e] of grouping.__exprs__) {\n keyShape[k] = $expressionify({\n __element__: e.__element__,\n __cardinality__: Cardinality.AtMostOne\n } as any);\n keyPointers[k] = {\n __kind__: \"property\",\n target: e.__element__,\n cardinality: Cardinality.AtMostOne,\n exclusive: false,\n computed: false,\n readonly: false,\n hasDefault: false\n } as PropertyDesc;\n keyShapeElement[k] = true;\n }\n\n const $FreeObject = makeType(\n spec,\n [...spec.values()].find(s => s.name === \"std::FreeObject\")!.id,\n literal\n );\n\n const str = makeType(\n spec,\n [...spec.values()].find(s => s.name === \"std::str\")!.id,\n literal\n );\n\n return $expressionify({\n __element__: {\n ...$FreeObject,\n __name__: \"std::FreeObject\",\n __pointers__: {\n ...($FreeObject as any).__pointers__,\n __name__: \"std::FreeObject\",\n grouping: {\n __kind__: \"property\",\n target: str,\n cardinality: Cardinality.Many,\n exclusive: false,\n computed: false,\n readonly: false,\n hasDefault: false\n } as PropertyDesc,\n key: {\n __kind__: \"link\",\n target: {\n ...$FreeObject,\n __name__: \"std::FreeObject\",\n __pointers__: {\n ...($FreeObject as any).__pointers__,\n ...keyPointers\n },\n __shape__: keyShape\n },\n properties: {},\n cardinality: Cardinality.One,\n exclusive: false,\n computed: false,\n readonly: false,\n hasDefault: false\n } as LinkDesc,\n\n elements: {\n __kind__: \"link\",\n target: expr.__element__,\n cardinality: Cardinality.Many,\n properties: {},\n exclusive: false,\n computed: false,\n readonly: false,\n hasDefault: false\n } as LinkDesc\n },\n __shape__: {\n grouping: $expressionify({\n __element__: str,\n __cardinality__: Cardinality.Many\n } as any),\n key: $expressionify({\n __element__: {\n ...$FreeObject,\n __shape__: keyShape\n },\n __cardinality__: Cardinality.One\n } as any),\n elements: $expressionify({\n __element__: {...expr.__element__, __shape__: shape} as any,\n __cardinality__: Cardinality.Many\n } as any)\n }\n },\n\n __cardinality__: Cardinality.Many,\n __expr__: expr,\n __modifiers__: {by: grouping},\n __kind__: ExpressionKind.Group,\n __scope__: scope\n }) as any;\n};\nObject.assign(groupFunc, setFuncs);\n\nfunction resolveShape(\n shapeGetter: ((scope: any) => any) | any,\n expr: TypeSet\n): {modifiers: {by: SimpleGroupElements}; shape: any; scope: TypeSet} {\n const modifiers: {by: SimpleGroupElements} = {} as any;\n const shape: any = {};\n\n // get scoped object if expression is objecttypeset\n const scope = $getScopedExpr(expr as any) as ObjectTypeSet;\n\n // execute getter with scope\n const selectShape =\n typeof shapeGetter === \"function\" ? shapeGetter(scope) : shapeGetter;\n\n for (const [key, value] of Object.entries(selectShape)) {\n // handle modifier keys\n if (key === \"by\") {\n modifiers[key] = value as any;\n } else {\n // for scalar expressions, scope === expr\n // shape keys are not allowed\n if (expr.__element__.__kind__ !== TypeKind.object) {\n throw new Error(\n `Invalid select shape key '${key}' on scalar expression, ` +\n `only modifiers are allowed (filter, order_by, offset and limit)`\n );\n }\n shape[key] = resolveShapeElement(key, value, scope);\n }\n }\n if (Object.keys(shape).length === 0) {\n shape.id = true;\n }\n if (!modifiers.by) {\n throw new Error(\"Must provide a `by` key in `e.group`\");\n }\n return {shape, modifiers, scope};\n}\nexport const group: typeof setFuncs & groupFunc = groupFunc as any;\n"},{"path":"hydrate.ts","content":"import type {$} from \"edgedb\";\n\nimport type {\n BaseType,\n ObjectType,\n ObjectTypePointers,\n LinkDesc,\n PropertyDesc,\n TupleType\n} from \"./typesystem.ts\";\n\nimport {util, TypeKind} from \"edgedb/_src/reflection/index.ts\";\nimport type {typeutil} from \"edgedb/_src/reflection/index.ts\";\n\nconst typeCache = new Map();\n\nconst _linkProps = Symbol();\n\nfunction applySpec(\n spec: $.introspect.Types,\n type: $.introspect.ObjectType,\n shape: any,\n seen: Set,\n literal: any\n): void {\n const allPointers = [\n ...type.pointers,\n ...type.backlinks,\n ...type.backlink_stubs\n ];\n for (const ptr of allPointers) {\n if (seen.has(ptr.name)) {\n continue;\n }\n seen.add(ptr.name);\n\n if (ptr.kind === \"link\") {\n shape[ptr.name] = {\n __kind__: \"link\",\n cardinality: ptr.card,\n exclusive: ptr.is_exclusive,\n computed: ptr.is_computed,\n readonly: ptr.is_readonly\n } as LinkDesc;\n util.defineGetter(shape[ptr.name], \"target\", () =>\n makeType(spec, ptr.target_id, literal)\n );\n util.defineGetter(shape[ptr.name], \"properties\", () => {\n if (!shape[ptr.name][_linkProps]) {\n const linkProperties: {[k: string]: any} = (shape[ptr.name][\n _linkProps\n ] = {});\n for (const linkProp of ptr.pointers ?? []) {\n // We only support \"link properties\" in EdgeDB, currently.\n if (linkProp.kind !== \"property\") {\n return;\n }\n // No use for them reflected, at the moment.\n if (linkProp.name === \"source\" || linkProp.name === \"target\") {\n return;\n }\n\n const linkPropObject: any = {\n __kind__: \"property\"\n };\n linkPropObject.cardinality = linkProp.card;\n util.defineGetter(linkPropObject, \"target\", () => {\n return makeType(spec, linkProp.target_id, literal);\n });\n linkProperties[linkProp.name] = linkPropObject;\n }\n }\n return shape[ptr.name][_linkProps];\n });\n } else if (ptr.kind === \"property\") {\n shape[ptr.name] = {\n __kind__: \"property\",\n cardinality: ptr.card,\n exclusive: ptr.is_exclusive,\n computed: ptr.is_computed,\n readonly: ptr.is_readonly\n } as PropertyDesc;\n util.defineGetter(shape[ptr.name], \"target\", () =>\n makeType(spec, ptr.target_id, literal)\n );\n }\n }\n}\n\nexport function makeType(\n spec: $.introspect.Types,\n id: string,\n // should be (type: any, val: any) => any, but causes\n // 'Type instantiation is excessively deep and possibly infinite' error\n // in typescript 4.5\n literal: any,\n anytype?: BaseType\n): T {\n const type = spec.get(id);\n\n if (type.name === \"anytype\" || type.name === \"std::anypoint\") {\n if (anytype) return anytype as unknown as T;\n throw new Error(\"anytype not provided\");\n }\n\n if (typeCache.has(id)) {\n return typeCache.get(id) as T;\n }\n\n const obj: any = {};\n obj.__name__ = type.name;\n\n if (type.kind === \"object\") {\n obj.__kind__ = TypeKind.object;\n\n const pointers: any = {};\n const seen = new Set();\n applySpec(spec, type, pointers, seen, literal);\n const ancestors = [...type.bases];\n for (const anc of ancestors) {\n const ancType = spec.get(anc.id);\n if (ancType.kind === \"object\" || ancType.kind === \"scalar\") {\n ancestors.push(...ancType.bases);\n }\n if (ancType.kind !== \"object\") {\n throw new Error(`Not an object: ${id}`);\n }\n applySpec(spec, ancType, pointers, seen, literal);\n }\n\n obj.__pointers__ = pointers;\n obj.__shape__ = {};\n typeCache.set(id, obj);\n return obj;\n } else if (type.kind === \"scalar\") {\n const scalarObj = type.is_abstract\n ? {}\n : type.enum_values\n ? {}\n : // : type.name === \"std::json\"\n // ? (((val: any) => {\n // return literal(scalarObj, JSON.stringify(val));\n // }) as any)\n (((val: any) => {\n return literal(scalarObj, val);\n }) as any);\n\n if (type.enum_values) {\n scalarObj.__kind__ = TypeKind.enum;\n scalarObj.__values__ = type.enum_values;\n for (const val of type.enum_values) {\n Object.defineProperty(scalarObj, util.toIdent(val), {\n get() {\n return literal(scalarObj, val);\n }\n });\n }\n // if (type.enum_values) {\n // for (const val of type.enum_values) {\n // scalarObj[val] = val;\n // }\n // }\n } else {\n scalarObj.__kind__ = TypeKind.scalar;\n }\n scalarObj.__name__ = type.name;\n\n if (type.cast_type) {\n scalarObj.__casttype__ = makeType(spec, type.cast_type, literal);\n }\n typeCache.set(id, scalarObj);\n return scalarObj;\n } else if (type.kind === \"array\") {\n obj.__kind__ = TypeKind.array;\n util.defineGetter(obj, \"__element__\", () => {\n return makeType(spec, type.array_element_id, literal, anytype);\n });\n util.defineGetter(obj, \"__name__\", () => {\n return `array<${obj.__element__.__name__}>`;\n });\n return obj;\n } else if (type.kind === \"tuple\") {\n if (type.tuple_elements[0].name === \"0\") {\n // unnamed tuple\n obj.__kind__ = TypeKind.tuple;\n\n util.defineGetter(obj, \"__items__\", () => {\n return type.tuple_elements.map(el =>\n makeType(spec, el.target_id, literal, anytype)\n ) as any;\n });\n util.defineGetter(obj, \"__name__\", () => {\n return `tuple<${obj.__items__\n .map((item: any) => item.__name__)\n .join(\", \")}>`;\n });\n return obj;\n } else {\n // named tuple\n obj.__kind__ = TypeKind.namedtuple;\n\n util.defineGetter(obj, \"__shape__\", () => {\n const shape: any = {};\n for (const el of type.tuple_elements) {\n shape[el.name] = makeType(spec, el.target_id, literal, anytype);\n }\n return shape;\n });\n util.defineGetter(obj, \"__name__\", () => {\n return `tuple<${Object.entries(obj.__shape__)\n .map(([key, val]: [string, any]) => `${key}: ${val.__name__}`)\n .join(\", \")}>`;\n });\n return obj;\n }\n } else if (type.kind === \"range\") {\n obj.__kind__ = TypeKind.range;\n util.defineGetter(obj, \"__element__\", () => {\n return makeType(spec, type.range_element_id, literal, anytype);\n });\n util.defineGetter(obj, \"__name__\", () => {\n return `range<${obj.__element__.__name__}>`;\n });\n return obj;\n } else {\n throw new Error(\"Invalid type.\");\n }\n}\nexport type mergeObjectShapes<\n A extends ObjectTypePointers,\n B extends ObjectTypePointers\n> = typeutil.flatten<{\n [k in keyof A & keyof B]: A[k] extends B[k] // possible performance issue?\n ? B[k] extends A[k]\n ? A[k]\n : never\n : never;\n}>;\n\nexport type mergeObjectTypes<\n A extends ObjectType | undefined,\n B extends ObjectType | undefined\n> = A extends ObjectType\n ? B extends ObjectType\n ? ObjectType<\n `${A[\"__name__\"]} UNION ${B[\"__name__\"]}`,\n mergeObjectShapes,\n null\n >\n : A\n : B extends ObjectType\n ? B\n : undefined;\n\nexport function $mergeObjectTypes(\n a: A,\n b: B\n): mergeObjectTypes {\n const obj = {\n __kind__: TypeKind.object,\n __name__: `${a.__name__} UNION ${b.__name__}`,\n get __pointers__() {\n const merged: any = {};\n for (const [akey, aitem] of Object.entries(a.__pointers__)) {\n if (!b.__pointers__[akey]) continue;\n\n const bitem = b.__pointers__[akey];\n if (aitem.cardinality !== bitem.cardinality) continue;\n // names must reflect full type\n if (aitem.target.__name__ !== bitem.target.__name__) continue;\n merged[akey] = aitem;\n }\n return merged;\n },\n __shape__: {}\n };\n return obj as any;\n}\n\nexport function $mergeTupleTypes(\n a: A,\n b: B\n): TupleType {\n if (a.__items__.length !== b.__items__.length) {\n throw new Error(\"Incompatible tuple types; lengths differ.\");\n }\n return {} as TupleType;\n}\n"},{"path":"insert.ts","content":"import {\n Cardinality,\n ExpressionKind,\n typeutil,\n TypeKind\n} from \"edgedb/_src/reflection/index.ts\";\nimport type {\n Expression,\n LinkDesc,\n ObjectTypeSet,\n ObjectTypePointers,\n PropertyDesc,\n stripBacklinks,\n stripNonInsertables,\n $scopify,\n stripSet,\n TypeSet,\n ObjectType\n} from \"./typesystem.ts\";\nimport type {pointerToAssignmentExpression} from \"./casting.ts\";\nimport {$expressionify, $getScopedExpr} from \"./path.ts\";\nimport {cast} from \"./cast.ts\";\nimport {set} from \"./set.ts\";\nimport {literal} from \"./literal.ts\";\nimport {$getTypeByName} from \"./literal.ts\";\nimport type {$expr_PathNode} from \"./path.ts\";\nimport type {$Object} from \"./modules/std.ts\";\nimport type {scalarLiterals} from \"./castMaps.ts\";\n\nexport type pointerIsOptional =\n T[\"cardinality\"] extends\n | Cardinality.Many\n | Cardinality.Empty\n | Cardinality.AtMostOne\n ? true\n : false;\n\nexport type InsertShape = typeutil.flatten<\n RawInsertShape\n>;\n\nexport type RawInsertShape =\n // short-circuit infinitely deep\n ObjectType extends El\n ? never\n : typeutil.stripNever<\n stripNonInsertables>\n > extends infer Shape\n ? Shape extends ObjectTypePointers\n ? typeutil.addQuestionMarks<{\n [k in keyof Shape]:\n | pointerToAssignmentExpression\n | (pointerIsOptional extends true\n ? undefined | null\n : never)\n | (Shape[k][\"hasDefault\"] extends true ? undefined : never);\n }> & {[k in `@${string}`]: TypeSet | scalarLiterals}\n : never\n : never;\n\ninterface UnlessConflict {\n on: TypeSet | null;\n else?: TypeSet;\n}\n\ntype InsertBaseExpression = {\n __kind__: ExpressionKind.Insert;\n __element__: Root[\"__element__\"];\n __cardinality__: Cardinality.One;\n __expr__: stripSet;\n __shape__: any;\n};\nexport type $expr_Insert<\n // Root extends $expr_PathNode = $expr_PathNode\n El extends ObjectType = ObjectType\n // Conflict = UnlessConflict | null\n // Shape extends InsertShape = any\n> = Expression<{\n __kind__: ExpressionKind.Insert;\n __element__: El;\n __cardinality__: Cardinality.One;\n __expr__: $expr_PathNode;\n __shape__: InsertShape;\n\n unlessConflict(): $expr_InsertUnlessConflict<\n El,\n // Expression<{\n // __kind__: ExpressionKind.Insert;\n // __element__: El;\n // __cardinality__: Cardinality.One;\n // __expr__: $expr_PathNode;\n // __shape__: InsertShape;\n // }>,\n {on: null}\n >;\n unlessConflict(\n conflictGetter: (scope: $scopify) => Conflict\n ): $expr_InsertUnlessConflict<\n El,\n // Expression<{\n // __kind__: ExpressionKind.Insert;\n // __element__: El;\n // __cardinality__: Cardinality.One;\n // __expr__: $expr_PathNode;\n // __shape__: InsertShape;\n // }>,\n Conflict\n >;\n}>;\n\nexport type $expr_InsertUnlessConflict<\n El extends ObjectType = ObjectType,\n // Root extends InsertBaseExpression = InsertBaseExpression,\n Conflict extends UnlessConflict = UnlessConflict\n> = Expression<{\n __kind__: ExpressionKind.InsertUnlessConflict;\n __element__: Conflict[\"else\"] extends TypeSet\n ? Conflict[\"else\"][\"__element__\"][\"__name__\"] extends El[\"__name__\"]\n ? El\n : $Object\n : El;\n __cardinality__: Conflict[\"else\"] extends TypeSet\n ? Conflict[\"else\"][\"__cardinality__\"]\n : Cardinality.AtMostOne;\n __expr__: InsertBaseExpression;\n __conflict__: Conflict;\n}>;\n\nfunction unlessConflict(\n this: $expr_Insert,\n conflictGetter?: (scope: TypeSet) => UnlessConflict\n) {\n const expr: any = {\n __kind__: ExpressionKind.InsertUnlessConflict,\n __element__: this.__element__,\n __cardinality__: Cardinality.AtMostOne,\n __expr__: this\n // __conflict__: Conflict;\n };\n\n if (!conflictGetter) {\n expr.__conflict__ = {on: null};\n return $expressionify(expr);\n } else {\n const scopedExpr = $getScopedExpr(this.__expr__);\n const conflict = conflictGetter(scopedExpr);\n expr.__conflict__ = conflict;\n if (conflict.else) {\n expr.__cardinality__ = conflict.else.__cardinality__;\n if (this.__element__.__name__ !== conflict.else.__element__.__name__) {\n expr.__element__ = $getTypeByName(\"std::Object\");\n }\n }\n return $expressionify(expr);\n }\n}\n\nexport function $insertify(\n expr: Omit<$expr_Insert, \"unlessConflict\">\n): $expr_Insert {\n (expr as any).unlessConflict = unlessConflict.bind(expr as any);\n return expr as any;\n}\n\nexport function $normaliseInsertShape(\n root: ObjectTypeSet,\n shape: {[key: string]: any},\n isUpdate: boolean = false\n): {[key: string]: TypeSet | {\"+=\": TypeSet} | {\"-=\": TypeSet}} {\n const newShape: {\n [key: string]: TypeSet | {\"+=\": TypeSet} | {\"-=\": TypeSet};\n } = {};\n for (const [key, _val] of Object.entries(shape)) {\n let val = _val;\n let setModify: string | null = null;\n if (isUpdate && _val != null && typeof _val === \"object\") {\n const valKeys = Object.keys(_val);\n if (\n valKeys.length === 1 &&\n (valKeys[0] === \"+=\" || valKeys[0] === \"-=\")\n ) {\n val = _val[valKeys[0]];\n setModify = valKeys[0];\n }\n }\n\n const pointer = root.__element__.__pointers__[key];\n\n // no pointer, not a link property\n const isLinkProp = key[0] === \"@\";\n if (!pointer && !isLinkProp) {\n throw new Error(\n `Could not find property pointer for ${\n isUpdate ? \"update\" : \"insert\"\n } shape key: '${key}'`\n );\n }\n\n // skip undefined vals\n if (val === undefined) continue;\n\n // is val is expression, assign to newShape\n if (val?.__kind__) {\n // ranges can contain null values, so if the type is 'std::number'\n // we need to set the type to the exact number type of the pointer\n // so null casts are correct\n if (\n val.__kind__ === ExpressionKind.Literal &&\n val.__element__.__kind__ === TypeKind.range &&\n val.__element__.__element__.__name__ === \"std::number\"\n ) {\n newShape[key] = (literal as any)(pointer.target, val.__value__);\n } else {\n newShape[key] = _val;\n }\n continue;\n }\n\n // handle link props\n // after this guard, pointer definitely is defined\n if (isLinkProp) {\n throw new Error(\n `Cannot assign plain data to link property '${key}'. Provide an expression instead.`\n );\n }\n\n // trying to assign plain data to a link\n if (pointer.__kind__ !== \"property\" && val !== null) {\n throw new Error(\n `Must provide subquery when assigning to link '${key}' in ${\n isUpdate ? \"update\" : \"insert\"\n } query.`\n );\n }\n\n // val is plain data\n // key corresponds to pointer or starts with \"@\"\n const isMulti =\n pointer.cardinality === Cardinality.AtLeastOne ||\n pointer.cardinality === Cardinality.Many;\n if (pointer.__kind__ === \"property\") {\n if (pointer.target.__name__ === \"std::json\") {\n }\n }\n\n const wrappedVal =\n val === null\n ? cast(pointer.target, null)\n : isMulti && Array.isArray(val)\n ? val.length === 0\n ? cast(pointer.target, null)\n : set(...val.map(v => (literal as any)(pointer.target, v)))\n : (literal as any)(pointer.target, val);\n newShape[key] = setModify\n ? ({[setModify]: wrappedVal} as any)\n : wrappedVal;\n }\n return newShape;\n}\n\nexport function insert(\n root: Root,\n shape: InsertShape\n): $expr_Insert {\n if (typeof shape !== \"object\") {\n throw new Error(\n `invalid insert shape.${\n typeof shape === \"function\"\n ? \" Hint: Insert shape is expected to be an object, \" +\n \"not a function returning a shape object.\"\n : \"\"\n }`\n );\n }\n const expr: any = {\n __kind__: ExpressionKind.Insert,\n __element__: root.__element__,\n __cardinality__: Cardinality.One,\n __expr__: root,\n __shape__: $normaliseInsertShape(root, shape)\n };\n (expr as any).unlessConflict = unlessConflict.bind(expr);\n return $expressionify($insertify(expr)) as any;\n}\n"},{"path":"json.ts","content":"import {ExpressionKind, TypeKind} from \"edgedb/_src/reflection/index.ts\";\nimport type {ParamType} from \"./typesystem.ts\";\nimport {encodeB64} from \"edgedb/_src/primitives/buffer.ts\";\nimport type {$expr_WithParams} from \"./params.ts\";\n\nfunction jsonStringify(type: ParamType, val: any): string {\n if (type.__kind__ === TypeKind.array) {\n if (Array.isArray(val)) {\n return `[${val\n .map(item => jsonStringify(type.__element__, item))\n .join()}]`;\n }\n throw new Error(`Param with array type is not an array`);\n }\n if (type.__kind__ === TypeKind.tuple) {\n if (!Array.isArray(val)) {\n throw new Error(`Param with tuple type is not an array`);\n }\n if (val.length !== type.__items__.length) {\n throw new Error(\n `Param with tuple type has incorrect number of items. Got ${val.length} expected ${type.__items__.length}`\n );\n }\n return `[${val\n .map((item, i) => jsonStringify(type.__items__[i], item))\n .join()}]`;\n }\n if (type.__kind__ === TypeKind.namedtuple) {\n if (typeof val !== \"object\") {\n throw new Error(`Param with named tuple type is not an object`);\n }\n if (Object.keys(val).length !== Object.keys(type.__shape__).length) {\n throw new Error(\n `Param with named tuple type has incorrect number of items. Got ${\n Object.keys(val).length\n } expected ${Object.keys(type.__shape__).length}`\n );\n }\n return `{${Object.entries(val)\n .map(([key, item]) => {\n if (!type.__shape__[key]) {\n throw new Error(\n `Unexpected key in named tuple param: ${key}, expected keys: ${Object.keys(\n type.__shape__\n ).join()}`\n );\n }\n return `\"${key}\": ${jsonStringify(type.__shape__[key], item)}`;\n })\n .join()}}`;\n }\n if (\n type.__kind__ === TypeKind.scalar\n // || type.__kind__ === TypeKind.castonlyscalar\n ) {\n switch (type.__name__) {\n case \"std::bigint\":\n return val.toString();\n case \"std::json\":\n return JSON.stringify(val);\n case \"std::bytes\":\n return `\"${encodeB64(val)}\"`;\n case \"cfg::memory\":\n return `\"${val.toString()}\"`;\n default:\n return JSON.stringify(val);\n }\n }\n if (type.__kind__ === TypeKind.enum) {\n return JSON.stringify(val);\n }\n throw new Error(`Invalid param type: ${(type as any).__kind__}`);\n}\n\nexport function jsonifyComplexParams(expr: any, _args: any) {\n if (_args && expr.__kind__ === ExpressionKind.WithParams) {\n const args = {..._args};\n for (const param of (expr as $expr_WithParams).__params__) {\n if (param.__isComplex__) {\n args[param.__name__] = jsonStringify(\n param.__element__ as any,\n args[param.__name__]\n );\n }\n }\n\n return args;\n }\n return _args;\n}\n"},{"path":"literal.ts","content":"import type {\n Expression,\n BaseType,\n BaseTypeToTsType,\n ScalarType\n} from \"./typesystem.ts\";\n\n// import {\n// Cardinality,\n// ExpressionKind,\n// BaseType,\n// BaseTypeToTsType,\n// makeType,\n// ScalarType\n// } from \"edgedb/_src/reflection/index.ts\";\n\n// import type {$expr_Literal} from \"./literal.ts\";\nimport {$expressionify} from \"./path.ts\";\nimport {spec} from \"./__spec__.ts\";\nimport {Cardinality, ExpressionKind} from \"edgedb/_src/reflection/index.ts\";\nimport {makeType} from \"./hydrate.ts\";\n\nexport type $expr_Literal = Expression<{\n __element__: Type;\n __cardinality__: Cardinality.One;\n __kind__: ExpressionKind.Literal;\n __value__: any;\n}>;\n\nexport function literal(\n type: T,\n value: BaseTypeToTsType\n): $expr_Literal {\n return $expressionify({\n __element__: type,\n __cardinality__: Cardinality.One,\n __kind__: ExpressionKind.Literal,\n __value__: value\n }) as any;\n}\n\nexport const $nameMapping = new Map([\n ...([...spec.values()].map(type => [type.name, type.id]) as any),\n [\"std::number\", \"00000000-0000-0000-0000-0000000001ff\"]\n]);\n\nexport function $getType(id: string): (val: any) => $expr_Literal {\n return makeType(spec, id, literal) as any;\n}\n\nexport function $getTypeByName(\n name: string\n): (val: any) => $expr_Literal {\n return makeType(spec, $nameMapping.get(name)!, literal) as any;\n}\n"},{"path":"operators.ts","content":"export declare function op(...args: any[]): any;\n"},{"path":"params.ts","content":"import type {Executor} from \"edgedb\";\nimport {\n ExpressionKind,\n Cardinality,\n TypeKind\n} from \"edgedb/_src/reflection/index.ts\";\nimport type {\n Expression,\n ParamType,\n setToTsType,\n TypeSet,\n BaseTypeToTsType\n} from \"./typesystem.ts\";\n\nimport {$expressionify} from \"./path.ts\";\n\nexport type $expr_OptionalParam = {\n __kind__: ExpressionKind.OptionalParam;\n __type__: Type;\n};\n\nexport function optional(\n type: Type\n): $expr_OptionalParam {\n return {\n __kind__: ExpressionKind.OptionalParam,\n __type__: type\n };\n}\n\nexport type QueryableWithParamsExpression<\n Set extends TypeSet = TypeSet,\n Params extends {\n [key: string]: ParamType | $expr_OptionalParam;\n } = {}\n> = Expression & {\n run(\n cxn: Executor,\n args: paramsToParamArgs\n ): Promise>;\n runJSON(cxn: Executor, args: paramsToParamArgs): Promise;\n};\n\nexport type $expr_WithParams<\n Params extends {\n [key: string]: ParamType | $expr_OptionalParam;\n } = {},\n Expr extends TypeSet = TypeSet\n> = QueryableWithParamsExpression<\n {\n __kind__: ExpressionKind.WithParams;\n __element__: Expr[\"__element__\"];\n __cardinality__: Expr[\"__cardinality__\"];\n __expr__: Expr;\n __params__: $expr_Param[];\n },\n Params\n>;\n\ntype paramsToParamArgs<\n Params extends {\n [key: string]: ParamType | $expr_OptionalParam;\n }\n> = {\n [key in keyof Params as Params[key] extends ParamType\n ? key\n : never]: Params[key] extends ParamType\n ? Readonly>\n : never;\n} & {\n [key in keyof Params as Params[key] extends $expr_OptionalParam\n ? key\n : never]?: Params[key] extends $expr_OptionalParam\n ? Readonly | null>\n : never;\n};\n\nexport type $expr_Param<\n Name extends string | number | symbol = string,\n Type extends ParamType = ParamType,\n Optional extends boolean = boolean\n> = Expression<{\n __kind__: ExpressionKind.Param;\n __element__: Type;\n __cardinality__: Optional extends true\n ? Cardinality.AtMostOne\n : Cardinality.One;\n __name__: Name;\n __isComplex__: boolean;\n}>;\n\ntype paramsToParamExprs<\n Params extends {\n [key: string]: ParamType | $expr_OptionalParam;\n }\n> = {\n [key in keyof Params]: Params[key] extends $expr_OptionalParam\n ? $expr_Param\n : Params[key] extends ParamType\n ? $expr_Param\n : never;\n};\n\nconst complexParamKinds = new Set([TypeKind.tuple, TypeKind.namedtuple]);\n\nexport function params<\n Params extends {\n [key: string]: ParamType | $expr_OptionalParam;\n } = {},\n Expr extends Expression = Expression\n>(\n paramsDef: Params,\n expr: (params: paramsToParamExprs) => Expr\n): $expr_WithParams {\n const paramExprs: {[key: string]: $expr_Param} = {};\n for (const [key, param] of Object.entries(paramsDef)) {\n const paramType =\n param.__kind__ === ExpressionKind.OptionalParam ? param.__type__ : param;\n const isComplex =\n complexParamKinds.has(paramType.__kind__) ||\n (paramType.__kind__ === TypeKind.array &&\n complexParamKinds.has(paramType.__element__.__kind__));\n paramExprs[key] = $expressionify({\n __kind__: ExpressionKind.Param,\n __element__: paramType,\n __cardinality__:\n param.__kind__ === ExpressionKind.OptionalParam\n ? Cardinality.AtMostOne\n : Cardinality.One,\n __name__: key,\n __isComplex__: isComplex\n }) as any;\n }\n\n const returnExpr = expr(paramExprs as any);\n\n return $expressionify({\n __kind__: ExpressionKind.WithParams,\n __element__: returnExpr.__element__,\n __cardinality__: returnExpr.__cardinality__,\n __expr__: returnExpr,\n __params__: Object.values(paramExprs)\n }) as any;\n}\n"},{"path":"path.ts","content":"import {\n // cardutil,\n // ObjectTypeSet,\n // TypeSet,\n // Expression,\n ExpressionKind,\n TypeKind,\n // LinkDesc,\n // PropertyDesc,\n Cardinality,\n // BaseType,\n typeutil\n} from \"edgedb/_src/reflection/index.ts\";\n\nimport {cardutil} from \"./cardinality.ts\";\n\nimport {literalToTypeSet} from \"./castMaps.ts\";\nimport {$arrayLikeIndexify, $tuplePathify} from \"./collections.ts\";\nimport {$toEdgeQL} from \"./toEdgeQL.ts\";\nimport {$queryFunc, $queryFuncJSON} from \"./query.ts\";\n\nimport type {\n BaseType,\n Expression,\n LinkDesc,\n ObjectType,\n ObjectTypePointers,\n ObjectTypeSet,\n PropertyDesc,\n PropertyShape,\n TypeSet\n} from \"./typesystem.ts\";\n// import {typeutil} from \"./typeutil.ts\";\n// import {cardutil} from \"./cardinality.ts\";\n\n// get the set representing the result of a path traversal\n// including cardinality merging\ntype getChildOfObjectTypeSet<\n Root extends ObjectTypeSet,\n ChildKey extends keyof Root[\"__element__\"][\"__pointers__\"]\n> = TypeSet<\n Root[\"__element__\"][\"__pointers__\"][ChildKey][\"target\"],\n cardutil.multiplyCardinalities<\n Root[\"__cardinality__\"],\n Root[\"__element__\"][\"__pointers__\"][ChildKey][\"cardinality\"]\n >\n>;\n\n// path parent must be object expression\nexport interface PathParent<\n Parent extends ObjectTypeSet = ObjectTypeSet,\n L extends string = string\n> {\n type: Parent;\n linkName: L;\n}\n\nexport type $linkPropify = Root extends {\n __parent__: PathParent;\n}\n ? // tslint:disable-next-line\n Parent[\"__element__\"][\"__pointers__\"][L] extends LinkDesc<\n any,\n any,\n infer LinkProps,\n any,\n any,\n any,\n any\n >\n ? pathifyLinkProps>\n : {}\n : unknown;\n\nexport type $pathify<\n Root extends TypeSet\n // Parent extends PathParent | null = null\n> = Root extends ObjectTypeSet\n ? ObjectTypeSet extends Root\n ? {} // Root is literally ObjectTypeSet\n : pathifyPointers & pathifyShape & $linkPropify\n : {}; // pathify does nothing on non-object types\n\nexport type pathifyPointers<\n Root extends ObjectTypeSet\n // Parent extends PathParent | null = null\n> = ObjectTypePointers extends Root[\"__element__\"][\"__pointers__\"]\n ? unknown\n : {\n // & string required to avoid typeError on linkName\n [k in keyof Root[\"__element__\"][\"__pointers__\"] &\n string]: Root[\"__element__\"][\"__pointers__\"][k] extends PropertyDesc\n ? $expr_PathLeaf<\n getChildOfObjectTypeSet,\n {type: anonymizeObjectTypeSet; linkName: k}\n // Root[\"__element__\"][\"__pointers__\"][k][\"exclusive\"]\n >\n : Root[\"__element__\"][\"__pointers__\"][k] extends LinkDesc\n ? getChildOfObjectTypeSet extends ObjectTypeSet\n ? $expr_PathNode<\n getChildOfObjectTypeSet,\n {type: anonymizeObjectTypeSet; linkName: k}\n // Root[\"__element__\"][\"__pointers__\"][k][\"exclusive\"]\n >\n : unknown\n : unknown;\n };\n\ntype anonymizeObjectTypeSet = typeutil.flatten<{\n __element__: ObjectType<\n T[\"__element__\"][\"__name__\"],\n T[\"__element__\"][\"__pointers__\"],\n {id: true}\n >;\n __cardinality__: T[\"__cardinality__\"];\n}>;\n\nexport type pathifyShape<\n Root extends ObjectTypeSet,\n Shape extends {[k: string]: any} = Root[\"__element__\"][\"__shape__\"]\n> = string extends keyof Shape\n ? {}\n : {\n [k in keyof Shape & string]: Shape[k] extends ObjectTypeSet\n ? $expr_PathNode<\n TypeSet<\n Shape[k][\"__element__\"],\n cardutil.multiplyCardinalities<\n Root[\"__cardinality__\"],\n Shape[k][\"__cardinality__\"]\n >\n >,\n {type: Root; linkName: k}\n // false\n >\n : Shape[k] extends TypeSet\n ? $expr_PathLeaf<\n TypeSet<\n Shape[k][\"__element__\"],\n cardutil.multiplyCardinalities<\n Root[\"__cardinality__\"],\n Shape[k][\"__cardinality__\"]\n >\n >,\n {type: Root; linkName: k}\n // false\n >\n : // must be unknown (not never) to avoid overriding\n // a pointer with the same key\n unknown;\n };\n\ntype pathifyLinkProps<\n Props extends PropertyShape,\n Root extends ObjectTypeSet,\n Parent extends PathParent | null = null\n> = {\n [k in keyof Props & string]: Props[k] extends PropertyDesc\n ? $expr_PathLeaf<\n TypeSet<\n Props[k][\"target\"],\n cardutil.multiplyCardinalities<\n Root[\"__cardinality__\"],\n Props[k][\"cardinality\"]\n >\n >,\n {type: $expr_PathNode; linkName: k}\n // {type: $expr_PathNode; linkName: k},\n // Props[k][\"exclusive\"]\n >\n : unknown;\n};\n\nexport type getPropsShape = typeutil.flatten<\n typeutil.stripNever<{\n [k in keyof T[\"__pointers__\"]]: T[\"__pointers__\"][k][\"__kind__\"] extends \"property\"\n ? true\n : never;\n }>\n>;\n\nexport type $expr_PathNode<\n Root extends ObjectTypeSet = ObjectTypeSet,\n Parent extends PathParent | null = PathParent | null\n // Exclusive extends boolean = boolean\n> = Expression<{\n __element__: Root[\"__element__\"];\n __cardinality__: Root[\"__cardinality__\"];\n __parent__: Parent;\n __kind__: ExpressionKind.PathNode;\n // __exclusive__: boolean;\n \"*\": getPropsShape;\n}>;\n\nexport type $expr_TypeIntersection<\n Card extends Cardinality = Cardinality,\n Intersection extends ObjectType = ObjectType\n> = Expression<{\n __element__: Intersection;\n __cardinality__: Card;\n __kind__: ExpressionKind.TypeIntersection;\n __expr__: TypeSet;\n}>;\n\nexport type $expr_PathLeaf<\n Root extends TypeSet = TypeSet,\n Parent extends PathParent = PathParent\n // Exclusive extends boolean = boolean\n> = Expression<{\n __element__: Root[\"__element__\"];\n __cardinality__: Root[\"__cardinality__\"];\n __kind__: ExpressionKind.PathLeaf;\n __parent__: Parent;\n // __exclusive__: boolean;\n}>;\n\nexport type ExpressionRoot = {\n __element__: BaseType;\n __cardinality__: Cardinality;\n __kind__: ExpressionKind;\n};\n\nfunction PathLeaf<\n Root extends TypeSet,\n Parent extends PathParent,\n Exclusive extends boolean = boolean\n>(\n root: Root,\n parent: Parent,\n exclusive: Exclusive,\n scopeRoot: TypeSet | null = null\n): $expr_PathLeaf {\n return $expressionify({\n __kind__: ExpressionKind.PathLeaf,\n __element__: root.__element__,\n __cardinality__: root.__cardinality__,\n __parent__: parent,\n // __exclusive__: exclusive,\n __scopeRoot__: scopeRoot\n }) as any;\n}\n\nfunction PathNode<\n Root extends ObjectTypeSet,\n Parent extends PathParent | null\n // Exclusive extends boolean = boolean\n>(\n root: Root,\n parent: Parent,\n // exclusive: boolean,\n scopeRoot: TypeSet | null = null\n): $expr_PathNode {\n const obj = {\n __kind__: ExpressionKind.PathNode,\n __element__: root.__element__,\n __cardinality__: root.__cardinality__,\n __parent__: parent,\n // __exclusive__: exclusive,\n __scopeRoot__: scopeRoot\n };\n\n const shape: any = {};\n Object.entries(obj.__element__.__pointers__).map(([key, ptr]) => {\n if (ptr.__kind__ === \"property\") {\n shape[key] = true;\n }\n });\n Object.defineProperty(obj, \"*\", {\n writable: false,\n value: shape\n });\n return $expressionify(obj) as any;\n}\n\nconst _pathCache = Symbol();\nconst _pointers = Symbol();\n\nconst pathifyProxyHandlers: ProxyHandler = {\n get(target: any, prop: string | symbol, proxy: any) {\n const ptr = target[_pointers][prop as any] as LinkDesc | PropertyDesc;\n if (ptr) {\n return (\n target[_pathCache][prop] ??\n (target[_pathCache][prop] = (\n (ptr.__kind__ === \"property\" ? PathLeaf : PathNode) as any\n )(\n {\n __element__: ptr.target,\n __cardinality__: cardutil.multiplyCardinalities(\n target.__cardinality__,\n ptr.cardinality\n )\n },\n {\n linkName: prop,\n type: proxy\n },\n ptr.exclusive ?? false,\n target.__scopeRoot__ ?? (scopeRoots.has(proxy) ? proxy : null)\n ))\n );\n }\n return target[prop];\n }\n};\n\nexport function $pathify(\n _root: Root\n): $pathify {\n if (_root.__element__.__kind__ !== TypeKind.object) {\n return _root as any;\n }\n\n const root: $expr_PathNode = _root as any;\n\n let pointers = {\n ...root.__element__.__pointers__\n };\n\n if (root.__parent__) {\n const {type, linkName} = root.__parent__;\n const parentPointer = type.__element__.__pointers__[linkName];\n if (parentPointer?.__kind__ === \"link\") {\n pointers = {...pointers, ...parentPointer.properties};\n }\n }\n\n for (const [key, val] of Object.entries(\n root.__element__.__shape__ || {id: true}\n )) {\n if (pointers[key]) continue;\n const valType: BaseType = (val as any)?.__element__;\n if (!valType) continue;\n\n pointers[key] = {\n __kind__: valType.__kind__ === TypeKind.object ? \"link\" : \"property\",\n properties: {},\n target: (val as any).__element__,\n cardinality: (val as any).__cardinality__,\n exclusive: false,\n computed: true,\n readonly: true,\n hasDefault: false\n };\n }\n\n (root as any)[_pointers] = pointers;\n (root as any)[_pathCache] = {};\n\n return new Proxy(root, pathifyProxyHandlers);\n}\n\nfunction isFunc(this: any, expr: ObjectTypeSet) {\n return $expressionify({\n __kind__: ExpressionKind.TypeIntersection,\n __cardinality__: this.__cardinality__,\n __element__: {\n ...expr.__element__,\n __shape__: {id: true}\n } as any,\n __expr__: this\n });\n}\n\nfunction assert_single(expr: Expression) {\n return $expressionify({\n __kind__: ExpressionKind.Function,\n __element__: expr.__element__,\n __cardinality__: cardutil.overrideUpperBound(expr.__cardinality__, \"One\"),\n __name__: \"std::assert_single\",\n __args__: [expr],\n __namedargs__: {}\n }) as any;\n}\n\nconst jsonDestructureProxyHandlers: ProxyHandler = {\n get(target: ExpressionRoot, prop: string | symbol, proxy: any) {\n if (typeof prop === \"string\" && !(prop in target)) {\n const parsedProp = Number.isInteger(Number(prop)) ? Number(prop) : prop;\n return jsonDestructure.call(proxy, parsedProp);\n }\n return (target as any)[prop];\n }\n};\n\nfunction jsonDestructure(this: ExpressionRoot, path: any) {\n const pathTypeSet = literalToTypeSet(path);\n return $expressionify({\n __kind__: ExpressionKind.Operator,\n __element__: this.__element__,\n __cardinality__: cardutil.multiplyCardinalities(\n this.__cardinality__,\n pathTypeSet.__cardinality__\n ),\n __name__: \"[]\",\n __opkind__: \"Infix\",\n __args__: [this, pathTypeSet]\n }) as any;\n}\n\nexport function $jsonDestructure(_expr: ExpressionRoot) {\n if (\n _expr.__element__.__kind__ === TypeKind.scalar &&\n _expr.__element__.__name__ === \"std::json\"\n ) {\n const expr = new Proxy(_expr, jsonDestructureProxyHandlers) as any;\n\n expr.destructure = jsonDestructure.bind(expr);\n\n return expr;\n }\n\n return _expr;\n}\n\nexport function $expressionify(\n _expr: T\n): Expression {\n const expr: Expression = $pathify(\n $jsonDestructure($arrayLikeIndexify($tuplePathify(_expr)))\n ) as any;\n\n expr.run = $queryFunc.bind(expr) as any;\n expr.runJSON = $queryFuncJSON.bind(expr) as any;\n expr.is = isFunc.bind(expr) as any;\n expr.toEdgeQL = $toEdgeQL.bind(expr);\n expr.assert_single = () => assert_single(expr) as any;\n\n return Object.freeze(expr) as any;\n}\n\nconst scopedExprCache = new WeakMap();\nconst scopeRoots = new WeakSet();\n\nexport function $getScopedExpr(\n expr: T,\n existingScopes?: Set\n): Expression {\n let scopedExpr = scopedExprCache.get(expr);\n if (!scopedExpr || existingScopes?.has(scopedExpr)) {\n // free objects should not be scopified\n const isFreeObject =\n expr.__cardinality__ === Cardinality.One &&\n expr.__element__.__name__ === \"std::FreeObject\";\n\n const isInsert = expr.__kind__ === ExpressionKind.Insert;\n scopedExpr =\n isFreeObject || isInsert\n ? (expr as any as Expression>)\n : $expressionify({\n ...expr,\n __cardinality__: Cardinality.One,\n __scopedFrom__: expr,\n \"*\": (expr as any)[\"*\"]\n });\n scopeRoots.add(scopedExpr);\n const uncached = !scopedExpr;\n if (uncached) {\n scopedExprCache.set(expr, scopedExpr);\n }\n }\n existingScopes?.add(scopedExpr);\n return scopedExpr as any;\n}\n\nexport {PathLeaf as $PathLeaf, PathNode as $PathNode};\n"},{"path":"query.ts","content":"import type * as edgedb from \"edgedb\";\nimport {Cardinality, ExpressionKind} from \"edgedb/_src/reflection/index.ts\";\nimport {jsonifyComplexParams} from \"./json.ts\";\nimport {select} from \"./select.ts\";\n\nconst runnableExpressionKinds = new Set([\n ExpressionKind.Select,\n ExpressionKind.Update,\n ExpressionKind.Insert,\n ExpressionKind.InsertUnlessConflict,\n ExpressionKind.Delete,\n ExpressionKind.Group,\n ExpressionKind.For,\n ExpressionKind.With,\n ExpressionKind.WithParams\n]);\n\nconst wrappedExprCache = new WeakMap();\n\nexport async function $queryFunc(this: any, cxn: edgedb.Executor, args: any) {\n const expr = runnableExpressionKinds.has(this.__kind__)\n ? this\n : wrappedExprCache.get(this) ??\n wrappedExprCache.set(this, select(this)).get(this);\n\n const _args = jsonifyComplexParams(expr, args);\n\n const query = expr.toEdgeQL();\n\n if (\n expr.__cardinality__ === Cardinality.One ||\n expr.__cardinality__ === Cardinality.AtMostOne ||\n expr.__cardinality__ === Cardinality.Empty\n ) {\n return cxn.querySingle(query, _args);\n } else {\n return cxn.query(query, _args);\n }\n}\n\nexport async function $queryFuncJSON(\n this: any,\n cxn: edgedb.Executor,\n args: any\n) {\n const expr = runnableExpressionKinds.has(this.__kind__)\n ? this\n : wrappedExprCache.get(this) ??\n wrappedExprCache.set(this, select(this)).get(this);\n const _args = jsonifyComplexParams(expr, args);\n\n if (\n expr.__cardinality__ === Cardinality.One ||\n expr.__cardinality__ === Cardinality.AtMostOne\n ) {\n return cxn.querySingleJSON(expr.toEdgeQL(), _args);\n } else {\n return cxn.queryJSON(expr.toEdgeQL(), _args);\n }\n}\n"},{"path":"range.ts","content":"import type {LocalDate, LocalDateTime, Duration} from \"edgedb\";\nimport {Range} from \"edgedb\";\nimport {TypeKind, ExpressionKind} from \"edgedb/_src/reflection/index.ts\";\n\nimport type {cardutil} from \"./cardinality.ts\";\nimport type {\n RangeType,\n getPrimitiveBaseType,\n TypeSet,\n BaseType\n} from \"./typesystem.ts\";\nimport type {$expr_Literal} from \"./literal.ts\";\n\nimport type {\n $number,\n $decimal,\n $datetime,\n $duration,\n $bool\n} from \"./modules/std.ts\";\nimport type {$local_date, $local_datetime} from \"./modules/cal.ts\";\nimport type {literalToScalarType, orScalarLiteral} from \"./castMaps.ts\";\nimport {literalToTypeSet} from \"./castMaps.ts\";\nimport {spec} from \"./__spec__.ts\";\nimport {literal, $nameMapping} from \"./literal.ts\";\nimport {$expr_Function, $resolveOverload} from \"./funcops.ts\";\nimport {$expressionify} from \"./path.ts\";\n\ntype $anypoint =\n | $number\n | $local_date\n | $decimal\n | $datetime\n | $local_datetime\n | $duration;\n\nfunction range(\n element: Element\n): RangeType;\nfunction range(\n val: Range\n): $expr_Literal>>>;\nfunction range<\n NamedArgs extends {\n inc_lower?: orScalarLiteral>;\n inc_upper?: orScalarLiteral>;\n empty?: orScalarLiteral>;\n },\n P1 extends orScalarLiteral> | undefined,\n P2 extends\n | orScalarLiteral<\n TypeSet<\n BaseType extends literalToScalarType\n ? $anypoint\n : getPrimitiveBaseType>\n >\n >\n | undefined\n>(\n namedArgs: NamedArgs,\n lower?: P1,\n upper?: P2\n): $expr_Function<\n // \"std::range\",\n // mapLiteralToTypeSet<[P1, P2]>,\n // mapLiteralToTypeSet,\n // TypeSet<\n RangeType<\n literalToScalarType extends $anypoint\n ? literalToScalarType\n : literalToScalarType extends $anypoint\n ? literalToScalarType\n : $anypoint\n >,\n cardutil.multiplyCardinalities<\n cardutil.multiplyCardinalities<\n cardutil.multiplyCardinalities<\n cardutil.multiplyCardinalities<\n cardutil.optionalParamCardinality,\n cardutil.optionalParamCardinality\n >,\n cardutil.optionalParamCardinality\n >,\n cardutil.optionalParamCardinality\n >,\n cardutil.optionalParamCardinality\n >\n // >\n>;\nfunction range<\n P1 extends orScalarLiteral> | undefined,\n P2 extends\n | orScalarLiteral<\n TypeSet<\n BaseType extends literalToScalarType\n ? $anypoint\n : getPrimitiveBaseType>\n >\n >\n | undefined\n>(\n lower?: P1,\n upper?: P2\n): $expr_Function<\n // \"std::range\",\n // mapLiteralToTypeSet<[P1, P2]>,\n // {},\n // TypeSet<\n RangeType<\n literalToScalarType extends $anypoint\n ? literalToScalarType\n : literalToScalarType extends $anypoint\n ? literalToScalarType\n : $anypoint\n >,\n cardutil.multiplyCardinalities<\n cardutil.optionalParamCardinality,\n cardutil.optionalParamCardinality\n >\n // >\n>;\nfunction range(...args: any[]): any {\n if (args.length === 1) {\n const arg = args[0];\n if (arg instanceof Range) {\n if (arg.lower === null && arg.upper === null) {\n throw new Error(\n `Can't create literal expression from unbounded range. Try this instead:\\n\\n e.range(e.cast(e.int64, e.set()), e.cast(e.int64, e.set()))`\n );\n }\n if (arg.isEmpty) {\n throw new Error(`Can't create literal expression from empty range.`);\n }\n return literal(\n range(literalToTypeSet(arg.lower ?? arg.upper).__element__ as any),\n arg\n );\n }\n if (arg.__kind__ && !arg.__element__) {\n return {\n __kind__: TypeKind.range,\n __name__: `range<${arg.__name__}>`,\n __element__: arg\n } as any;\n }\n }\n const {\n returnType,\n cardinality,\n args: positionalArgs,\n namedArgs\n } = $resolveOverload(\"std::range\", args, spec, [\n {\n args: [\n {\n typeId: $nameMapping.get(\"std::anypoint\")!,\n optional: true,\n setoftype: false,\n variadic: false\n },\n {\n typeId: $nameMapping.get(\"std::anypoint\")!,\n optional: true,\n setoftype: false,\n variadic: false\n }\n ],\n namedArgs: {\n inc_lower: {\n typeId: $nameMapping.get(\"std::bool\")!,\n optional: true,\n setoftype: false,\n variadic: false\n },\n inc_upper: {\n typeId: $nameMapping.get(\"std::bool\")!,\n optional: true,\n setoftype: false,\n variadic: false\n },\n empty: {\n typeId: $nameMapping.get(\"std::bool\")!,\n optional: true,\n setoftype: false,\n variadic: false\n }\n },\n returnTypeId: $nameMapping.get(\"range\")!\n }\n ]);\n return $expressionify({\n __kind__: ExpressionKind.Function,\n __element__: returnType,\n __cardinality__: cardinality,\n __name__: \"std::range\",\n __args__: positionalArgs,\n __namedargs__: namedArgs\n }) as any;\n}\n\nexport {range as $range};\n"},{"path":"reflection.ts","content":"export * from \"edgedb/_src/reflection/index.ts\";\nexport * from \"./typesystem.ts\";\nexport {cardutil} from \"./cardinality.ts\";\nexport type {$expr_Literal} from \"./literal.ts\";\nexport type {$expr_PathNode, $expr_PathLeaf} from \"./path.ts\";\nexport type {$expr_Function, $expr_Operator} from \"./funcops.ts\";\nexport {makeType, $mergeObjectTypes} from \"./hydrate.ts\";\nexport type {mergeObjectTypes} from \"./hydrate.ts\";\n"},{"path":"select.ts","content":"import {\n LocalDateTime,\n LocalDate,\n LocalTime,\n Duration,\n RelativeDuration,\n ConfigMemory,\n DateDuration\n} from \"edgedb\";\nimport type {$bool, $number} from \"./modules/std.ts\";\n\nimport {\n Cardinality,\n ExpressionKind,\n TypeKind,\n OperatorKind\n} from \"edgedb/_src/reflection/index.ts\";\nimport {makeType} from \"./hydrate.ts\";\n\nimport {cardutil} from \"./cardinality.ts\";\nimport type {\n $expr_PolyShapeElement,\n $scopify,\n Expression,\n LinkDesc,\n ObjectType,\n ObjectTypeExpression,\n ObjectTypePointers,\n ObjectTypeSet,\n PrimitiveTypeSet,\n PropertyDesc,\n ScalarType,\n stripSet,\n TypeSet,\n BaseType,\n ExclusiveTuple,\n orLiteralValue\n} from \"./typesystem.ts\";\n\nimport type {\n $expr_PathLeaf,\n $expr_PathNode,\n $linkPropify,\n ExpressionRoot\n} from \"./path.ts\";\nimport type {anonymizeObject} from \"./casting.ts\";\nimport {$expressionify, $getScopedExpr} from \"./path.ts\";\nimport {$getTypeByName, literal} from \"./literal.ts\";\nimport {spec} from \"./__spec__.ts\";\nimport {\n scalarLiterals,\n literalToScalarType,\n literalToTypeSet\n} from \"./castMaps.ts\";\nimport type {$expr_Operator} from \"./funcops.ts\";\n\nexport const ASC: \"ASC\" = \"ASC\";\nexport const DESC: \"DESC\" = \"DESC\";\nexport const EMPTY_FIRST: \"EMPTY FIRST\" = \"EMPTY FIRST\";\nexport const EMPTY_LAST: \"EMPTY LAST\" = \"EMPTY LAST\";\nexport type OrderByDirection = \"ASC\" | \"DESC\";\nexport type OrderByEmpty = \"EMPTY FIRST\" | \"EMPTY LAST\";\n\nexport type OrderByExpr = TypeSet;\nexport type OrderByObjExpr = {\n expression: OrderByExpr;\n direction?: OrderByDirection;\n empty?: OrderByEmpty;\n};\n\nexport type OrderByExpression =\n | OrderByExpr\n | OrderByObjExpr\n | [OrderByExpr | OrderByObjExpr, ...(OrderByExpr | OrderByObjExpr)[]];\n\nexport type OffsetExpression = TypeSet<\n $number,\n Cardinality.Empty | Cardinality.One | Cardinality.AtMostOne\n>;\n\nexport type SelectFilterExpression = TypeSet<$bool, Cardinality>;\nexport type LimitOffsetExpression = TypeSet<\n $number,\n Cardinality.Empty | Cardinality.One | Cardinality.AtMostOne\n>;\nexport type LimitExpression = TypeSet<\n $number,\n Cardinality.Empty | Cardinality.One | Cardinality.AtMostOne\n>;\n\nexport type SelectModifierNames =\n | \"filter\"\n | \"filter_single\"\n | \"order_by\"\n | \"offset\"\n | \"limit\";\n\nexport type exclusivesToFilterSingle =\n ExclusiveTuple extends E\n ? never\n : E extends []\n ? never\n : {\n [j in keyof E]: {\n [k in keyof E[j]]: orLiteralValue;\n // asdf: T[\"__exclusives__\"][0].asdf\n };\n }[number];\nexport type SelectModifiers = {\n // export type SelectModifiers = {\n filter?: SelectFilterExpression;\n filter_single?: // | Partial<\n // typeutil.stripNever<{\n // [k in keyof T[\"__pointers__\"]]: T[\"__pointers__\"][k]\n // extends PropertyDesc\n // ? orScalarLiteral<{\n // __element__: T[\"__pointers__\"][k][\"target\"];\n // __cardinality__: T[\"__pointers__\"][k][\"cardinality\"];\n // }>\n // : never;\n // }>\n // >\n\n // | (ObjectType extends T\n // ? unknown\n // : typeutil.stripNever<{\n // [k in keyof T[\"__pointers__\"]]: T[\"__pointers__\"][k]\n // extends PropertyDesc<\n // infer T,\n // infer C,\n // infer E\n // >\n // ? E extends true\n // ? orScalarLiteral<{\n // __element__: T;\n // __cardinality__: C;\n // }>\n // : never\n // : never;\n // }>)\n exclusivesToFilterSingle | SelectFilterExpression;\n\n // | (ObjectType extends T\n // ? unknown\n // : typeutil.stripNever<{\n // [k in keyof T[\"__pointers__\"]]: T[\"__pointers__\"][k]\n // extends PropertyDesc<\n // infer T,\n // infer C,\n // infer E\n // >\n // ? E extends true\n // ? orScalarLiteral<{\n // __element__: T;\n // __cardinality__: C;\n // }>\n // : never\n // : never;\n // }>);\n order_by?: OrderByExpression;\n offset?: OffsetExpression | number;\n limit?: LimitExpression | number;\n};\n\nexport type UnknownSelectModifiers = {[k in keyof SelectModifiers]: unknown};\n\nexport type NormalisedSelectModifiers = {\n filter?: SelectFilterExpression;\n order_by?: OrderByObjExpr[];\n offset?: OffsetExpression;\n limit?: LimitExpression;\n singleton: boolean;\n};\n\n// type NormaliseOrderByModifier =\n// Mods extends OrderByExpr\n// ? [{expression: Mods}]\n// : Mods extends OrderByObjExpr\n// ? [Mods]\n// : Mods extends (OrderByExpr | OrderByObjExpr)[]\n// ? {\n// [K in keyof Mods]: Mods[K] extends OrderByExpr\n// ? {expression: Mods[K]}\n// : Mods[K];\n// }\n// : [];\n\n// type NormaliseSelectModifiers = {\n// filter: Mods[\"filter\"];\n// order_by: Mods[\"order_by\"] extends OrderByExpression\n// ? NormaliseOrderByModifier\n// : [];\n// offset: Mods[\"offset\"] extends number\n// ? $expr_Literal>\n// : Mods[\"offset\"];\n// limit: Mods[\"offset\"] extends number\n// ? $expr_Literal>\n// : Mods[\"offset\"];\n// };\n\nexport type $expr_Select = Expression<{\n __element__: Set[\"__element__\"];\n __cardinality__: Set[\"__cardinality__\"];\n __expr__: TypeSet;\n __kind__: ExpressionKind.Select;\n __modifiers__: NormalisedSelectModifiers;\n __scope__?: ObjectTypeExpression;\n}>;\n// Modifier methods removed for now, until we can fix typescript inference\n// problems / excessively deep errors\n// & SelectModifierMethods>;\n\nexport interface SelectModifierMethods {\n filter(\n filter:\n | Filter\n | ((\n scope: Root extends ObjectTypeSet\n ? $scopify\n : stripSet\n ) => Filter)\n ): this;\n order_by(\n order_by:\n | OrderByExpression\n | ((\n scope: Root extends ObjectTypeSet\n ? $scopify\n : stripSet\n ) => OrderByExpression)\n ): this;\n offset(\n offset:\n | OffsetExpression\n | number\n | ((\n scope: Root extends ObjectTypeSet\n ? $scopify\n : stripSet\n ) => OffsetExpression | number)\n ): this;\n // $expr_Select<{\n // __element__: Root[\"__element__\"];\n // __cardinality__: cardutil.overrideLowerBound<\n // Root[\"__cardinality__\"],\n // \"Zero\"\n // >;\n // }>;\n limit(\n limit:\n | LimitExpression\n | number\n | ((\n scope: Root extends ObjectTypeSet\n ? $scopify\n : stripSet\n ) => LimitExpression | number)\n ): this;\n // $expr_Select<{\n // __element__: Root[\"__element__\"];\n // __cardinality__: cardutil.overrideLowerBound<\n // Root[\"__cardinality__\"],\n // \"Zero\"\n // >;\n // }>;\n}\n// Base is ObjectTypeSet &\n// Filter is equality &\n// Filter.args[0] is PathLeaf\n// Filter.args[0] is __exclusive__ &\n// Filter.args[0].parent.__element__ === Base.__element__\n// Filter.args[1].__cardinality__ is AtMostOne or One\n// if Filter.args[0] is PathNode:\n// Filter.args[0] is __exclusive__ &\n// if Filter.args[0].parent === null\n// Filter.args[0].parent.__element__ === Base.__element__\n// Filter.args[1].__cardinality__ is AtMostOne or One\n// else\n// Filter.args[0].type.__element__ === Base.__element__ &\n// Filter.args[1].__cardinality__ is AtMostOne or One\n\n// type argCardToResultCard<\n// OpCard extends Cardinality,\n// BaseCase extends Cardinality\n// > = [OpCard] extends [Cardinality.AtMostOne | Cardinality.One]\n// ? Cardinality.AtMostOne\n// : [OpCard] extends [Cardinality.Empty]\n// ? Cardinality.Empty\n// : BaseCase;\n\n// export type InferFilterCardinality<\n// Base extends TypeSet,\n// Filter\n// > = Filter extends TypeSet\n// ? // Base is ObjectTypeExpression &\n// Base extends ObjectTypeSet // $expr_PathNode\n// ? // Filter is equality\n// Filter extends $expr_Operator<\"=\", any, infer Args, any>\n// ? // Filter.args[0] is PathLeaf\n// Args[0] extends $expr_PathLeaf\n// ? // Filter.args[0] is unique\n// Args[0][\"__exclusive__\"] extends true\n// ? // Filter.args[0].parent.__element__ === Base.__element__\n// typeutil.assertEqual extends true\n// ? // Filter.args[1].__cardinality__ is AtMostOne or One\n// argCardToResultCard<\n// Args[1][\"__cardinality__\"],\n// Base[\"__cardinality__\"]\n// >\n// : Base[\"__cardinality__\"]\n// : Base[\"__cardinality__\"]\n// : Args[0] extends $expr_PathNode\n// ? Args[0][\"__exclusive__\"] extends true\n// ? // Filter.args[0].parent.__element__ === Base.__element__\n// Args[0][\"__parent__\"] extends null\n// ? typeutil.assertEqual<\n// Args[0][\"__element__\"][\"__name__\"],\n// Base[\"__element__\"][\"__name__\"]\n// > extends true\n// ? // Filter.args[1].__cardinality__ is AtMostOne or One\n// argCardToResultCard<\n// Args[1][\"__cardinality__\"],\n// Base[\"__cardinality__\"]\n// >\n// : Base[\"__cardinality__\"]\n// : Args[0][\"__parent__\"] extends infer Parent\n// ? Parent extends PathParent\n// ? typeutil.assertEqual<\n// Parent[\"type\"][\"__element__\"][\"__name__\"],\n// Base[\"__element__\"][\"__name__\"]\n// > extends true\n// ? // Filter.args[1].__cardinality__ is AtMostOne or One\n// argCardToResultCard<\n// Args[1][\"__cardinality__\"],\n// Base[\"__cardinality__\"]\n// >\n// : Base[\"__cardinality__\"]\n// : Base[\"__cardinality__\"]\n// : Base[\"__cardinality__\"]\n// : Base[\"__cardinality__\"]\n// : Base[\"__cardinality__\"]\n// : Base[\"__cardinality__\"]\n// : Base[\"__cardinality__\"]\n// : Base[\"__cardinality__\"];\n\nexport type InferOffsetLimitCardinality<\n Card extends Cardinality,\n Modifers extends UnknownSelectModifiers\n> = Modifers[\"limit\"] extends number | LimitExpression\n ? cardutil.overrideLowerBound\n : Modifers[\"offset\"] extends number | OffsetExpression\n ? cardutil.overrideLowerBound\n : Card;\n\n// export type ComputeSelectCardinality<\n// Expr extends ObjectTypeExpression,\n// Modifiers extends UnknownSelectModifiers\n// > = InferOffsetLimitCardinality<\n// InferFilterCardinality,\n// Modifiers\n// >;\nexport type ComputeSelectCardinality<\n Expr extends ObjectTypeExpression,\n Modifiers extends UnknownSelectModifiers\n> = InferOffsetLimitCardinality<\n undefined extends Modifiers[\"filter_single\"]\n ? Expr[\"__cardinality__\"]\n : cardutil.overrideUpperBound,\n Modifiers\n>;\n\nexport function is<\n Expr extends ObjectTypeExpression,\n Shape extends objectTypeToSelectShape\n>(\n expr: Expr,\n shape: Shape\n): {\n [k in Exclude]: $expr_PolyShapeElement<\n Expr,\n normaliseElement\n >;\n} {\n const mappedShape: any = {};\n for (const [key, value] of Object.entries(shape)) {\n mappedShape[key] = {\n __kind__: ExpressionKind.PolyShapeElement,\n __polyType__: expr,\n __shapeElement__: value\n };\n }\n return mappedShape;\n}\n\n// function computeFilterCardinality(\n// expr: SelectFilterExpression,\n// cardinality: Cardinality,\n// base: TypeSet\n// ) {\n// let card = cardinality;\n\n// const filter: any = expr;\n// // Base is ObjectExpression\n// const baseIsObjectExpr = base?.__element__?.__kind__ === TypeKind.object;\n// const filterExprIsEq =\n// filter.__kind__ === ExpressionKind.Operator && filter.__name__ === \"=\";\n// const arg0: $expr_PathLeaf | $expr_PathNode = filter?.__args__?.[0];\n// const arg1: TypeSet = filter?.__args__?.[1];\n// const argsExist = !!arg0 && !!arg1 && !!arg1.__cardinality__;\n// const arg0IsUnique = arg0?.__exclusive__ === true;\n\n// if (baseIsObjectExpr && filterExprIsEq && argsExist && arg0IsUnique) {\n// const newCard =\n// arg1.__cardinality__ === Cardinality.One ||\n// arg1.__cardinality__ === Cardinality.AtMostOne\n// ? Cardinality.AtMostOne\n// : arg1.__cardinality__ === Cardinality.Empty\n// ? Cardinality.Empty\n// : cardinality;\n\n// if (arg0.__kind__ === ExpressionKind.PathLeaf) {\n// const arg0ParentMatchesBase =\n// arg0.__parent__.type.__element__.__name__ ===\n// base.__element__.__name__;\n// if (arg0ParentMatchesBase) {\n// card = newCard;\n// }\n// } else if (arg0.__kind__ === ExpressionKind.PathNode) {\n// // if Filter.args[0] is PathNode:\n// // Filter.args[0] is __exclusive__ &\n// // if Filter.args[0].parent === null\n// // Filter.args[0].__element__ === Base.__element__\n// // Filter.args[1].__cardinality__ is AtMostOne or One\n// // else\n// // Filter.args[0].type.__element__ === Base.__element__ &\n// // Filter.args[1].__cardinality__ is AtMostOne or One\n// const parent = arg0.__parent__;\n// if (parent === null) {\n// const arg0MatchesBase =\n// arg0.__element__.__name__ === base.__element__.__name__;\n// if (arg0MatchesBase) {\n// card = newCard;\n// }\n// } else {\n// const arg0ParentMatchesBase =\n// parent?.type.__element__.__name__ === base.__element__.__name__;\n// if (arg0ParentMatchesBase) {\n// card = newCard;\n// }\n// }\n// }\n// }\n\n// return card;\n// }\n\nexport function $handleModifiers(\n modifiers: SelectModifiers,\n params: {root: TypeSet; scope: TypeSet}\n): {modifiers: NormalisedSelectModifiers; cardinality: Cardinality} {\n const {root, scope} = params;\n const mods: NormalisedSelectModifiers = {\n singleton: !!modifiers[\"filter_single\"]\n };\n\n let card = root.__cardinality__;\n\n if (modifiers.filter) {\n mods.filter = modifiers.filter;\n // card = computeFilterCardinality(mods.filter, card, rootExpr);\n }\n\n if (modifiers.filter_single) {\n if (root.__element__.__kind__ !== TypeKind.object) {\n throw new Error(\"filter_single can only be used with object types\");\n }\n card = Cardinality.AtMostOne;\n // mods.filter = modifiers.filter_single;\n const fs: any = modifiers.filter_single;\n if (fs.__element__) {\n mods.filter = modifiers.filter_single as any;\n } else {\n const exprs = Object.keys(fs).map(key => {\n const val = fs[key].__element__\n ? fs[key]\n : (literal as any)(\n (root.__element__ as any as ObjectType)[\"__pointers__\"][key][\n \"target\"\n ],\n fs[key]\n );\n return $expressionify({\n __element__: {\n __name__: \"std::bool\",\n __kind__: TypeKind.scalar\n } as any,\n __cardinality__: Cardinality.One,\n __kind__: ExpressionKind.Operator,\n __opkind__: OperatorKind.Infix,\n __name__: \"=\",\n __args__: [(scope as any)[key], val]\n }) as $expr_Operator;\n });\n if (exprs.length === 1) {\n mods.filter = exprs[0] as any;\n } else {\n mods.filter = exprs.reduce((a, b) => {\n return $expressionify({\n __element__: {\n __name__: \"std::bool\",\n __kind__: TypeKind.scalar\n } as any,\n __cardinality__: Cardinality.One,\n __kind__: ExpressionKind.Operator,\n __opkind__: OperatorKind.Infix,\n __name__: \"and\",\n __args__: [a, b]\n }) as $expr_Operator;\n }) as any;\n }\n }\n }\n if (modifiers.order_by) {\n const orderExprs = Array.isArray(modifiers.order_by)\n ? modifiers.order_by\n : [modifiers.order_by];\n mods.order_by = orderExprs.map(expr =>\n typeof (expr as any).__element__ === \"undefined\"\n ? expr\n : {expression: expr}\n ) as any;\n }\n if (modifiers.offset) {\n mods.offset =\n typeof modifiers.offset === \"number\"\n ? ($getTypeByName(\"std::number\")(modifiers.offset) as any)\n : modifiers.offset;\n card = cardutil.overrideLowerBound(card, \"Zero\");\n }\n if (modifiers.limit) {\n let expr: LimitExpression;\n if (typeof modifiers.limit === \"number\") {\n expr = $getTypeByName(\"std::number\")(modifiers.limit) as any;\n } else if ((modifiers.limit as any).__kind__ === ExpressionKind.Set) {\n expr = (modifiers.limit as any).__exprs__[0];\n } else {\n throw new Error(\"Invalid value for `limit` modifier\");\n }\n mods.limit = expr;\n card = cardutil.overrideLowerBound(card, \"Zero\");\n }\n\n return {modifiers: mods as NormalisedSelectModifiers, cardinality: card};\n}\n\nexport type $expr_Delete =\n Expression<{\n __kind__: ExpressionKind.Delete;\n __element__: Root[\"__element__\"];\n __cardinality__: Root[\"__cardinality__\"];\n __expr__: ObjectTypeSet;\n }>;\n\nfunction deleteExpr<\n Expr extends ObjectTypeExpression,\n Modifiers extends SelectModifiers\n>(\n expr: Expr,\n modifiers?: (scope: $scopify) => Readonly\n): $expr_Delete<{\n __element__: ObjectType<\n Expr[\"__element__\"][\"__name__\"],\n Expr[\"__element__\"][\"__pointers__\"],\n {id: true}\n >;\n __cardinality__: ComputeSelectCardinality;\n}>;\nfunction deleteExpr(expr: any, modifiersGetter: any) {\n const selectExpr = select(expr, modifiersGetter);\n\n return $expressionify({\n __kind__: ExpressionKind.Delete,\n __element__: selectExpr.__element__,\n __cardinality__: selectExpr.__cardinality__,\n __expr__: selectExpr\n }) as any;\n}\n\nexport {deleteExpr as delete};\n\n// Modifier methods removed for now, until we can fix typescript inference\n// problems / excessively deep errors\n\n// function resolveModifierGetter(parent: any, modGetter: any) {\n// if (typeof modGetter === \"function\" && !modGetter.__kind__) {\n// if (parent.__expr__.__element__.__kind__ === TypeKind.object) {\n// const shape = parent.__element__.__shape__;\n// const _scope =\n// parent.__scope__ ?? $getScopedExpr(parent.__expr__,\n// $existingScopes);\n// const scope = new Proxy(_scope, {\n// get(target: any, prop: string) {\n// if (shape[prop] && shape[prop] !== true) {\n// return shape[prop];\n// }\n// return target[prop];\n// },\n// });\n// return {\n// scope: _scope,\n// modExpr: modGetter(scope),\n// };\n// } else {\n// return {\n// scope: undefined,\n// modExpr: modGetter(parent.__expr__),\n// };\n// }\n// } else {\n// return {scope: parent.__scope__, modExpr: modGetter};\n// }\n// }\n\n// function updateModifier(\n// parent: any,\n// modName: \"filter\" | \"order_by\" | \"offset\" | \"limit\",\n// modGetter: any\n// ) {\n// const modifiers = {\n// ...parent.__modifiers__,\n// };\n// const cardinality = parent.__cardinality__;\n\n// const {modExpr, scope} = resolveModifierGetter(parent, modGetter);\n\n// switch (modName) {\n// case \"filter\":\n// modifiers.filter = modifiers.filter\n// ? op(modifiers.filter, \"and\", modExpr)\n// : modExpr;\n\n// // methods no longer change cardinality\n// // cardinality = computeFilterCardinality(\n// // modExpr,\n// // cardinality,\n// // parent.__expr__\n// // );\n// break;\n// case \"order_by\":\n// const ordering =\n// typeof (modExpr as any).__element__ === \"undefined\"\n// ? modExpr\n// : {expression: modExpr};\n// modifiers.order_by = modifiers.order_by\n// ? [...modifiers.order_by, ordering]\n// : [ordering];\n// break;\n// case \"offset\":\n// modifiers.offset =\n// typeof modExpr === \"number\" ? _std.number(modExpr) : modExpr;\n// // methods no longer change cardinality\n// // cardinality = cardutil\n// .overrideLowerBound(cardinality, \"Zero\");\n// break;\n// case \"limit\":\n// modifiers.limit =\n// typeof modExpr === \"number\"\n// ? _std.number(modExpr)\n// : (modExpr as any).__kind__ === ExpressionKind.Set\n// ? (modExpr as any).__exprs__[0]\n// : modExpr;\n// // methods no longer change cardinality\n// // cardinality = cardutil\n// .overrideLowerBound(cardinality, \"Zero\");\n// break;\n// }\n\n// return $expressionify(\n// $selectify({\n// __kind__: ExpressionKind.Select,\n// __element__: parent.__element__,\n// __cardinality__: cardinality,\n// __expr__: parent.__expr__,\n// __modifiers__: modifiers,\n// __scope__: scope,\n// })\n// );\n// }\n\nexport function $selectify(expr: Expr) {\n // Object.assign(expr, {\n // filter: (filter: any) => updateModifier(expr, \"filter\", filter),\n // order_by: (order_by: any) => updateModifier(expr, \"order_by\", order_by),\n // offset: (offset: any) => updateModifier(expr, \"offset\", offset),\n // limit: (limit: any) => updateModifier(expr, \"limit\", limit),\n // });\n return expr;\n}\n\nexport type linkDescToLinkProps = {\n [k in keyof Desc[\"properties\"] & string]: $expr_PathLeaf<\n TypeSet<\n Desc[\"properties\"][k][\"target\"],\n Desc[\"properties\"][k][\"cardinality\"]\n >\n // {\n // type: $scopify;\n // linkName: k;\n // },\n // Desc[\"properties\"][k][\"exclusive\"]\n >;\n};\n\nexport type pointersToObjectType

= ObjectType<\n string,\n P,\n {}\n>;\n\ntype linkDescToShape = objectTypeToSelectShape<\n L[\"target\"]\n> &\n objectTypeToSelectShape> &\n SelectModifiers;\nexport type linkDescToSelectElement =\n | boolean\n // | pointerToCastableExpression\n | TypeSet<\n anonymizeObject,\n cardutil.assignable\n >\n | linkDescToShape\n | ((\n scope: $scopify & linkDescToLinkProps\n ) => linkDescToShape);\n\n// object types -> pointers\n// pointers -> links\n// links -> target object type\n// links -> link properties\nexport type objectTypeToSelectShape =\n // ObjectType extends T\n // ? {[k: string]: unknown}\n // :\n Partial<{\n [k in keyof T[\"__pointers__\"]]: T[\"__pointers__\"][k] extends PropertyDesc\n ?\n | boolean\n | TypeSet<\n T[\"__pointers__\"][k][\"target\"],\n cardutil.assignable\n >\n : T[\"__pointers__\"][k] extends LinkDesc\n ? linkDescToSelectElement\n : any;\n }> & {[k: string]: unknown};\n\n// incorporate __shape__ (computeds) on selection shapes\n// this works but a major rewrite of setToTsType is required\n// to incorporate __shape__-based selection shapes into\n// result type inference\n// & [k in keyof T[\"__shape__\"]]:\n// string | number | symbol extends k // Partial<{ // &\n// ? unknown\n// : T[\"__shape__\"][k] extends infer U\n// ? U extends ObjectTypeSet\n// ?\n// | boolean\n// | TypeSet<\n// anonymizeObject,\n// cardutil.assignable\n// >\n// | objectTypeToSelectShape\n// | ((\n// scope: $scopify\n// ) => objectTypeToSelectShape &\n// SelectModifiers)\n// : U extends TypeSet\n// ?\n// | boolean\n// | TypeSet<\n// U[\"__element__\"],\n// cardutil.assignable\n// >\n// : unknown\n// : unknown;\n// }>\n\nexport type normaliseElement = El extends boolean\n ? El\n : El extends TypeSet\n ? stripSet\n : El extends (...scope: any[]) => any\n ? normaliseShape>\n : El extends object\n ? normaliseShape>\n : stripSet;\n\nexport type normaliseShape<\n Shape extends object,\n Strip = SelectModifierNames\n> = {\n [k in Exclude]: normaliseElement;\n};\n\nconst $FreeObject = makeType(\n spec,\n [...spec.values()].find(s => s.name === \"std::FreeObject\")!.id,\n literal\n);\nconst FreeObject: $expr_PathNode = {\n __kind__: ExpressionKind.PathNode,\n __element__: $FreeObject as any,\n __cardinality__: Cardinality.One,\n __parent__: null,\n __exclusive__: true,\n __scopeRoot__: null\n} as any;\n\nexport const $existingScopes = new Set<\n Expression>\n>();\n\nfunction $shape<\n Expr extends ObjectTypeExpression,\n Shape extends objectTypeToSelectShape &\n SelectModifiers // \n>(\n expr: Expr,\n _shape: (\n scope: $scopify &\n $linkPropify<{\n [k in keyof Expr]: k extends \"__cardinality__\"\n ? Cardinality.One\n : Expr[k];\n }>\n ) => Readonly\n): (scope: unknown) => Readonly;\nfunction $shape(_a: unknown, b: (...args: any) => any) {\n return b;\n}\nexport {$shape as shape};\n\nexport function select(\n expr: Expr\n): $expr_Select<{\n __element__: ObjectType<\n `${Expr[\"__element__\"][\"__name__\"]}`, // _shape\n Expr[\"__element__\"][\"__pointers__\"],\n Expr[\"__element__\"][\"__shape__\"] // {id: true}\n >;\n __cardinality__: Expr[\"__cardinality__\"];\n}>;\nexport function select(\n expr: Expr\n): $expr_Select>;\nexport function select<\n Expr extends ObjectTypeExpression,\n Shape extends objectTypeToSelectShape &\n SelectModifiers,\n Modifiers extends UnknownSelectModifiers = Pick\n>(\n expr: Expr,\n shape: (\n scope: $scopify &\n $linkPropify<{\n [k in keyof Expr]: k extends \"__cardinality__\"\n ? Cardinality.One\n : Expr[k];\n }>\n ) => Readonly\n): $expr_Select<{\n __element__: ObjectType<\n `${Expr[\"__element__\"][\"__name__\"]}`, // _shape\n Expr[\"__element__\"][\"__pointers__\"],\n Omit, SelectModifierNames>\n >;\n __cardinality__: ComputeSelectCardinality;\n}>;\n/*\n\nFor the moment is isn't possible to implement both closure-based and plain\nobject overloads without breaking autocomplete on one or the other.\nThis is due to a limitation in TS:\n\nhttps://github.com/microsoft/TypeScript/issues/26892\nhttps://github.com/microsoft/TypeScript/issues/47081\n\n*/\n\nexport function select<\n Expr extends PrimitiveTypeSet,\n Modifiers extends SelectModifiers\n>(\n expr: Expr,\n modifiers: (expr: Expr) => Readonly\n): $expr_Select<{\n __element__: Expr[\"__element__\"];\n __cardinality__: InferOffsetLimitCardinality<\n Expr[\"__cardinality__\"],\n Modifiers\n >;\n}>;\nexport function select(\n shape: Shape\n): $expr_Select<{\n __element__: ObjectType<\n `std::FreeObject`,\n {\n [k in keyof Shape]: Shape[k][\"__element__\"] extends ObjectType\n ? LinkDesc<\n Shape[k][\"__element__\"],\n Shape[k][\"__cardinality__\"],\n {},\n false,\n true,\n true,\n false\n >\n : PropertyDesc<\n Shape[k][\"__element__\"],\n Shape[k][\"__cardinality__\"],\n false,\n true,\n true,\n false\n >;\n },\n Shape\n >; // _shape\n __cardinality__: Cardinality.One;\n}>;\nexport function select(\n expr: Expr\n): $expr_Select<{\n __element__: literalToScalarType;\n __cardinality__: Cardinality.One;\n}>;\nexport function select(...args: any[]) {\n const firstArg = args[0];\n\n if (\n typeof firstArg !== \"object\" ||\n firstArg instanceof Uint8Array ||\n firstArg instanceof Date ||\n firstArg instanceof Duration ||\n firstArg instanceof LocalDateTime ||\n firstArg instanceof LocalDate ||\n firstArg instanceof LocalTime ||\n firstArg instanceof RelativeDuration ||\n firstArg instanceof DateDuration ||\n firstArg instanceof ConfigMemory\n ) {\n const literalExpr = literalToTypeSet(firstArg);\n return $expressionify(\n $selectify({\n __kind__: ExpressionKind.Select,\n __element__: literalExpr.__element__,\n __cardinality__: literalExpr.__cardinality__,\n __expr__: literalExpr,\n __modifiers__: {}\n })\n ) as any;\n }\n\n const exprPair: [TypeSet, (scope: any) => any] =\n typeof args[0].__element__ !== \"undefined\"\n ? (args as any)\n : [FreeObject, () => args[0]];\n\n let expr = exprPair[0];\n const shapeGetter = exprPair[1];\n if (expr === FreeObject) {\n const freeObjectPtrs: ObjectTypePointers = {};\n for (const [k, v] of Object.entries(args[0]) as [string, TypeSet][]) {\n freeObjectPtrs[k] = {\n __kind__:\n v.__element__.__kind__ === TypeKind.object ? \"link\" : \"property\",\n target: v.__element__,\n\n cardinality: v.__cardinality__,\n exclusive: false,\n computed: true,\n readonly: true,\n hasDefault: false,\n properties: {}\n };\n }\n expr = {\n ...FreeObject,\n __element__: {\n ...FreeObject.__element__,\n __pointers__: {\n ...FreeObject.__element__.__pointers__,\n ...freeObjectPtrs\n }\n } as any\n };\n }\n if (!shapeGetter) {\n if (expr.__element__.__kind__ === TypeKind.object) {\n const objectExpr: ObjectTypeSet = expr as any;\n return $expressionify(\n $selectify({\n __kind__: ExpressionKind.Select,\n __element__: {\n __kind__: TypeKind.object,\n __name__: `${objectExpr.__element__.__name__}`, // _shape\n __pointers__: objectExpr.__element__.__pointers__,\n __shape__: objectExpr.__element__.__shape__\n } as any,\n __cardinality__: objectExpr.__cardinality__,\n __expr__: objectExpr,\n __modifiers__: {}\n })\n ) as any;\n } else {\n return $expressionify(\n $selectify({\n __kind__: ExpressionKind.Select,\n __element__: expr.__element__,\n __cardinality__: expr.__cardinality__,\n __expr__: expr,\n __modifiers__: {}\n })\n ) as any;\n }\n }\n\n const cleanScopedExprs = $existingScopes.size === 0;\n\n const {modifiers: mods, shape, scope} = resolveShape(shapeGetter, expr);\n\n if (cleanScopedExprs) {\n $existingScopes.clear();\n }\n\n const {modifiers, cardinality} = $handleModifiers(mods, {root: expr, scope});\n return $expressionify(\n $selectify({\n __kind__: ExpressionKind.Select,\n __element__:\n expr.__element__.__kind__ === TypeKind.object\n ? {\n __kind__: TypeKind.object,\n __name__: `${expr.__element__.__name__}`, // _shape\n __pointers__: (expr.__element__ as ObjectType).__pointers__,\n __shape__: shape\n }\n : expr.__element__,\n __cardinality__: cardinality,\n __expr__: expr,\n __modifiers__: modifiers,\n __scope__:\n expr !== scope // && expr.__element__.__name__ !== \"std::FreeObject\"\n ? scope\n : undefined\n })\n ) as any;\n}\n\nfunction resolveShape(\n shapeGetter: ((scope: any) => any) | any,\n expr: TypeSet\n): {modifiers: any; shape: any; scope: TypeSet} {\n const modifiers: any = {};\n const shape: any = {};\n\n // get scoped object if expression is objecttypeset\n const scope =\n expr.__element__.__kind__ === TypeKind.object\n ? $getScopedExpr(expr as any, $existingScopes)\n : expr;\n\n // execute getter with scope\n const selectShape =\n typeof shapeGetter === \"function\" ? shapeGetter(scope) : shapeGetter;\n\n for (const [key, value] of Object.entries(selectShape)) {\n // handle modifier keys\n if (\n key === \"filter\" ||\n key === \"filter_single\" ||\n key === \"order_by\" ||\n key === \"offset\" ||\n key === \"limit\"\n ) {\n modifiers[key] = value;\n } else {\n // for scalar expressions, scope === expr\n // shape keys are not allowed\n if (expr.__element__.__kind__ !== TypeKind.object) {\n throw new Error(\n `Invalid select shape key '${key}' on scalar expression, ` +\n `only modifiers are allowed (filter, order_by, offset and limit)`\n );\n }\n shape[key] = resolveShapeElement(key, value, scope);\n }\n }\n return {shape, modifiers, scope};\n}\n\nexport function resolveShapeElement(\n key: any,\n value: any,\n scope: ObjectTypeExpression\n): any {\n // if value is a nested closure\n // or a nested shape object\n const isSubshape =\n typeof value === \"object\" &&\n typeof (value as any).__kind__ === \"undefined\";\n const isClosure =\n typeof value === \"function\" &&\n scope.__element__.__pointers__[key]?.__kind__ === \"link\";\n // if (isSubshape) {\n // // return value;\n // const childExpr = (scope as any)[key];\n // const {\n // shape: childShape,\n // // scope: childScope,\n // // modifiers: mods,\n // } = resolveShape(value as any, childExpr);\n // return childShape;\n // }\n if (isSubshape || isClosure) {\n // get child node expression\n // this relies on Proxy-based getters\n const childExpr = (scope as any)[key];\n if (!childExpr) {\n throw new Error(\n `Invalid shape element \"${key}\" for type ${scope.__element__.__name__}`\n );\n }\n const {\n shape: childShape,\n scope: childScope,\n modifiers: mods\n } = resolveShape(value as any, childExpr);\n\n // extracts normalized modifiers\n const {modifiers} = $handleModifiers(mods, {\n root: childExpr,\n scope: childScope\n });\n\n return {\n __kind__: ExpressionKind.Select,\n __element__: {\n __kind__: TypeKind.object,\n __name__: `${childExpr.__element__.__name__}`,\n __pointers__: childExpr.__element__.__pointers__,\n __shape__: childShape\n },\n __cardinality__:\n scope.__element__.__pointers__?.[key]?.cardinality ||\n scope.__element__.__shape__?.[key]?.__cardinality__,\n __expr__: childExpr,\n __modifiers__: modifiers,\n __scope__: childExpr !== childScope ? childScope : undefined\n };\n } else if ((value as any)?.__kind__ === ExpressionKind.PolyShapeElement) {\n const polyElement = value as $expr_PolyShapeElement;\n\n const polyScope = (scope as any).is(polyElement.__polyType__);\n return {\n __kind__: ExpressionKind.PolyShapeElement,\n __polyType__: polyScope,\n __shapeElement__: resolveShapeElement(\n key,\n polyElement.__shapeElement__,\n polyScope\n )\n };\n } else if (typeof value === \"boolean\" && key.startsWith(\"@\")) {\n const linkProp = (scope as any)[key];\n if (!linkProp) {\n throw new Error(\n (scope as any).__parent__\n ? `link property '${key}' does not exist on link ${\n (scope as any).__parent__.linkName\n }`\n : `cannot select link property '${key}' on an object (${scope.__element__.__name__})`\n );\n }\n return value ? linkProp : false;\n } else {\n return value;\n }\n}\n"},{"path":"set.ts","content":"import type {ExpressionKind, Cardinality} from \"edgedb/_src/reflection/index.ts\";\nimport {TypeKind} from \"edgedb/_src/reflection/index.ts\";\nimport type {\n ArrayType,\n BaseTypeTuple,\n BaseType,\n NamedTupleType,\n ObjectTypeSet,\n TypeSet,\n TupleType,\n Expression,\n ObjectType,\n getPrimitiveBaseType,\n SomeType\n} from \"./typesystem.ts\";\n\nimport {$mergeObjectTypes, mergeObjectTypes} from \"./hydrate.ts\";\n\nimport * as castMaps from \"./castMaps.ts\";\n\nexport function getSharedParent(a: SomeType, b: SomeType): SomeType {\n if (a.__kind__ !== b.__kind__) {\n throw new Error(\n `Incompatible array types: ${a.__name__} and ${b.__name__}`\n );\n }\n if (a.__kind__ === TypeKind.scalar && b.__kind__ === TypeKind.scalar) {\n return castMaps.getSharedParentScalar(a, b);\n } else if (\n a.__kind__ === TypeKind.object &&\n b.__kind__ === TypeKind.object\n ) {\n return $mergeObjectTypes(a, b);\n } else if (a.__kind__ === TypeKind.tuple && b.__kind__ === TypeKind.tuple) {\n if (a.__items__.length !== b.__items__.length) {\n throw new Error(\n `Incompatible tuple types: ${a.__name__} and ${b.__name__}`\n );\n }\n try {\n const items = a.__items__.map((_, i) => {\n if (!a.__items__[i] || !b.__items__[i]) {\n throw new Error();\n }\n return getSharedParent(\n a.__items__[i] as SomeType,\n b.__items__[i] as SomeType\n );\n });\n\n return {\n __kind__: TypeKind.tuple,\n __name__: `tuple<${items.map(item => item.__name__).join(\", \")}>`,\n __items__: items as BaseTypeTuple\n };\n } catch (err) {\n throw new Error(\n `Incompatible tuple types: ${a.__name__} and ${b.__name__}`\n );\n }\n } else if (\n a.__kind__ === TypeKind.namedtuple &&\n b.__kind__ === TypeKind.namedtuple\n ) {\n const aKeys = Object.keys(a);\n const bKeys = new Set(Object.keys(b));\n const sameKeys =\n aKeys.length === bKeys.size && aKeys.every(k => bKeys.has(k));\n if (!sameKeys) {\n throw new Error(\n `Incompatible tuple types: ${a.__name__} and ${b.__name__}`\n );\n }\n try {\n const items: {[k: string]: BaseType} = {};\n for (const [i] of Object.entries(a.__shape__)) {\n if (!a.__shape__[i] || !b.__shape__[i]) {\n throw new Error();\n }\n items[i] = getSharedParent(\n a.__shape__[i] as SomeType,\n b.__shape__[i] as SomeType\n );\n }\n\n return {\n __kind__: TypeKind.namedtuple,\n __name__: `tuple<${Object.entries(items)\n .map(([key, val]: [string, any]) => `${key}: ${val.__name__}`)\n .join(\", \")}>`,\n __shape__: items\n };\n } catch (err) {\n throw new Error(\n `Incompatible tuple types: ${a.__name__} and ${b.__name__}`\n );\n }\n } else if (a.__kind__ === TypeKind.array && b.__kind__ === TypeKind.array) {\n try {\n const mergedEl: any = getSharedParent(\n a.__element__ as any,\n b.__element__ as any\n );\n return {\n __kind__: TypeKind.array,\n __name__: a.__name__,\n __element__: mergedEl\n } as ArrayType;\n } catch (err) {\n throw new Error(\n `Incompatible array types: ${a.__name__} and ${b.__name__}`\n );\n }\n } else if (a.__kind__ === TypeKind.enum && b.__kind__ === TypeKind.enum) {\n if (a.__name__ === b.__name__) return a;\n throw new Error(\n `Incompatible array types: ${a.__name__} and ${b.__name__}`\n );\n } else {\n throw new Error(\n `Incompatible array types: ${a.__name__} and ${b.__name__}`\n );\n }\n}\n\nexport {set} from \"./setImpl.ts\";\n\n// export type $expr_Set = Expression<\nexport type $expr_Set = Expression<{\n __element__: Set[\"__element__\"];\n __cardinality__: Set[\"__cardinality__\"];\n __exprs__: TypeSet[];\n __kind__: ExpressionKind.Set;\n}>;\n\ntype mergeTypeTuples = {\n [k in keyof AItems]: k extends keyof BItems\n ? getSharedParentPrimitive\n : never;\n};\n\n// find shared parent of two primitives\nexport type getSharedParentPrimitive = A extends undefined\n ? B extends undefined\n ? undefined\n : B\n : B extends undefined\n ? A\n : A extends ArrayType\n ? B extends ArrayType\n ? ArrayType>\n : never\n : A extends NamedTupleType\n ? B extends NamedTupleType\n ? NamedTupleType<{\n [k in keyof AShape & keyof BShape]: castMaps.getSharedParentScalar<\n AShape[k],\n BShape[k]\n >;\n }>\n : never\n : A extends TupleType\n ? B extends TupleType\n ? mergeTypeTuples extends BaseTypeTuple\n ? TupleType>\n : never\n : never\n : castMaps.getSharedParentScalar;\n\ntype _getSharedParentPrimitiveVariadic =\n Types extends [infer U]\n ? U\n : Types extends [infer A, infer B, ...infer Rest]\n ? _getSharedParentPrimitiveVariadic<\n [getSharedParentPrimitive, ...Rest]\n >\n : never;\n\nexport type getSharedParentPrimitiveVariadic =\n _getSharedParentPrimitiveVariadic;\n\nexport type LooseTypeSet<\n T extends any = any,\n C extends Cardinality = Cardinality\n> = {\n __element__: T;\n __cardinality__: C;\n};\n\nexport type {mergeObjectTypes};\n\ntype _mergeObjectTypesVariadic =\n Types extends [infer U]\n ? U\n : Types extends [infer A, infer B, ...infer Rest]\n ? A extends ObjectType\n ? B extends ObjectType\n ? mergeObjectTypes extends BaseType\n ? mergeObjectTypesVariadic<[mergeObjectTypes, ...Rest]>\n : never\n : never\n : never\n : never;\n\nexport type mergeObjectTypesVariadic =\n _mergeObjectTypesVariadic;\n\nexport type getTypesFromExprs = {\n [k in keyof Exprs]: Exprs[k] extends TypeSet\n ? getPrimitiveBaseType\n : never;\n};\n\nexport type getTypesFromObjectExprs<\n Exprs extends [ObjectTypeSet, ...ObjectTypeSet[]]\n> = {\n [k in keyof Exprs]: Exprs[k] extends TypeSet ? El : never;\n};\n\nexport type getCardsFromExprs = {\n [k in keyof Exprs]: Exprs[k] extends TypeSet ? Card : never;\n};\n"},{"path":"setImpl.ts","content":"export function set(...args: any[]): any {}\n"},{"path":"syntax.ts","content":"import type {TypeSet, setToTsType} from \"./typesystem.ts\";\n\nexport * from \"./literal.ts\";\nexport * from \"./path.ts\";\nexport * from \"./set.ts\";\nexport * from \"./cast.ts\";\nexport * from \"./select.ts\";\nexport * from \"./update.ts\";\nexport * from \"./insert.ts\";\nexport * from \"./group.ts\";\nexport * from \"./collections.ts\";\nexport * from \"./funcops.ts\";\nexport * from \"./for.ts\";\nexport * from \"./with.ts\";\nexport * from \"./params.ts\";\nexport * from \"./globals.ts\";\nexport * from \"./detached.ts\";\nexport * from \"./toEdgeQL.ts\";\nexport * from \"./range.ts\";\n\nexport type $infer = setToTsType;\n"},{"path":"toEdgeQL.ts","content":"import {\n Duration,\n LocalDate,\n LocalDateTime,\n LocalTime,\n RelativeDuration,\n DateDuration,\n Range\n} from \"edgedb\";\nimport {\n Cardinality,\n ExpressionKind,\n OperatorKind,\n TypeKind,\n util\n} from \"edgedb/_src/reflection/index.ts\";\nimport {\n $expr_Array,\n $expr_NamedTuple,\n $expr_Tuple,\n $expr_TuplePath,\n BaseType,\n EnumType,\n isArrayType,\n isNamedTupleType,\n isObjectType,\n isTupleType,\n ObjectType,\n ObjectTypeSet,\n RangeType,\n TypeSet\n} from \"./typesystem.ts\";\nimport type {$expr_Literal} from \"./literal.ts\";\nimport type {\n $expr_PathLeaf,\n $expr_PathNode,\n $expr_TypeIntersection\n} from \"./path.ts\";\nimport {reservedKeywords} from \"edgedb/_src/reflection/index.ts\";\nimport type {$expr_Cast} from \"./cast.ts\";\nimport type {$expr_Detached} from \"./detached.ts\";\nimport type {$expr_For, $expr_ForVar} from \"./for.ts\";\nimport type {$expr_Function, $expr_Operator} from \"./funcops.ts\";\nimport type {$expr_Insert, $expr_InsertUnlessConflict} from \"./insert.ts\";\nimport type {$expr_Param, $expr_WithParams} from \"./params.ts\";\nimport type {\n $expr_Delete,\n $expr_Select,\n LimitExpression,\n OffsetExpression\n} from \"./select.ts\";\nimport type {$expr_Set} from \"./set.ts\";\nimport type {$expr_Update} from \"./update.ts\";\nimport type {$expr_Alias, $expr_With} from \"./with.ts\";\nimport type {$expr_Group, GroupingSet} from \"./group.ts\";\nimport type {$expr_Global} from \"./globals.ts\";\n\nexport type SomeExpression =\n | $expr_PathNode\n | $expr_PathLeaf\n | $expr_Literal\n | $expr_Set\n | $expr_Array\n | $expr_Tuple\n | $expr_NamedTuple\n | $expr_TuplePath\n | $expr_Cast\n | $expr_Select\n | $expr_Delete\n | $expr_Update\n | $expr_Insert\n | $expr_InsertUnlessConflict\n | $expr_Function\n | $expr_Operator\n | $expr_For\n | $expr_ForVar\n | $expr_TypeIntersection\n | $expr_Alias\n | $expr_With\n | $expr_WithParams\n | $expr_Param\n | $expr_Detached\n | $expr_Group\n | $expr_Global;\n\ntype WithScopeExpr =\n | $expr_Select\n | $expr_Update\n | $expr_Insert\n | $expr_InsertUnlessConflict\n | $expr_For\n | $expr_Group;\n\ninterface RenderCtx {\n // mapping withable expr to list of with vars\n withBlocks: Map>;\n // metadata about each with var\n withVars: Map<\n SomeExpression,\n {\n name: string;\n scope: WithScopeExpr;\n childExprs: Set;\n scopedExpr?: SomeExpression; // scope vars only\n }\n >;\n renderWithVar?: SomeExpression;\n forVars: Map<$expr_ForVar, string>;\n linkProps: Map;\n}\n\nconst toEdgeQLCache = new WeakMap();\n\nexport function $toEdgeQL(this: any) {\n if (toEdgeQLCache.has(this)) {\n return toEdgeQLCache.get(this)!;\n }\n\n const walkExprCtx: WalkExprTreeCtx = {\n seen: new Map(),\n rootScope: null\n };\n\n walkExprTree(this, null, walkExprCtx);\n\n // get variables by block\n const withBlocks: RenderCtx[\"withBlocks\"] = new Map();\n // get per-variable metadata\n const withVars: RenderCtx[\"withVars\"] = new Map();\n const seen = new Map(walkExprCtx.seen);\n const linkProps: RenderCtx[\"linkProps\"] = new Map();\n\n // iterate over all expressions\n for (const [expr, refData] of seen) {\n // delete from seen after visitinng\n seen.delete(expr);\n\n // convert referenced link props to simple string array\n if (refData.linkProps.length) {\n linkProps.set(\n expr,\n refData.linkProps.map(linkProp =>\n linkProp.__parent__.linkName.slice(1)\n )\n );\n }\n\n // already extracted\n if (withVars.has(expr)) {\n continue;\n }\n\n // ignore unbound leaves, nodes, and intersections\n // these should be rendered as is\n if (\n !refData.boundScope &&\n (expr.__kind__ === ExpressionKind.PathLeaf ||\n expr.__kind__ === ExpressionKind.PathNode ||\n expr.__kind__ === ExpressionKind.TypeIntersection)\n ) {\n continue;\n }\n\n // forvars and params should not be hoisted\n if (\n expr.__kind__ === ExpressionKind.ForVar ||\n expr.__kind__ === ExpressionKind.Param\n ) {\n continue;\n }\n\n // pull out scope variables\n // from select, update, and group expressions.\n // these are always rendered in with blocks\n if (\n (expr.__kind__ === ExpressionKind.Select ||\n expr.__kind__ === ExpressionKind.Update ||\n expr.__kind__ === ExpressionKind.Group) &&\n expr.__scope__ &&\n // with var not previously registered\n !withVars.has(expr.__scope__ as any)\n ) {\n const withBlock = expr;\n const scopeVar = expr.__scope__ as SomeExpression;\n const scopeVarName = `__scope_${\n withVars.size\n }_${scopeVar.__element__.__name__.replace(/[^A-Za-z]/g, \"\")}`;\n\n withVars.set(scopeVar, {\n name: scopeVarName,\n scope: withBlock,\n childExprs: new Set(),\n scopedExpr:\n expr.__element__.__kind__ === TypeKind.object\n ? (expr.__expr__ as any)\n : undefined\n });\n }\n\n // expression should be extracted to with block if\n // - bound with e.with\n // - refcount > 1\n // - aliased with e.alias\n if (\n refData.refCount > 1 ||\n refData.boundScope ||\n refData.aliases.length > 0\n ) {\n // first, check if expr is bound to scope\n let withBlock = refData.boundScope;\n\n // filter nulls\n const parentScopes = [...refData.parentScopes].filter(\n scope => scope !== null\n ) as WithScopeExpr[];\n\n // if expression is unbound\n if (!withBlock) {\n // if parent scopes haven't all been resolved,\n // re-add current expr to `seen` to be resolved later\n if (parentScopes.some(parentScope => seen.has(parentScope))) {\n seen.set(expr, refData);\n continue;\n }\n\n // set withBlock to top-level parent scope\n const resolvedParentScopes = parentScopes.map(\n parentScope => withVars.get(parentScope)?.scope ?? parentScope\n );\n withBlock =\n resolvedParentScopes.find(parentScope => {\n // loop over parent scopes\n // get list of children exprs for each parent\n const childExprs = new Set(\n walkExprCtx.seen.get(parentScope)!.childExprs\n );\n // return true for scope that contains all other scopes\n return resolvedParentScopes.every(\n scope => childExprs.has(scope) || scope === parentScope\n );\n }) ?? walkExprCtx.rootScope;\n }\n\n if (!withBlock) {\n throw new Error(\n `Cannot extract repeated expression into 'WITH' block, ` +\n `query has no 'WITH'able expressions`\n );\n }\n\n if (!withBlocks.has(withBlock)) {\n withBlocks.set(withBlock, new Set());\n }\n\n // check all references and aliases are within this block\n const validScopes = new Set([\n withBlock,\n ...walkExprCtx.seen.get(withBlock)!.childExprs\n ]);\n for (const scope of [\n ...refData.parentScopes,\n ...util.flatMap(refData.aliases, alias => [\n ...walkExprCtx.seen.get(alias)!.parentScopes\n ])\n ]) {\n if (scope === null || !validScopes.has(scope)) {\n throw new Error(\n refData.boundScope\n ? `Expr or its aliases used outside of declared 'WITH' block scope`\n : `Cannot extract repeated or aliased expression into 'WITH' block, ` +\n `expression or its aliases appear outside root scope`\n );\n }\n }\n\n for (const withVar of [expr, ...refData.aliases]) {\n // withVar is an alias already explicitly bound\n // to an inner WITH block\n const withVarBoundScope = walkExprCtx.seen.get(withVar)!.boundScope;\n if (withVarBoundScope && withVarBoundScope !== refData.boundScope) {\n continue;\n }\n\n const withVarName = `__withVar_${withVars.size}`;\n\n withBlocks.get(withBlock)!.add(withVar);\n withVars.set(withVar, {\n name: withVarName,\n scope: withBlock,\n childExprs: new Set(walkExprCtx.seen.get(withVar)!.childExprs)\n });\n }\n }\n }\n\n let edgeQL = renderEdgeQL(this, {\n withBlocks,\n withVars,\n forVars: new Map(),\n linkProps\n });\n if (\n edgeQL.startsWith(\"(\") &&\n edgeQL.endsWith(\")\") &&\n !(\n this.__kind__ === ExpressionKind.Tuple ||\n this.__kind__ === ExpressionKind.NamedTuple ||\n this.__kind__ === ExpressionKind.Literal\n )\n ) {\n edgeQL = edgeQL.slice(1, -1);\n }\n toEdgeQLCache.set(this, edgeQL);\n\n return edgeQL;\n}\n\ninterface WalkExprTreeCtx {\n seen: Map<\n SomeExpression,\n {\n refCount: number;\n // tracks all withable ancestors\n parentScopes: Set;\n // tracks all child exprs\n childExprs: SomeExpression[];\n // tracks bound scope from e.with\n boundScope: WithScopeExpr | null;\n // tracks aliases from e.alias\n aliases: SomeExpression[];\n linkProps: $expr_PathLeaf[];\n }\n >;\n rootScope: WithScopeExpr | null;\n}\n\n// walks entire expression tree\n// populates\nfunction walkExprTree(\n _expr: TypeSet,\n parentScope: WithScopeExpr | null,\n ctx: WalkExprTreeCtx\n): SomeExpression[] {\n if (!(_expr as any).__kind__) {\n throw new Error(\n `Expected a valid querybuilder expression, ` +\n `instead received ${typeof _expr}${\n typeof _expr !== \"undefined\" ? `: '${_expr}'` : \"\"\n }.` +\n getErrorHint(_expr)\n );\n }\n\n const expr = _expr as SomeExpression;\n\n function walkShape(shape: object) {\n for (let param of Object.values(shape)) {\n if (param.__kind__ === ExpressionKind.PolyShapeElement) {\n param = param.__shapeElement__;\n }\n if (typeof param === \"object\") {\n if (!!(param as any).__kind__) {\n // param is expression\n childExprs.push(...walkExprTree(param as any, expr as any, ctx));\n } else {\n walkShape(param);\n }\n }\n }\n }\n\n // set root scope\n if (!ctx.rootScope && parentScope) {\n ctx.rootScope = parentScope;\n }\n\n // return without walking if expression has been seen\n const seenExpr = ctx.seen.get(expr);\n if (seenExpr) {\n seenExpr.refCount += 1;\n // if (seenExpr.refCount > 1) {\n // console.log(`###########\\nSEEN ${seenExpr.refCount} times`);\n // console.log(expr.__kind__);\n // console.log(expr.__element__.__name__);\n // const arg = (expr as any)?.__parent__ || (expr as any)?.__name__;\n // if (arg) console.log(arg);\n // }\n seenExpr.parentScopes.add(parentScope);\n return [expr, ...seenExpr.childExprs];\n }\n\n const childExprs: SomeExpression[] = [];\n ctx.seen.set(expr, {\n refCount: 1,\n parentScopes: new Set([parentScope]),\n childExprs,\n boundScope: null,\n aliases: [],\n linkProps: []\n });\n\n switch (expr.__kind__) {\n case ExpressionKind.Alias:\n childExprs.push(...walkExprTree(expr.__expr__, parentScope, ctx));\n ctx.seen.get(expr.__expr__ as any)!.aliases.push(expr);\n break;\n case ExpressionKind.With:\n childExprs.push(...walkExprTree(expr.__expr__, parentScope, ctx));\n for (const refExpr of expr.__refs__) {\n walkExprTree(refExpr, expr.__expr__, ctx);\n const seenRef = ctx.seen.get(refExpr as any)!;\n if (seenRef.boundScope) {\n throw new Error(`Expression bound to multiple 'WITH' blocks`);\n }\n seenRef.boundScope = expr.__expr__;\n }\n break;\n case ExpressionKind.Literal:\n case ExpressionKind.ForVar:\n case ExpressionKind.Param:\n break;\n case ExpressionKind.PathLeaf:\n case ExpressionKind.PathNode:\n if (expr.__parent__) {\n if ((expr.__parent__.type as any).__scopedFrom__) {\n // if parent is scoped expr then don't walk expr\n // since it will already be walked by enclosing select/update\n\n childExprs.push(expr.__parent__.type as any);\n } else {\n childExprs.push(\n ...walkExprTree(expr.__parent__.type, parentScope, ctx)\n );\n }\n\n if (\n // is link prop\n expr.__kind__ === ExpressionKind.PathLeaf &&\n expr.__parent__.linkName.startsWith(\"@\")\n ) {\n // don't hoist a linkprop that isn't scoped from parentScope\n const parentScopeVar = (parentScope as any).__scope__;\n if (parentScopeVar === expr.__parent__.type) {\n ctx.seen.get(parentScope!)?.linkProps.push(expr);\n }\n }\n }\n break;\n case ExpressionKind.Cast:\n if (expr.__expr__ === null) break;\n childExprs.push(...walkExprTree(expr.__expr__, parentScope, ctx));\n break;\n case ExpressionKind.Set:\n for (const subExpr of expr.__exprs__) {\n childExprs.push(...walkExprTree(subExpr, parentScope, ctx));\n }\n break;\n case ExpressionKind.Array:\n for (const subExpr of expr.__items__) {\n childExprs.push(...walkExprTree(subExpr, parentScope, ctx));\n }\n break;\n case ExpressionKind.Tuple:\n for (const subExpr of expr.__items__) {\n childExprs.push(...walkExprTree(subExpr, parentScope, ctx));\n }\n break;\n case ExpressionKind.NamedTuple:\n for (const subExpr of Object.values(expr.__shape__)) {\n childExprs.push(...walkExprTree(subExpr, parentScope, ctx));\n }\n break;\n case ExpressionKind.TuplePath:\n childExprs.push(...walkExprTree(expr.__parent__, parentScope, ctx));\n break;\n case ExpressionKind.Select:\n case ExpressionKind.Update: {\n const modifiers = expr.__modifiers__;\n if (modifiers.filter) {\n childExprs.push(...walkExprTree(modifiers.filter, expr, ctx));\n }\n if (modifiers.order_by) {\n for (const orderExpr of modifiers.order_by) {\n childExprs.push(...walkExprTree(orderExpr.expression, expr, ctx));\n }\n }\n if (modifiers.offset) {\n childExprs.push(...walkExprTree(modifiers.offset!, expr, ctx));\n }\n if (modifiers.limit) {\n childExprs.push(...walkExprTree(modifiers.limit!, expr, ctx));\n }\n\n if (expr.__kind__ === ExpressionKind.Select) {\n if (\n isObjectType(expr.__element__) &&\n // don't walk shape twice if select expr justs wrap another object\n // type expr with the same shape\n expr.__element__.__shape__ !==\n (expr.__expr__ as ObjectTypeSet).__element__.__shape__\n ) {\n walkShape(expr.__element__.__shape__ ?? {});\n }\n } else {\n // Update\n const shape: any = expr.__shape__ ?? {};\n\n for (const _element of Object.values(shape)) {\n let element: any = _element;\n if (!element.__element__) {\n if (element[\"+=\"]) element = element[\"+=\"];\n else if (element[\"-=\"]) element = element[\"-=\"];\n }\n childExprs.push(...walkExprTree(element as any, expr, ctx));\n }\n }\n\n childExprs.push(...walkExprTree(expr.__expr__, expr, ctx));\n break;\n }\n case ExpressionKind.Delete: {\n childExprs.push(...walkExprTree(expr.__expr__, parentScope, ctx));\n break;\n }\n case ExpressionKind.Insert: {\n const shape: any = expr.__shape__ ?? {};\n\n for (const element of Object.values(shape)) {\n childExprs.push(...walkExprTree(element as any, expr, ctx));\n }\n\n childExprs.push(...walkExprTree(expr.__expr__, expr, ctx));\n break;\n }\n case ExpressionKind.InsertUnlessConflict: {\n // InsertUnlessConflict doesn't create a new scope, the parent scope of\n // child expressions is the wrapped Insert expr\n if (expr.__conflict__.on) {\n childExprs.push(\n ...walkExprTree(\n expr.__conflict__.on,\n expr.__expr__ as $expr_Insert,\n ctx\n )\n );\n }\n if (expr.__conflict__.else) {\n childExprs.push(\n ...walkExprTree(\n expr.__conflict__.else,\n expr.__expr__ as $expr_Insert,\n ctx\n )\n );\n }\n\n childExprs.push(...walkExprTree(expr.__expr__, parentScope, ctx));\n break;\n }\n case ExpressionKind.Group: {\n const groupingSet = expr.__modifiers__.by as any as GroupingSet;\n // const groupingSet = expr.__grouping__ as any as GroupingSet;\n for (const [_k, groupExpr] of groupingSet.__exprs__) {\n // this prevents recurring grouping elements from being walked twice\n // this way, these won't get pulled into with blocks,\n // which is good because they need to be rendered in `using`\n const seen: Set = new Set();\n if (!seen.has(expr)) {\n childExprs.push(...walkExprTree(groupExpr, expr, ctx));\n seen.add(expr);\n }\n }\n\n if (!expr.__element__.__shape__.elements.__element__.__shape__) {\n throw new Error(\"Missing shape in GROUP statement\");\n }\n walkShape(expr.__element__.__shape__.elements.__element__.__shape__);\n childExprs.push(...walkExprTree(expr.__expr__, expr, ctx));\n break;\n }\n case ExpressionKind.TypeIntersection:\n childExprs.push(...walkExprTree(expr.__expr__, parentScope, ctx));\n break;\n case ExpressionKind.Operator:\n case ExpressionKind.Function:\n for (const subExpr of expr.__args__) {\n if (Array.isArray(subExpr)) {\n for (const arg of subExpr) {\n if (arg) childExprs.push(...walkExprTree(arg, parentScope, ctx));\n }\n } else {\n childExprs.push(...walkExprTree(subExpr!, parentScope, ctx));\n }\n }\n if (expr.__kind__ === ExpressionKind.Function) {\n for (const subExpr of Object.values(expr.__namedargs__)) {\n childExprs.push(...walkExprTree(subExpr, parentScope, ctx));\n }\n }\n break;\n case ExpressionKind.For: {\n childExprs.push(...walkExprTree(expr.__iterSet__ as any, expr, ctx));\n childExprs.push(...walkExprTree(expr.__expr__, expr, ctx));\n break;\n }\n case ExpressionKind.WithParams: {\n if (parentScope !== null) {\n throw new Error(\n `'withParams' does not support being used as a nested expression`\n );\n }\n childExprs.push(...walkExprTree(expr.__expr__, parentScope, ctx));\n break;\n }\n case ExpressionKind.Detached: {\n childExprs.push(...walkExprTree(expr.__expr__, parentScope, ctx));\n break;\n }\n case ExpressionKind.Global:\n break;\n default:\n util.assertNever(\n expr,\n new Error(`Unrecognized expression kind: \"${(expr as any).__kind__}\"`)\n );\n }\n\n return [expr, ...childExprs];\n}\n\nfunction renderEdgeQL(\n _expr: TypeSet,\n ctx: RenderCtx,\n renderShape: boolean = true,\n noImplicitDetached: boolean = false\n): string {\n if (!(_expr as any).__kind__) {\n throw new Error(\"Invalid expression.\");\n }\n const expr = _expr as SomeExpression;\n\n // if expression is in a with block\n // render its name\n const withVar = ctx.withVars.get(expr);\n\n if (withVar && ctx.renderWithVar !== expr) {\n return renderShape &&\n expr.__kind__ === ExpressionKind.Select &&\n isObjectType(expr.__element__)\n ? `(${withVar.name} ${shapeToEdgeQL(\n (expr.__element__.__shape__ || {}) as object,\n ctx,\n null,\n true // render shape only\n )})`\n : withVar.name;\n }\n\n // render with block expression\n function renderWithBlockExpr(\n varExpr: SomeExpression,\n _noImplicitDetached?: boolean\n ) {\n const withBlockElement = ctx.withVars.get(varExpr)!;\n let renderedExpr = renderEdgeQL(\n withBlockElement.scopedExpr ?? varExpr,\n {\n ...ctx,\n renderWithVar: varExpr\n },\n !withBlockElement.scopedExpr, // render shape if no scopedExpr exists\n _noImplicitDetached\n );\n const renderedExprNoDetached = renderEdgeQL(\n withBlockElement.scopedExpr ?? varExpr,\n {\n ...ctx,\n renderWithVar: varExpr\n },\n !withBlockElement.scopedExpr, // render shape if no scopedExpr exists\n true\n );\n\n if (ctx.linkProps.has(expr)) {\n renderedExpr = `(SELECT ${renderedExpr} {\\n${ctx.linkProps\n .get(expr)!\n .map(\n linkPropName =>\n ` __linkprop_${linkPropName} := ${renderedExprNoDetached}@${linkPropName}`\n )\n .join(\",\\n\")}\\n})`;\n }\n return ` ${withBlockElement.name} := ${\n renderedExpr.includes(\"\\n\")\n ? `(\\n${indent(\n renderedExpr[0] === \"(\" &&\n renderedExpr[renderedExpr.length - 1] === \")\"\n ? renderedExpr.slice(1, -1)\n : renderedExpr,\n 4\n )}\\n )`\n : renderedExpr\n }`;\n }\n\n // extract scope expression from select/update if exists\n const scopeExpr =\n (expr.__kind__ === ExpressionKind.Select ||\n expr.__kind__ === ExpressionKind.Update ||\n expr.__kind__ === ExpressionKind.Group) &&\n ctx.withVars.has(expr.__scope__ as any)\n ? (expr.__scope__ as SomeExpression)\n : undefined;\n\n const scopeExprVar: string[] = [];\n const unscopedWithBlock: string[] = [];\n const scopedWithBlock: string[] = [];\n\n // generate with block if needed\n if (ctx.withBlocks.has(expr as any) || scopeExpr) {\n // sort associated vars\n const sortedBlockVars = topoSortWithVars(\n ctx.withBlocks.get(expr as any) ?? new Set(),\n ctx\n );\n\n if (!scopeExpr) {\n // if no scope expression exists, all variables are unscoped\n unscopedWithBlock.push(\n ...sortedBlockVars.map(blockVar => renderWithBlockExpr(blockVar))\n );\n }\n // else if (expr.__kind__ === ExpressionKind.Group) {\n // // add all vars into scoped with block\n // // this is rendered inside the `using` clause later\n // // no need for the with/for trick\n // scopeExprVar.push(renderWithBlockExpr(scopeExpr, noImplicitDetached));\n // scopedWithBlock.push(\n // ...sortedBlockVars.map(blockVar => renderWithBlockExpr(blockVar))\n // );\n // }\n else {\n // get scope variable\n const scopeVar = ctx.withVars.get(scopeExpr)!;\n\n // get list of with vars that reference scope\n const scopedVars = sortedBlockVars.filter(blockVarExpr =>\n ctx.withVars.get(blockVarExpr)?.childExprs.has(scopeExpr)\n );\n // filter blockvars to only include vars that don't reference scope\n unscopedWithBlock.push(\n ...sortedBlockVars\n .filter(blockVar => !scopedVars.includes(blockVar))\n .map(blockVar => renderWithBlockExpr(blockVar))\n );\n\n // when rendering `with` variables that reference current scope\n // they are extracted into computed properties defining in a for loop\n if (!scopedVars.length) {\n scopeExprVar.push(renderWithBlockExpr(scopeExpr, noImplicitDetached));\n } else {\n const scopeName = scopeVar.name;\n\n // render a reference to scoped path (e.g. \".nemesis\")\n scopeVar.name = scopeName + \"_expr\";\n scopeExprVar.push(renderWithBlockExpr(scopeExpr, noImplicitDetached));\n // scopedWithBlock.push(\n // renderWithBlockExpr(scopeExpr, noImplicitDetached)\n // );\n\n // render a for loop containing all scoped block vars\n // as computed properties\n scopeVar.name = scopeName + \"_inner\";\n scopeExprVar.push(\n ` ${scopeName} := (FOR ${scopeVar.name} IN {${\n scopeName + \"_expr\"\n }} UNION (\\n WITH\\n${indent(\n scopedVars\n .map(blockVar => renderWithBlockExpr(blockVar))\n .join(\",\\n\"),\n 4\n )}\\n SELECT ${scopeVar.name} {\\n${scopedVars\n .map(blockVar => {\n const name = ctx.withVars.get(blockVar)!.name;\n return ` ${name} := ${name}`;\n })\n .join(\",\\n\")}\\n }\\n ))`\n );\n\n // change var name back to original value\n scopeVar.name = scopeName;\n\n // reassign name for all scoped block vars\n for (const blockVarExpr of scopedVars) {\n const blockVar = ctx.withVars.get(blockVarExpr)!;\n blockVar.name = `${scopeName}.${blockVar.name}`;\n }\n }\n }\n }\n\n const withBlockElements = [\n ...unscopedWithBlock,\n ...scopeExprVar,\n ...scopedWithBlock\n ];\n const withBlock = withBlockElements.length\n ? `WITH\\n${withBlockElements.join(\",\\n\")}\\n`\n : \"\";\n\n if (expr.__kind__ === ExpressionKind.With) {\n return renderEdgeQL(expr.__expr__, ctx);\n } else if (expr.__kind__ === ExpressionKind.WithParams) {\n return `(WITH\\n${expr.__params__\n .map(param => {\n const optional =\n param.__cardinality__ === Cardinality.AtMostOne ? \"OPTIONAL \" : \"\";\n return ` __param__${param.__name__} := ${\n param.__isComplex__\n ? `<${param.__element__.__name__}>to_json(<${optional}str>$${param.__name__})`\n : `<${optional}${param.__element__.__name__}>$${param.__name__}`\n }`;\n })\n .join(\",\\n\")}\\nSELECT ${renderEdgeQL(expr.__expr__, ctx)})`;\n } else if (expr.__kind__ === ExpressionKind.Alias) {\n const aliasedExprVar = ctx.withVars.get(expr.__expr__ as any);\n if (!aliasedExprVar) {\n throw new Error(\n `Expression referenced by alias does not exist in 'WITH' block`\n );\n }\n return aliasedExprVar.name;\n } else if (\n expr.__kind__ === ExpressionKind.PathNode ||\n expr.__kind__ === ExpressionKind.PathLeaf\n ) {\n if (!expr.__parent__) {\n return `${noImplicitDetached ? \"\" : \"DETACHED \"}${\n expr.__element__.__name__\n }`;\n } else {\n const isScopedLinkProp =\n expr.__parent__.linkName.startsWith(\"@\") &&\n ctx.withVars.has(expr.__parent__.type as any);\n const linkName = isScopedLinkProp\n ? `__linkprop_${expr.__parent__.linkName.slice(1)}`\n : expr.__parent__.linkName;\n const parent = renderEdgeQL(\n expr.__parent__.type,\n ctx,\n false,\n noImplicitDetached\n );\n return `${parent}${linkName.startsWith(\"@\") ? \"\" : \".\"}${q(linkName)}`;\n }\n } else if (expr.__kind__ === ExpressionKind.Literal) {\n return literalToEdgeQL(expr.__element__, expr.__value__);\n } else if (expr.__kind__ === ExpressionKind.Set) {\n const exprs = expr.__exprs__;\n\n if (\n exprs.every(ex => ex.__element__.__kind__ === TypeKind.object) ||\n exprs.every(ex => ex.__element__.__kind__ !== TypeKind.object)\n ) {\n if (exprs.length === 0) return `<${expr.__element__.__name__}>{}`;\n return `{ ${exprs.map(ex => renderEdgeQL(ex, ctx)).join(\", \")} }`;\n } else {\n throw new Error(\n `Invalid arguments to set constructor: ${exprs\n .map(ex => ex.__element__.__name__)\n .join(\", \")}`\n );\n }\n } else if (expr.__kind__ === ExpressionKind.Array) {\n return `[${expr.__items__\n .map(item => renderEdgeQL(item, ctx))\n .join(\", \")}]`;\n } else if (expr.__kind__ === ExpressionKind.Tuple) {\n return `(\\n${expr.__items__\n .map(\n item => ` ` + renderEdgeQL(item, ctx, renderShape, noImplicitDetached)\n )\n .join(\",\\n\")}${expr.__items__.length === 1 ? \",\" : \"\"}\\n)`;\n } else if (expr.__kind__ === ExpressionKind.NamedTuple) {\n return `(\\n${Object.keys(expr.__shape__)\n .map(\n key =>\n ` ${key} := ${renderEdgeQL(\n expr.__shape__[key],\n ctx,\n renderShape,\n noImplicitDetached\n )}`\n )\n .join(\",\\n\")}\\n)`;\n } else if (expr.__kind__ === ExpressionKind.TuplePath) {\n return `${renderEdgeQL(expr.__parent__, ctx)}.${expr.__index__}`;\n } else if (expr.__kind__ === ExpressionKind.Cast) {\n const typeName =\n expr.__element__.__name__ === \"std::number\"\n ? \"std::float64\"\n : expr.__element__.__name__;\n if (expr.__expr__ === null) {\n return `<${typeName}>{}`;\n }\n return `<${typeName}>(${renderEdgeQL(expr.__expr__, ctx)})`;\n } else if (expr.__kind__ === ExpressionKind.Select) {\n const lines: string[] = [];\n if (isObjectType(expr.__element__)) {\n const selectionTarget = renderEdgeQL(\n expr.__scope__ ?? expr.__expr__,\n ctx,\n false\n );\n\n lines.push(\n `SELECT${\n selectionTarget === \"DETACHED std::FreeObject\"\n ? \"\"\n : ` ${selectionTarget}`\n }`\n );\n\n if (\n expr.__element__.__shape__ !==\n (expr.__expr__ as ObjectTypeSet).__element__.__shape__\n ) {\n lines.push(\n shapeToEdgeQL(\n (expr.__element__.__shape__ || {}) as object,\n ctx,\n expr.__element__\n )\n );\n }\n } else {\n // non-object/non-shape select expression\n const needsScalarVar =\n (expr.__modifiers__.filter ||\n expr.__modifiers__.order_by ||\n expr.__modifiers__.offset ||\n expr.__modifiers__.limit) &&\n !ctx.withVars.has(expr.__expr__ as any);\n\n lines.push(\n `SELECT ${needsScalarVar ? \"_ := \" : \"\"}${renderEdgeQL(\n expr.__expr__,\n ctx\n )}`\n );\n\n if (needsScalarVar) {\n ctx = {...ctx, withVars: new Map(ctx.withVars)};\n ctx.withVars.set(expr.__expr__ as any, {\n name: \"_\",\n childExprs: new Set(),\n scope: expr\n });\n }\n }\n\n const modifiers: string[] = [];\n\n if (expr.__modifiers__.filter) {\n modifiers.push(`FILTER ${renderEdgeQL(expr.__modifiers__.filter, ctx)}`);\n }\n if (expr.__modifiers__.order_by) {\n modifiers.push(\n ...expr.__modifiers__.order_by.map(\n ({expression, direction, empty}, i) => {\n return `${i === 0 ? \"ORDER BY\" : \" THEN\"} ${renderEdgeQL(\n expression,\n ctx\n )}${direction ? \" \" + direction : \"\"}${empty ? \" \" + empty : \"\"}`;\n }\n )\n );\n }\n if (expr.__modifiers__.offset) {\n modifiers.push(\n `OFFSET ${renderEdgeQL(\n expr.__modifiers__.offset as OffsetExpression,\n ctx\n )}`\n );\n }\n if (expr.__modifiers__.limit) {\n modifiers.push(\n `LIMIT ${renderEdgeQL(\n expr.__modifiers__.limit as LimitExpression,\n ctx\n )}`\n );\n }\n\n // without assert_single, the query will return a more informative\n // CardinalityMismatchError when the query returns more than one result\n return (\n // (expr.__modifiers__.singleton ? `select assert_single((` : ``) +\n \"(\" +\n withBlock +\n lines.join(\" \") +\n (modifiers.length ? \"\\n\" + modifiers.join(\"\\n\") : \"\") +\n \")\"\n // + (expr.__modifiers__.singleton ? `))` : ``)\n );\n } else if (expr.__kind__ === ExpressionKind.Update) {\n return `(${withBlock}UPDATE ${renderEdgeQL(expr.__scope__, ctx, false)}${\n expr.__modifiers__.filter\n ? `\\nFILTER ${renderEdgeQL(expr.__modifiers__.filter, ctx)}\\n`\n : \" \"\n }SET ${shapeToEdgeQL(expr.__shape__, ctx, null, false, false)})`;\n } else if (expr.__kind__ === ExpressionKind.Delete) {\n return `(${withBlock}DELETE ${renderEdgeQL(\n expr.__expr__,\n ctx,\n undefined,\n noImplicitDetached\n )})`;\n } else if (expr.__kind__ === ExpressionKind.Insert) {\n return `(${withBlock}INSERT ${renderEdgeQL(\n expr.__expr__,\n ctx,\n false,\n true\n )} ${shapeToEdgeQL(expr.__shape__, ctx, null, false, false)})`;\n } else if (expr.__kind__ === ExpressionKind.InsertUnlessConflict) {\n const $on = expr.__conflict__.on;\n const $else = expr.__conflict__.else;\n const clause: string[] = [];\n if (!$on) {\n clause.push(\"\\nUNLESS CONFLICT\");\n }\n if ($on) {\n clause.push(\n `\\nUNLESS CONFLICT ON ${renderEdgeQL($on, ctx, false, true)}`\n );\n }\n if ($else) {\n clause.push(`\\nELSE (${renderEdgeQL($else, ctx, true, true)})`);\n }\n return `(${renderEdgeQL(expr.__expr__, ctx, false, true).slice(\n 1,\n -1\n )} ${clause.join(\"\")})`;\n } else if (expr.__kind__ === ExpressionKind.Group) {\n const groupingSet = expr.__modifiers__.by as any as GroupingSet;\n const elementsShape =\n expr.__element__.__shape__.elements.__element__.__shape__;\n\n const selectStatement: string[] = [];\n const groupStatement: string[] = [];\n\n const groupTarget = renderEdgeQL(expr.__scope__, ctx, false);\n groupStatement.push(`GROUP ${groupTarget}`);\n\n // render scoped withvars in using\n const combinedBlock = [\n // ...scopedWithBlock,\n // this is deduplicated in e.group\n ...groupingSet.__exprs__.map(\n ([k, v]) => ` ${k} := ${renderEdgeQL(v, ctx)}`\n )\n ];\n groupStatement.push(`USING\\n${combinedBlock.join(\",\\n\")}`);\n\n let by = renderGroupingSet(groupingSet).trim();\n if (by[0] === \"(\" && by[by.length - 1] === \")\") {\n by = by.slice(1, by.length - 1);\n }\n groupStatement.push(`BY ` + by);\n\n // clause.push(withBlock.trim());\n\n // render scope var and any unscoped withVars in with block\n const selectTarget = `${groupTarget}_groups`;\n selectStatement.push(\n `WITH\\n${[\n ...unscopedWithBlock,\n ...scopeExprVar\n // ...scopedWithBlock,\n ].join(\",\\n\")},\n ${selectTarget} := (\n${indent(groupStatement.join(\"\\n\"), 4)}\n)`\n );\n\n // rename scope var to fix all scope references that\n // occur in the `elements` subshape\n const scopeVar = ctx.withVars.get(expr.__scope__ as any);\n\n // replace references to __scope__ with\n // .elements reference\n const elementsShapeQuery = indent(\n shapeToEdgeQL(elementsShape as object, {...ctx}, expr.__element__),\n 2\n )\n .trim()\n .split(scopeVar!.name + \".\")\n .join(`${selectTarget}.elements.`);\n\n selectStatement.push(`SELECT ${selectTarget} {\n key: {${groupingSet.__exprs__.map(e => e[0]).join(\", \")}},\n grouping,\n elements: ${elementsShapeQuery}\n}`);\n return `(${selectStatement.join(\"\\n\")})`;\n } else if (expr.__kind__ === ExpressionKind.Function) {\n const args = expr.__args__.map(arg => `${renderEdgeQL(arg!, ctx, false)}`);\n for (const [key, arg] of Object.entries(expr.__namedargs__)) {\n args.push(`${q(key)} := ${renderEdgeQL(arg, ctx, false)}`);\n }\n return `${expr.__name__}(${args.join(\", \")})`;\n } else if (expr.__kind__ === ExpressionKind.Operator) {\n const operator = expr.__name__;\n const args = expr.__args__;\n switch (expr.__opkind__) {\n case OperatorKind.Infix:\n if (operator === \"[]\") {\n let index = \"\";\n if (Array.isArray(args[1])) {\n const [start, end] = args[1];\n if (start) {\n index += renderEdgeQL(start, ctx);\n }\n index += \":\";\n if (end) {\n index += renderEdgeQL(end, ctx);\n }\n } else {\n index = renderEdgeQL(args[1], ctx);\n }\n\n return `${renderEdgeQL(args[0], ctx)}[${index}]`;\n }\n return `(${renderEdgeQL(args[0], ctx)} ${operator} ${renderEdgeQL(\n args[1],\n ctx\n )})`;\n case OperatorKind.Postfix:\n return `(${renderEdgeQL(args[0], ctx)} ${operator})`;\n case OperatorKind.Prefix:\n return `(${operator} ${renderEdgeQL(args[0], ctx)})`;\n case OperatorKind.Ternary:\n if (operator === \"if_else\") {\n return `(${renderEdgeQL(args[0], ctx)} IF ${renderEdgeQL(\n args[1],\n ctx\n )} ELSE ${renderEdgeQL(args[2], ctx)})`;\n } else {\n throw new Error(`Unknown operator: ${operator}`);\n }\n default:\n util.assertNever(\n expr.__opkind__,\n new Error(`Unknown operator kind: ${expr.__opkind__}`)\n );\n }\n } else if (expr.__kind__ === ExpressionKind.TypeIntersection) {\n return `${renderEdgeQL(expr.__expr__, ctx)}[IS ${\n expr.__element__.__name__\n }]`;\n } else if (expr.__kind__ === ExpressionKind.For) {\n ctx.forVars.set(expr.__forVar__, `__forVar__${ctx.forVars.size}`);\n return `(${withBlock}FOR ${ctx.forVars.get(\n expr.__forVar__\n )} IN {${renderEdgeQL(expr.__iterSet__, ctx)}}\nUNION (\\n${indent(renderEdgeQL(expr.__expr__, ctx), 2)}\\n))`;\n } else if (expr.__kind__ === ExpressionKind.ForVar) {\n const forVar = ctx.forVars.get(expr);\n if (!forVar) {\n throw new Error(`'FOR' loop variable used outside of 'FOR' loop`);\n }\n return forVar;\n } else if (expr.__kind__ === ExpressionKind.Param) {\n return `__param__${expr.__name__}`;\n } else if (expr.__kind__ === ExpressionKind.Detached) {\n return `(DETACHED ${renderEdgeQL(\n expr.__expr__,\n {\n ...ctx,\n renderWithVar: expr.__expr__ as any\n },\n undefined,\n true\n )})`;\n } else if (expr.__kind__ === ExpressionKind.Global) {\n return `(GLOBAL ${expr.__name__})`;\n } else {\n util.assertNever(\n expr,\n new Error(`Unrecognized expression kind: \"${(expr as any).__kind__}\"`)\n );\n }\n}\n\nfunction isGroupingSet(arg: any): arg is GroupingSet {\n return arg.__kind__ === \"groupingset\";\n}\n\n// recursive renderer\nfunction renderGroupingSet(set: GroupingSet): string {\n const contents = Object.entries(set.__elements__)\n .map(([k, v]) => {\n return isGroupingSet(v) ? renderGroupingSet(v) : k;\n })\n .join(\", \");\n if (set.__settype__ === \"tuple\") {\n return `(${contents})`;\n } else if (set.__settype__ === \"set\") {\n return `{${contents}}`;\n } else if (set.__settype__ === \"cube\") {\n return `cube(${contents})`;\n } else if (set.__settype__ === \"rollup\") {\n return `rollup(${contents})`;\n } else {\n throw new Error(`Unrecognized set type: \"${set.__settype__}\"`);\n }\n}\n\nfunction shapeToEdgeQL(\n shape: object | null,\n ctx: RenderCtx,\n type: ObjectType | null = null,\n keysOnly: boolean = false,\n injectImplicitId: boolean = true\n) {\n const pointers = type?.__pointers__ || null;\n const isFreeObject = type?.__name__ === \"std::FreeObject\";\n if (shape === null) {\n return ``;\n }\n\n const lines: string[] = [];\n const addLine = (line: string) =>\n lines.push(`${keysOnly ? \"\" : \" \"}${line}`);\n\n const seen = new Set();\n\n for (const key in shape) {\n if (!shape.hasOwnProperty(key)) continue;\n if (seen.has(key)) {\n // tslint:disable-next-line\n console.warn(`Invalid: duplicate key \"${key}\"`);\n continue;\n }\n seen.add(key);\n let val = (shape as any)[key];\n let operator = \":=\";\n let polyType: SomeExpression | null = null;\n\n if (typeof val === \"object\" && !val.__element__) {\n if (!!val[\"+=\"]) {\n operator = \"+=\";\n val = val[\"+=\"];\n } else if (!!val[\"-=\"]) {\n operator = \"-=\";\n val = val[\"-=\"];\n }\n }\n if (val.__kind__ === ExpressionKind.PolyShapeElement) {\n polyType = val.__polyType__;\n val = val.__shapeElement__;\n }\n const polyIntersection = polyType\n ? `[IS ${polyType.__element__.__name__}].`\n : \"\";\n\n // For computed properties in select shapes, inject the expected\n // cardinality inferred by the query builder. This ensures the actual\n // type returned by the server matches the inferred return type, or an\n // explicit error is thrown, instead of a silent mismatch between\n // actual and inferred type.\n // Add annotations on FreeObjects, despite the existence of a pointer.\n const ptr = pointers?.[key];\n const addCardinalityAnnotations = pointers && (!ptr || isFreeObject);\n\n const expectedCardinality =\n addCardinalityAnnotations && val.hasOwnProperty(\"__cardinality__\")\n ? val.__cardinality__ === Cardinality.Many ||\n val.__cardinality__ === Cardinality.AtLeastOne\n ? \"multi \"\n : \"single \"\n : \"\";\n\n // if selecting a required multi link, wrap expr in 'assert_exists'\n const wrapAssertExists = ptr?.cardinality === Cardinality.AtLeastOne;\n\n if (typeof val === \"boolean\") {\n if (\n !pointers?.[key] &&\n key[0] !== \"@\" &&\n type &&\n type?.__name__ !== \"std::FreeObject\" &&\n !polyIntersection\n ) {\n throw new Error(`Field \"${key}\" does not exist in ${type?.__name__}`);\n }\n if (val) {\n addLine(`${polyIntersection}${q(key)}`);\n }\n continue;\n }\n\n if (typeof val !== \"object\") {\n throw new Error(`Invalid shape element at \"${key}\".`);\n }\n\n const valIsExpression = val.hasOwnProperty(\"__kind__\");\n\n // is subshape\n if (!valIsExpression) {\n addLine(\n `${polyIntersection}${q(key, false)}: ${indent(\n shapeToEdgeQL(val, ctx, ptr?.target),\n 2\n ).trim()}`\n );\n continue;\n }\n\n // val is expression\n\n // is computed\n if (keysOnly) {\n addLine(\n q(key, false) +\n (isObjectType(val.__element__)\n ? `: ${shapeToEdgeQL(val.__element__.__shape__, ctx, null, true)}`\n : \"\")\n );\n continue;\n }\n const renderedExpr = renderEdgeQL(val, ctx);\n\n addLine(\n `${expectedCardinality}${q(key, false)} ${operator} ${\n wrapAssertExists ? \"assert_exists(\" : \"\"\n }${\n renderedExpr.includes(\"\\n\")\n ? `(\\n${indent(\n renderedExpr[0] === \"(\" &&\n renderedExpr[renderedExpr.length - 1] === \")\"\n ? renderedExpr.slice(1, -1)\n : renderedExpr,\n 4\n )}\\n )`\n : renderedExpr\n }${wrapAssertExists ? \")\" : \"\"}`\n );\n }\n\n if (lines.length === 0 && injectImplicitId) {\n addLine(\"id\");\n }\n return keysOnly ? `{${lines.join(\", \")}}` : `{\\n${lines.join(\",\\n\")}\\n}`;\n}\n\nfunction topoSortWithVars(\n vars: Set,\n ctx: RenderCtx\n): SomeExpression[] {\n if (!vars.size) {\n return [];\n }\n\n const sorted: SomeExpression[] = [];\n\n const unvisited = new Set(vars);\n const visiting = new Set();\n\n for (const withVar of unvisited) {\n visit(withVar);\n }\n\n function visit(withVar: SomeExpression): void {\n if (!unvisited.has(withVar)) {\n return;\n }\n if (visiting.has(withVar)) {\n throw new Error(`'WITH' variables contain a cyclic dependency`);\n }\n\n visiting.add(withVar);\n\n for (const child of ctx.withVars.get(withVar)!.childExprs) {\n if (vars.has(child)) {\n visit(child);\n }\n }\n\n visiting.delete(withVar);\n unvisited.delete(withVar);\n\n sorted.push(withVar);\n }\n return sorted;\n}\n\nconst numericalTypes: Record = {\n \"std::number\": true,\n \"std::int16\": true,\n \"std::int32\": true,\n \"std::int64\": true,\n \"std::float32\": true,\n \"std::float64\": true\n};\n\nfunction literalToEdgeQL(type: BaseType, val: any): string {\n let skipCast = false;\n let stringRep;\n if (type.__name__ === \"std::json\") {\n skipCast = true;\n stringRep = `to_json($$${JSON.stringify(val)}$$)`;\n } else if (typeof val === \"string\") {\n if (numericalTypes[type.__name__]) {\n skipCast = true;\n stringRep = val;\n } else if (type.__kind__ === TypeKind.enum) {\n skipCast = true;\n const vals = (type as EnumType).__values__;\n if (vals.includes(val)) {\n skipCast = true;\n if (val.includes(\" \")) {\n stringRep = `<${type.__name__}>\"${val}\"`;\n } else {\n stringRep = `${type.__name__}.${val}`;\n }\n } else {\n throw new Error(\n `Invalid value for type ${type.__name__}: ${JSON.stringify(val)}`\n );\n }\n } else {\n if (type.__name__ === \"std::str\") {\n skipCast = true;\n }\n stringRep = JSON.stringify(val);\n }\n } else if (typeof val === \"number\") {\n if (numericalTypes[type.__name__]) {\n skipCast = true;\n } else {\n throw new Error(`Unknown numerical type: ${type.__name__}!`);\n }\n stringRep = `${val.toString()}`;\n } else if (typeof val === \"boolean\") {\n stringRep = `${val.toString()}`;\n skipCast = true;\n } else if (typeof val === \"bigint\") {\n stringRep = `${val.toString()}n`;\n } else if (Array.isArray(val)) {\n skipCast = val.length !== 0;\n if (isArrayType(type)) {\n stringRep = `[${val\n .map(el => literalToEdgeQL(type.__element__ as any, el))\n .join(\", \")}]`;\n } else if (isTupleType(type)) {\n stringRep = `( ${val\n .map((el, j) => literalToEdgeQL(type.__items__[j] as any, el))\n .join(\", \")}${type.__items__.length === 1 ? \",\" : \"\"} )`;\n } else {\n throw new Error(\n `Invalid value for type ${type.__name__}: ${JSON.stringify(val)}`\n );\n }\n } else if (val instanceof Date) {\n stringRep = `'${val.toISOString()}'`;\n } else if (\n val instanceof LocalDate ||\n val instanceof LocalDateTime ||\n val instanceof LocalTime ||\n val instanceof Duration ||\n val instanceof RelativeDuration ||\n val instanceof DateDuration\n ) {\n stringRep = `'${val.toString()}'`;\n } else if (val instanceof Uint8Array) {\n stringRep = bufferToStringRep(val);\n skipCast = true;\n } else if (val instanceof Range) {\n const elType = (type as RangeType).__element__;\n\n // actual type will be inferred from\n // defined value\n const elTypeName =\n elType.__name__ === \"std::number\" ? \"std::int64\" : elType.__name__;\n\n return `std::range(${\n val.lower === null\n ? `<${elTypeName}>{}`\n : literalToEdgeQL(elType, val.lower)\n }, ${\n val.upper === null\n ? `<${elTypeName}>{}`\n : literalToEdgeQL(elType, val.upper)\n }, inc_lower := ${val.incLower}, inc_upper := ${val.incUpper})`;\n } else if (typeof val === \"object\") {\n if (isNamedTupleType(type)) {\n stringRep = `( ${Object.entries(val).map(\n ([key, value]) =>\n `${key} := ${literalToEdgeQL(type.__shape__[key], value)}`\n )} )`;\n skipCast = true;\n } else {\n throw new Error(\n `Invalid value for type ${type.__name__}: ${JSON.stringify(val)}`\n );\n }\n } else {\n throw new Error(\n `Invalid value for type ${type.__name__}: ${JSON.stringify(val)}`\n );\n }\n if (skipCast) {\n return stringRep;\n }\n return `<${type.__name__}>${stringRep}`;\n}\n\nfunction indent(str: string, depth: number) {\n return str\n .split(\"\\n\")\n .map(line => \" \".repeat(depth) + line)\n .join(\"\\n\");\n}\n\n// backtick quote identifiers if needed\n// https://github.com/edgedb/edgedb/blob/master/edb/edgeql/quote.py\nfunction q(ident: string, allowBacklinks: boolean = true): string {\n if (\n !ident ||\n ident.startsWith(\"@\") ||\n (allowBacklinks && (ident.startsWith(\"<\") || ident.includes(\"::\")))\n ) {\n return ident;\n }\n\n const isAlphaNum = /^([^\\W\\d]\\w*|([1-9]\\d*|0))$/.test(ident);\n if (isAlphaNum) {\n const lident = ident.toLowerCase();\n const isReserved =\n lident !== \"__type__\" &&\n lident !== \"__std__\" &&\n reservedKeywords.includes(lident);\n\n if (!isReserved) {\n return ident;\n }\n }\n\n return \"`\" + ident.replace(/`/g, \"``\") + \"`\";\n}\n\nfunction bufferToStringRep(buf: Uint8Array): string {\n let stringRep = \"\";\n for (const byte of buf) {\n if (byte < 32 || byte > 126) {\n // non printable ascii\n switch (byte) {\n case 8:\n stringRep += \"\\\\b\";\n break;\n case 9:\n stringRep += \"\\\\t\";\n break;\n case 10:\n stringRep += \"\\\\n\";\n break;\n case 12:\n stringRep += \"\\\\f\";\n break;\n case 13:\n stringRep += \"\\\\r\";\n break;\n default:\n stringRep += `\\\\x${byte.toString(16).padStart(2, \"0\")}`;\n }\n } else {\n stringRep +=\n (byte === 39 || byte === 92 ? \"\\\\\" : \"\") + String.fromCharCode(byte);\n }\n }\n return `b'${stringRep}'`;\n}\n\nfunction getErrorHint(expr: any): string {\n let literalConstructor: string | null = null;\n switch (typeof expr) {\n case \"string\":\n literalConstructor = \"e.str()\";\n break;\n case \"number\":\n literalConstructor = Number.isInteger(expr)\n ? \"e.int64()\"\n : \"e.float64()\";\n break;\n case \"bigint\":\n literalConstructor = \"e.bigint()\";\n break;\n case \"boolean\":\n literalConstructor = \"e.bool()\";\n break;\n }\n switch (true) {\n case expr instanceof Date:\n literalConstructor = \"e.datetime()\";\n break;\n case expr instanceof Duration:\n literalConstructor = \"e.duration()\";\n break;\n case expr instanceof LocalDate:\n literalConstructor = \"e.cal.local_date()\";\n break;\n case expr instanceof LocalDateTime:\n literalConstructor = \"e.cal.local_datetime()\";\n break;\n case expr instanceof LocalTime:\n literalConstructor = \"e.cal.local_time()\";\n break;\n case expr instanceof RelativeDuration:\n literalConstructor = \"e.cal.relative_duration()\";\n break;\n case expr instanceof DateDuration:\n literalConstructor = \"e.cal.date_duration()\";\n break;\n }\n\n return literalConstructor\n ? `\\nHint: Maybe you meant to wrap the value in ` +\n `a '${literalConstructor}' expression?`\n : \"\";\n}\n"},{"path":"typesystem.ts","content":"import type {Executor} from \"edgedb/_src/ifaces.ts\";\nimport type {$expr_PathNode, $expr_TypeIntersection, $pathify} from \"./path.ts\";\nimport type {$expr_Literal} from \"./literal.ts\";\nimport type {$expr_Operator} from \"./funcops.ts\";\nimport type {\n typeutil,\n Cardinality,\n ExpressionKind\n} from \"edgedb/_src/reflection/index.ts\";\nimport {TypeKind} from \"edgedb/_src/reflection/index.ts\";\nimport type {cardutil} from \"./cardinality.ts\";\nimport type {Range} from \"edgedb\";\n\n//////////////////\n// BASETYPE\n//////////////////\n\nexport interface BaseType {\n __kind__: TypeKind;\n __name__: string;\n}\nexport type BaseTypeSet = {\n __element__: BaseType;\n __cardinality__: Cardinality;\n};\nexport type BaseTypeTuple = typeutil.tupleOf;\n\n//////////////////\n// SCALARTYPE\n//////////////////\n\nexport interface ScalarType<\n Name extends string = string,\n TsType extends any = any,\n TsConstType extends TsType = TsType\n> extends BaseType {\n __kind__: TypeKind.scalar;\n __tstype__: TsType;\n __tsconsttype__: TsConstType;\n __name__: Name;\n}\n\nexport type scalarTypeWithConstructor<\n S extends ScalarType,\n ExtraTsTypes extends any = never\n> = S & {\n // tslint:disable-next-line\n (val: T): $expr_Literal<\n ScalarType<\n S[\"__name__\"],\n S[\"__tstype__\"],\n T extends S[\"__tstype__\"] ? T : S[\"__tstype__\"]\n >\n >;\n};\n\ntype $jsonDestructure =\n Set[\"__element__\"] extends ScalarType<\"std::json\">\n ? {\n [path: string]: $expr_Operator<\n // \"[]\",\n // OperatorKind.Infix,\n // [Set, TypeSet],\n // TypeSet<\n Set[\"__element__\"],\n Set[\"__cardinality__\"]\n // >\n >;\n } & {\n destructure> | string>(\n path: T\n ): $expr_Operator<\n // \"[]\",\n // OperatorKind.Infix,\n // [Set, TypeSet],\n // TypeSet<\n Set[\"__element__\"],\n cardutil.multiplyCardinalities<\n Set[\"__cardinality__\"],\n T extends TypeSet ? T[\"__cardinality__\"] : Cardinality.One\n >\n // >\n >;\n }\n : unknown;\n\n////////////////////\n// SETS AND EXPRESSIONS\n////////////////////\n\nexport interface TypeSet<\n T extends BaseType = BaseType,\n Card extends Cardinality = Cardinality\n> {\n __element__: T;\n __cardinality__: Card;\n}\n\n// utility function for creating set\nexport function $toSet(\n root: Root,\n card: Card\n): TypeSet {\n return {\n __element__: root,\n __cardinality__: card\n };\n}\n\nexport type Expression<\n Set extends TypeSet = TypeSet,\n Runnable extends boolean = true\n> = Set &\n (BaseType extends Set[\"__element__\"] // short-circuit non-specific types\n ? {\n run(cxn: Executor): any;\n runJSON(cxn: Executor): any;\n toEdgeQL(): string;\n is: any;\n assert_single: any;\n // warning: any;\n }\n : $pathify &\n ExpressionMethods> &\n (Runnable extends true\n ? {\n run(cxn: Executor): Promise>;\n runJSON(cxn: Executor): Promise;\n }\n : {}) &\n $tuplePathify &\n $arrayLikeIndexify &\n $jsonDestructure);\n\nexport type stripSet = \"__element__\" extends keyof T\n ? \"__cardinality__\" extends keyof T\n ? {\n __element__: T[\"__element__\"];\n __cardinality__: T[\"__cardinality__\"];\n }\n : T\n : T;\n\n// export type stripSet = T extends {__element__: any; __cardinality__: any}\n// ? {\n// __element__: T[\"__element__\"];\n// __cardinality__: T[\"__cardinality__\"];\n// }\n// : any;\n\nexport type stripSetShape = {\n [k in keyof T]: stripSet;\n};\n\n// importing the actual alias from\n// generated/modules/std didn't work.\n// returned 'any' every time\nexport type assert_single<\n El extends BaseType,\n Card extends Cardinality\n> = Expression<{\n __element__: El; // [\"__element__\"];\n __cardinality__: Card; // cardutil.overrideUpperBound<\n // Expr[\"__cardinality__\"], \"One\"\n // >;\n __kind__: ExpressionKind.Function;\n __name__: \"std::assert_single\";\n __args__: TypeSet[]; // discard wrapped expression\n __namedargs__: {};\n}>;\n\nexport type ExpressionMethods = {\n toEdgeQL(): string;\n\n is(\n ixn: T\n ): $expr_TypeIntersection<\n Set[\"__cardinality__\"],\n // might cause performance issues\n ObjectType<\n T[\"__element__\"][\"__name__\"],\n T[\"__element__\"][\"__pointers__\"],\n {id: true}\n >\n >;\n assert_single(): assert_single<\n Set[\"__element__\"],\n Cardinality.AtMostOne\n // cardutil.overrideUpperBound\n >;\n};\n\n//////////////////\n// ENUMTYPE\n//////////////////\nexport interface EnumType<\n Name extends string = string,\n Values extends [string, ...string[]] = [string, ...string[]]\n> extends BaseType {\n __kind__: TypeKind.enum;\n __tstype__: Values[number];\n __name__: Name;\n __values__: Values;\n}\n\n//////////////////\n// OBJECTTYPE\n//////////////////\n\nexport type ObjectTypeSet = TypeSet;\nexport type ObjectTypeExpression = TypeSet;\n\nexport type ExclusiveTuple = typeutil.tupleOf<{\n [k: string]: TypeSet;\n}>;\nexport interface ObjectType<\n Name extends string = string,\n Pointers extends ObjectTypePointers = ObjectTypePointers,\n Shape extends object | null = any,\n Exclusives extends ExclusiveTuple = ExclusiveTuple\n // Polys extends Poly[] = any[]\n> extends BaseType {\n __kind__: TypeKind.object;\n __name__: Name;\n __pointers__: Pointers;\n __shape__: Shape;\n __exclusives__: Exclusives;\n}\n\nexport type PropertyTypes =\n | ScalarType\n | EnumType\n | ArrayType\n | TupleType\n | NamedTupleType;\n\nexport type SomeType =\n | ScalarType\n | EnumType\n | ArrayType\n | TupleType\n | ObjectType\n | NamedTupleType\n | RangeType;\n\nexport interface PropertyDesc<\n Type extends BaseType = BaseType,\n Card extends Cardinality = Cardinality,\n Exclusive extends boolean = boolean,\n Computed extends boolean = boolean,\n Readonly extends boolean = boolean,\n HasDefault extends boolean = boolean\n> {\n __kind__: \"property\";\n target: Type;\n cardinality: Card;\n exclusive: Exclusive;\n computed: Computed;\n readonly: Readonly;\n hasDefault: HasDefault;\n}\n\nexport type $scopify = $expr_PathNode<\n TypeSet\n // null,\n // true // exclusivity\n>;\n\nexport type PropertyShape = {\n [k: string]: PropertyDesc;\n};\n\nexport interface LinkDesc<\n Type extends ObjectType = any,\n Card extends Cardinality = Cardinality,\n LinkProps extends PropertyShape = any,\n Exclusive extends boolean = boolean,\n Computed extends boolean = boolean,\n Readonly extends boolean = boolean,\n HasDefault extends boolean = boolean\n> {\n __kind__: \"link\";\n target: Type;\n cardinality: Card;\n properties: LinkProps;\n exclusive: Exclusive;\n computed: Computed;\n readonly: Readonly;\n hasDefault: HasDefault;\n}\n\nexport type ObjectTypePointers = {\n [k: string]: PropertyDesc | LinkDesc;\n};\n\nexport type stripBacklinks = {\n [k in keyof T]: k extends `<${string}` ? never : T[k];\n};\n\nexport type omitBacklinks =\n T extends `<${string}` ? never : T extends string ? T : never;\n\nexport type stripNonUpdateables = {\n [k in keyof T]: [T[k][\"computed\"]] extends [true]\n ? never\n : [T[k][\"readonly\"]] extends [true]\n ? never\n : k extends \"__type__\"\n ? never\n : k extends \"id\"\n ? never\n : T[k];\n};\n\nexport type stripNonInsertables = {\n [k in keyof T]: [T[k][\"computed\"]] extends [true]\n ? never\n : [k] extends [\"__type__\"]\n ? never\n : T[k];\n};\n\ntype shapeElementToTs = [\n Element\n] extends [true]\n ? pointerToTsType\n : [Element] extends [false]\n ? never\n : [Element] extends [boolean]\n ? pointerToTsType | undefined\n : Element extends TypeSet\n ? setToTsType>\n : Pointer extends LinkDesc\n ? Element extends object\n ? computeTsTypeCard<\n computeObjectShape<\n Pointer[\"target\"][\"__pointers__\"] & Pointer[\"properties\"],\n Element\n >,\n Pointer[\"cardinality\"]\n >\n : never\n : never;\n\n// Element extends (scope: any) => any\n// ? Pointer[\"target\"] extends ObjectType\n// ? computeObjectShape<\n// Pointer[\"target\"][\"__pointers__\"],\n// ReturnType\n// >\n// : never\n// : Element extends object\n// ? Pointer[\"target\"] extends ObjectType\n// ? computeObjectShape\n// : never\n// : never;\n\nexport type $expr_PolyShapeElement<\n PolyType extends ObjectTypeSet = ObjectTypeSet,\n ShapeElement extends any = any\n> = {\n __kind__: ExpressionKind.PolyShapeElement;\n __polyType__: PolyType;\n __shapeElement__: ShapeElement;\n};\n\nexport type computeObjectShape<\n Pointers extends ObjectTypePointers,\n Shape\n> = typeutil.flatten<\n keyof Shape extends never\n ? {id: string}\n : {\n [k in keyof Shape]: Shape[k] extends $expr_PolyShapeElement<\n infer PolyType,\n infer ShapeEl\n >\n ? [k] extends [keyof PolyType[\"__element__\"][\"__pointers__\"]]\n ? shapeElementToTs<\n PolyType[\"__element__\"][\"__pointers__\"][k],\n ShapeEl\n > | null\n : never\n : [k] extends [keyof Pointers]\n ? shapeElementToTs\n : Shape[k] extends TypeSet\n ? setToTsType\n : never;\n }\n>;\n\nexport type pointerToTsTypeSimple =\n El extends PropertyDesc\n ? propToTsType\n : El extends LinkDesc\n ? {id: string}\n : never;\n\nexport type PrimitiveType =\n | ScalarType\n | EnumType\n | TupleType\n | NamedTupleType\n | ArrayType\n | RangeType;\n\nexport type PrimitiveTypeSet = TypeSet;\n\n/////////////////////////\n/// ARRAYTYPE\n/////////////////////////\n\ntype $arrayLikeIndexify = Set[\"__element__\"] extends\n | ArrayType\n | ScalarType<\"std::str\">\n | ScalarType<\"std::bytes\">\n ? {\n [index: number]: $expr_Operator<\n // \"[]\",\n // OperatorKind.Infix,\n // [Set, TypeSet],\n // TypeSet<\n getPrimitiveBaseType<\n Set[\"__element__\"] extends ArrayType\n ? El\n : Set[\"__element__\"]\n >,\n Set[\"__cardinality__\"]\n // >\n >;\n [slice: `${number}:${number | \"\"}` | `:${number}`]: $expr_Operator<\n // \"[]\",\n // OperatorKind.Infix,\n // [Set, TypeSet],\n // TypeSet<\n getPrimitiveBaseType,\n Set[\"__cardinality__\"]\n // >\n >;\n index> | number>(\n index: T\n ): $expr_Operator<\n // \"[]\",\n // OperatorKind.Infix,\n // [Set, TypeSet],\n // TypeSet<\n getPrimitiveBaseType<\n Set[\"__element__\"] extends ArrayType\n ? El\n : Set[\"__element__\"]\n >,\n cardutil.multiplyCardinalities<\n Set[\"__cardinality__\"],\n T extends TypeSet ? T[\"__cardinality__\"] : Cardinality.One\n >\n // >\n >;\n slice<\n S extends TypeSet> | number,\n E extends\n | TypeSet>\n | number\n | undefined\n | null\n >(\n start: S,\n end: E\n ): $expr_Operator<\n // \"[]\",\n // OperatorKind.Infix,\n // [Set, TypeSet],\n // TypeSet<\n getPrimitiveBaseType,\n cardutil.multiplyCardinalities<\n cardutil.multiplyCardinalities<\n Set[\"__cardinality__\"],\n S extends TypeSet ? S[\"__cardinality__\"] : Cardinality.One\n >,\n E extends TypeSet ? C : Cardinality.One\n >\n // >\n >;\n slice<\n E extends\n | TypeSet>\n | number\n | undefined\n | null\n >(\n start: undefined | null,\n end: E\n ): $expr_Operator<\n // \"[]\",\n // OperatorKind.Infix,\n // [Set, TypeSet],\n // TypeSet<\n getPrimitiveBaseType,\n cardutil.multiplyCardinalities<\n Set[\"__cardinality__\"],\n E extends TypeSet ? C : Cardinality.One\n >\n // >\n >;\n }\n : unknown;\n\nexport type $expr_Array<\n Type extends ArrayType = ArrayType,\n Card extends Cardinality = Cardinality\n // Items extends typeutil.tupleOf>\n> = Expression<{\n __kind__: ExpressionKind.Array;\n __items__: typeutil.tupleOf>;\n __element__: Type;\n __cardinality__: Card;\n}>;\n\nexport interface ArrayType<\n Element extends BaseType = BaseType,\n Name extends string = `array<${Element[\"__name__\"]}>`\n> extends BaseType {\n __name__: Name;\n __kind__: TypeKind.array;\n __element__: Element;\n}\n\ntype ArrayTypeToTsType = BaseTypeToTsType<\n Type[\"__element__\"]\n>[];\n\n/////////////////////////\n/// TUPLE TYPE\n/////////////////////////\n\ntype $tuplePathify = Set[\"__element__\"] extends TupleType\n ? addTuplePaths\n : Set[\"__element__\"] extends NamedTupleType\n ? addNamedTuplePaths\n : unknown;\n\nexport type $expr_TuplePath<\n ItemType extends BaseType = BaseType,\n ParentCard extends Cardinality = Cardinality\n> = Expression<{\n __kind__: ExpressionKind.TuplePath;\n __element__: ItemType;\n __cardinality__: ParentCard;\n __parent__: $expr_Tuple | $expr_NamedTuple | $expr_TuplePath;\n __index__: string | number;\n}>;\n\nexport type baseTupleElementsToTupleType> =\n {\n [k in keyof T]: T[k] extends TypeSet\n ? getPrimitiveBaseType\n : never;\n };\nexport type tupleElementsToTupleType> =\n baseTupleElementsToTupleType extends BaseTypeTuple\n ? TupleType>\n : never;\n\nexport type baseTupleElementsToCardTuple = {\n [k in keyof T]: T[k] extends TypeSet ? C : never;\n};\n\nexport type tupleElementsToCardTuple =\n baseTupleElementsToCardTuple extends [Cardinality, ...Cardinality[]]\n ? baseTupleElementsToCardTuple\n : never;\n\nexport type $expr_Tuple<\n Items extends typeutil.tupleOf = typeutil.tupleOf\n> = Expression<{\n __kind__: ExpressionKind.Tuple;\n __items__: typeutil.tupleOf;\n __element__: tupleElementsToTupleType;\n __cardinality__: cardutil.multiplyCardinalitiesVariadic<\n tupleElementsToCardTuple\n >;\n}>;\n\nexport type indexKeys = T extends `${number}` ? T : never;\n\ntype addTuplePaths<\n Items extends BaseType[],\n ParentCard extends Cardinality\n> = {\n [k in indexKeys]: Items[k] extends BaseType\n ? $expr_TuplePath\n : never;\n};\n\nexport interface TupleType\n extends BaseType {\n __name__: string;\n __kind__: TypeKind.tuple;\n __items__: Items;\n}\n\ntype TupleItemsToTsType = {\n [k in keyof Items]: Items[k] extends BaseType\n ? BaseTypeToTsType\n : never;\n};\n\n/////////////////////////\n/// NAMED TUPLE TYPE\n/////////////////////////\ntype literalShapeToType = NamedTupleType<{\n [k in keyof T]: getPrimitiveBaseType;\n}>;\ntype shapeCardinalities =\n Shape[keyof Shape][\"__cardinality__\"];\ntype inferNamedTupleCardinality = [\n Cardinality.Many\n] extends [shapeCardinalities]\n ? Cardinality.Many\n : [Cardinality.Empty] extends [shapeCardinalities]\n ? Cardinality.Empty\n : [shapeCardinalities] extends [Cardinality.AtMostOne]\n ? Cardinality.AtMostOne\n : [shapeCardinalities] extends [\n Cardinality.AtMostOne | Cardinality.One\n ]\n ? Cardinality.One\n : Cardinality.Many;\n\nexport type $expr_NamedTuple<\n Shape extends NamedTupleLiteralShape = NamedTupleLiteralShape\n> = Expression<{\n __kind__: ExpressionKind.NamedTuple;\n __element__: literalShapeToType;\n __cardinality__: inferNamedTupleCardinality;\n __shape__: Shape;\n}>;\n\ntype addNamedTuplePaths<\n Shape extends NamedTupleShape,\n ParentCard extends Cardinality\n> = {\n [k in keyof Shape]: Shape[k] extends BaseType\n ? $expr_TuplePath\n : never;\n};\n\nexport type NamedTupleLiteralShape = {[k: string]: TypeSet};\nexport type NamedTupleShape = {[k: string]: BaseType};\nexport interface NamedTupleType<\n Shape extends NamedTupleShape = NamedTupleShape\n> extends BaseType {\n __name__: string;\n __kind__: TypeKind.namedtuple;\n __shape__: Shape;\n}\n\ntype NamedTupleTypeToTsType = {\n [k in keyof Type[\"__shape__\"]]: BaseTypeToTsType;\n};\n\n/////////////////////////\n/// RANGE TYPE\n/////////////////////////\n\nexport interface RangeType<\n Element extends ScalarType = ScalarType,\n Name extends string = `range<${Element[\"__name__\"]}>`\n> extends BaseType {\n __name__: Name;\n __kind__: TypeKind.range;\n __element__: Element;\n}\n\n/////////////////////\n/// TSTYPE COMPUTATION\n/////////////////////\nexport type orLiteralValue =\n | Set\n | (Set[\"__element__\"] extends ObjectType\n ? never\n : computeTsType);\n\nexport type BaseTypeToTsType = Type extends ScalarType\n ? Type[\"__tsconsttype__\"]\n : Type extends EnumType\n ? Type[\"__tstype__\"]\n : Type extends ArrayType\n ? typeutil.flatten>\n : Type extends RangeType\n ? Range\n : Type extends TupleType\n ? TupleItemsToTsType\n : Type extends NamedTupleType\n ? typeutil.flatten>\n : Type extends ObjectType\n ? typeutil.flatten<\n computeObjectShape\n >\n : never;\n\nexport type setToTsType = computeTsType<\n Set[\"__element__\"],\n Set[\"__cardinality__\"]\n>;\n\nexport type computeTsTypeCard<\n T extends any,\n C extends Cardinality\n> = Cardinality extends C\n ? unknown\n : C extends Cardinality.Empty\n ? null\n : C extends Cardinality.One\n ? T\n : C extends Cardinality.AtLeastOne\n ? [T, ...T[]]\n : C extends Cardinality.AtMostOne\n ? T | null\n : C extends Cardinality.Many\n ? T[]\n : C extends Cardinality\n ? unknown\n : never;\n\nexport type computeTsType<\n T extends BaseType,\n C extends Cardinality\n> = BaseType extends T ? unknown : computeTsTypeCard, C>;\n\nexport type propToTsType =\n Prop extends PropertyDesc\n ? setToTsType>\n : never;\n\nexport type linkToTsType = computeTsType<\n Link[\"target\"],\n Link[\"cardinality\"]\n>;\n\nexport type pointerToTsType =\n El extends PropertyDesc\n ? propToTsType\n : El extends LinkDesc\n ? linkToTsType\n : never;\n\n///////////////////\n// TYPE HELPERS\n///////////////////\n\nexport type getPrimitiveBaseType = T extends ScalarType\n ? ScalarType\n : T;\n\nexport type getPrimitiveNonArrayBaseType =\n T extends NonArrayType ? getPrimitiveBaseType : never;\n\nexport function isScalarType(type: BaseType): type is ScalarType {\n return type.__kind__ === TypeKind.scalar;\n}\nexport function isEnumType(type: BaseType): type is EnumType {\n return type.__kind__ === TypeKind.enum;\n}\nexport function isObjectType(type: BaseType): type is ObjectType {\n return type.__kind__ === TypeKind.object;\n}\nexport function isTupleType(type: BaseType): type is TupleType {\n return type.__kind__ === TypeKind.tuple;\n}\nexport function isNamedTupleType(type: BaseType): type is NamedTupleType {\n return type.__kind__ === TypeKind.namedtuple;\n}\nexport function isArrayType(type: BaseType): type is ArrayType {\n return type.__kind__ === TypeKind.array;\n}\n\nexport type NonArrayType =\n | ScalarType\n | EnumType\n | ObjectType\n | TupleType\n | NamedTupleType\n | RangeType;\n\nexport type AnyTupleType = TupleType | NamedTupleType;\n\nexport type ParamType =\n | ScalarType\n | EnumType\n | ArrayType<\n | ScalarType\n | TupleType>\n | NamedTupleType<{[k: string]: ParamType}>\n | RangeType\n >\n | TupleType>\n | NamedTupleType<{[k: string]: ParamType}>\n | RangeType;\n"},{"path":"update.ts","content":"import {\n ExpressionKind,\n typeutil,\n Cardinality\n} from \"edgedb/_src/reflection/index.ts\";\nimport type {\n Expression,\n ObjectTypePointers,\n TypeSet,\n ObjectTypeSet,\n stripBacklinks,\n stripNonUpdateables,\n ObjectTypeExpression,\n ObjectType,\n $scopify\n} from \"./typesystem.ts\";\nimport type {pointerToAssignmentExpression} from \"./casting.ts\";\nimport {$expressionify, $getScopedExpr} from \"./path.ts\";\nimport {\n SelectModifiers,\n NormalisedSelectModifiers,\n ComputeSelectCardinality,\n $existingScopes,\n $handleModifiers\n} from \"./select.ts\";\nimport {$normaliseInsertShape, pointerIsOptional} from \"./insert.ts\";\n\n/////////////////\n/// UPDATE\n/////////////////\n\nexport type $expr_Update<\n El extends ObjectType = ObjectType,\n Card extends Cardinality = Cardinality\n // Set extends TypeSet = TypeSet,\n // Expr extends ObjectTypeSet = ObjectTypeSet,\n // Shape extends UpdateShape = any\n> = Expression<{\n __kind__: ExpressionKind.Update;\n __element__: El;\n __cardinality__: Card;\n __expr__: TypeSet;\n __shape__: any;\n __modifiers__: NormalisedSelectModifiers;\n __scope__: ObjectTypeExpression;\n}>;\n\nexport type UpdateShape = typeutil.stripNever<\n stripNonUpdateables>\n> extends infer Shape\n ? Shape extends ObjectTypePointers\n ? {\n [k in keyof Shape]?:\n | (\n | pointerToAssignmentExpression\n | (Shape[k][\"cardinality\"] extends\n | Cardinality.Many\n | Cardinality.AtLeastOne\n ?\n | {\"+=\": pointerToAssignmentExpression}\n | {\"-=\": pointerToAssignmentExpression}\n : never)\n )\n | (pointerIsOptional extends true\n ? undefined | null\n : never);\n }\n : never\n : never;\n\nexport function update<\n Expr extends ObjectTypeExpression,\n Shape extends {\n filter?: SelectModifiers[\"filter\"];\n filter_single?: SelectModifiers[\"filter_single\"];\n order_by?: SelectModifiers[\"order_by\"];\n limit?: SelectModifiers[\"limit\"];\n offset?: SelectModifiers[\"offset\"];\n set: UpdateShape;\n }\n // SetShape extends UpdateShape,\n // Modifiers extends Pick\n>(\n expr: Expr,\n shape: (scope: $scopify) => Readonly\n): $expr_Update<\n // {\n // __element__: Expr[\"__element__\"];\n // __cardinality__: ComputeSelectCardinality;\n // },\n Expr[\"__element__\"],\n ComputeSelectCardinality\n // Expr,\n // Shape[\"set\"]\n> {\n const cleanScopedExprs = $existingScopes.size === 0;\n\n const scope = $getScopedExpr(expr as any, $existingScopes);\n\n const resolvedShape = shape(scope);\n\n if (cleanScopedExprs) {\n $existingScopes.clear();\n }\n\n const mods: any = {};\n let updateShape: any | null;\n for (const [key, val] of Object.entries(resolvedShape)) {\n if (key === \"filter\" || key === \"filter_single\") {\n mods[key] = val;\n } else if (key === \"set\") {\n updateShape = val;\n } else {\n throw new Error(\n `Invalid update shape key '${key}', only 'filter', ` +\n `and 'set' are allowed`\n );\n }\n }\n\n if (!updateShape) {\n throw new Error(`Update shape must contain 'set' shape`);\n }\n\n const {modifiers, cardinality} = $handleModifiers(mods, {root: expr, scope});\n\n return $expressionify({\n __kind__: ExpressionKind.Update,\n __element__: expr.__element__,\n __cardinality__: cardinality,\n __expr__: expr,\n __shape__: $normaliseInsertShape(expr, updateShape, true),\n __modifiers__: modifiers,\n __scope__: scope\n }) as any;\n}\n"},{"path":"with.ts","content":"import {ExpressionKind, Cardinality} from \"edgedb/_src/reflection/index.ts\";\nimport type {BaseType, Expression, TypeSet} from \"./typesystem.ts\";\nimport type {$expr_Select} from \"./select.ts\";\nimport type {$expr_For} from \"./for.ts\";\nimport type {$expr_Insert} from \"./insert.ts\";\nimport type {$expr_Update} from \"./update.ts\";\nimport type {$expr_Group} from \"./group.ts\";\nimport {$expressionify} from \"./path.ts\";\n\nexport type $expr_Alias<\n El extends BaseType = BaseType,\n Card extends Cardinality = Cardinality\n> = Expression<{\n __element__: El;\n __cardinality__: Card;\n __kind__: ExpressionKind.Alias;\n __expr__: TypeSet;\n}>;\n\nexport function alias(\n expr: Expr\n): $expr_Alias {\n return $expressionify({\n __kind__: ExpressionKind.Alias,\n __element__: expr.__element__,\n __cardinality__: expr.__cardinality__,\n __expr__: expr\n }) as any;\n}\n\nexport type WithableExpression =\n | $expr_Select\n | $expr_For\n | $expr_Insert\n | $expr_Update\n | $expr_Group;\n\nexport type $expr_With<\n // Refs extends TypeSet[] = TypeSet[],\n Expr extends WithableExpression = WithableExpression\n> = Expression<{\n __element__: Expr[\"__element__\"];\n __cardinality__: Expr[\"__cardinality__\"];\n __kind__: ExpressionKind.With;\n __expr__: Expr;\n __refs__: TypeSet[];\n}>;\n\nfunction _with(\n refs: Expression[],\n expr: Expr\n): $expr_With {\n return $expressionify({\n __kind__: ExpressionKind.With,\n __element__: expr.__element__,\n __cardinality__: expr.__cardinality__,\n __refs__: refs,\n __expr__: expr as any\n }) as any;\n}\n\nexport {_with as with};\n"}]} \ No newline at end of file diff --git a/_generate/builders.ts b/_generate/builders.ts index fb7501d..9ac792a 100644 --- a/_generate/builders.ts +++ b/_generate/builders.ts @@ -727,20 +727,10 @@ export class DirBuilder { } const mod = this.getPath(`modules/${this._modules.get(moduleName)}`); - const edgedb = "edgedb"; - mod.addImport({$: true}, edgedb); + mod.addImportStar("$", "../reflection", {allowFileExt: true}); mod.addImportStar("_", "../imports", {allowFileExt: true}); - // @ts-ignore - const isDeno = typeof Deno !== "undefined"; - if (moduleName === "std" && isDeno) { - mod.addImport( - {Buffer: true}, - "https://deno.land/std@0.114.0/node/buffer.ts" - ); - } - return mod; } diff --git a/_generate/cli.ts b/_generate/cli.ts index 4b5db35..de22bfd 100644 --- a/_generate/cli.ts +++ b/_generate/cli.ts @@ -1,27 +1,26 @@ #!/usr/bin/env node -// tslint:disable no-console +// tslint:disable:no-console import {adapter} from "../mod.ts"; -import { - ConnectConfig, - parseConnectArguments, - validTlsSecurityValues -} from "../_src/conUtils.ts"; +import {ConnectConfig, validTlsSecurityValues} from "../_src/conUtils.ts"; +import {parseConnectArguments} from "../_src/conUtils.server.ts"; import { CommandOptions, promptForPassword, readPasswordFromStdin } from "./commandutil.ts"; import {generateQueryBuilder} from "./edgeql-js.ts"; -import {exitWithError} from "./generate.ts"; +import {runInterfacesGenerator} from "./interfaces.ts"; +import {exitWithError} from "./genutil.ts"; import {generateQueryFiles} from "./queries.ts"; const {path, readFileUtf8, exists} = adapter; enum Generator { QueryBuilder = "edgeql-js", - Queries = "queries" + Queries = "queries", + Interfaces = "interfaces" } const run = async () => { @@ -37,7 +36,7 @@ const run = async () => { } if (!generator || generator[0] === "-") { console.error( - `Error: No generator specified.\n \`npx @edgedb/generate [generator]\`\nAvailable generators:\n - edgeql-js (query builder)\n - queries (query files)` + `Error: No generator specified.\n \`npx @edgedb/generate \`\nAvailable generators:\n - edgeql-js (query builder)\n - queries (query files)` ); adapter.exit(); } @@ -48,6 +47,16 @@ const run = async () => { adapter.exit(); } + switch (generator) { + case Generator.QueryBuilder: + break; + case Generator.Queries: + break; + case Generator.Interfaces: + options.target = "ts"; + break; + } + while (args.length) { let flag = args.shift()!; let val: string | null = null; @@ -135,6 +144,11 @@ const run = async () => { connectionConfig.tlsSecurity = tlsSec; break; case "--target": + if (generator === Generator.Interfaces) { + exitWithError( + `--target is not supported for generator "${generator}"` + ); + } const target = getVal(); if (!target || !["ts", "esm", "cjs", "mts", "deno"].includes(target)) { exitWithError( @@ -147,16 +161,29 @@ const run = async () => { break; case "--out": case "--output-dir": + if ( + generator === Generator.Interfaces || + generator === Generator.Queries + ) { + exitWithError( + `--output-dir is not supported for generator "${generator}"` + ); + } options.out = getVal(); break; case "--file": - if (generator !== Generator.Queries) { - exitWithError(`Unknown option: ${flag}`); - } - if (args.length > 0 && args[0][0] !== "-") { + if (generator === Generator.Interfaces) { options.file = getVal(); + } else if (generator === Generator.Queries) { + if (args.length > 0 && args[0][0] !== "-") { + options.file = getVal(); + } else { + options.file = "dbschema/queries"; + } } else { - options.file = "dbschema/queries"; + exitWithError( + `Flag --file not supported for generator "${generator}"` + ); } break; @@ -220,6 +247,9 @@ const run = async () => { case Generator.Queries: console.log(`Generating functions from .edgeql files...`); break; + case Generator.Interfaces: + console.log(`Generating TS interfaces from schema...`); + break; } let currentDir = adapter.process.cwd(); @@ -324,6 +354,13 @@ Run this command inside an EdgeDB project directory or specify the desired targe root: projectRoot }); break; + case Generator.Interfaces: + await runInterfacesGenerator({ + options, + connectionConfig, + root: projectRoot + }); + break; } }; @@ -336,8 +373,10 @@ USAGE npx @edgedb/generate [COMMAND] [OPTIONS] COMMANDS: - edgeql-js Generate query builder queries Generate typed functions from .edgeql files + edgeql-js Generate query builder + interfaces Generate TS interfaces for schema types + CONNECTION OPTIONS: -I, --instance diff --git a/_generate/codecToType.ts b/_generate/codecToType.ts deleted file mode 100644 index fb0ff81..0000000 --- a/_generate/codecToType.ts +++ /dev/null @@ -1,148 +0,0 @@ -import type {ParseResult} from "../_src/baseConn.ts"; -import {ArrayCodec} from "../_src/codecs/array.ts"; -import {AT_LEAST_ONE, AT_MOST_ONE, MANY, ONE} from "../_src/codecs/consts.ts"; -import {EnumCodec} from "../_src/codecs/enum.ts"; -import {ICodec, ScalarCodec} from "../_src/codecs/ifaces.ts"; -import {NamedTupleCodec} from "../_src/codecs/namedtuple.ts"; -import {ObjectCodec} from "../_src/codecs/object.ts"; -import {RangeCodec} from "../_src/codecs/range.ts"; -import {SetCodec} from "../_src/codecs/set.ts"; -import {TupleCodec} from "../_src/codecs/tuple.ts"; -import {Cardinality, OutputFormat} from "../_src/ifaces.ts"; -import {Options, Session} from "../_src/options.ts"; -import type {Client} from "../mod.ts"; -import type {ClientPool} from "../_src/client.ts"; -import {prettyPrintError} from "./prettyPrint.ts"; - -export type QueryType = { - args: string; - out: string; - cardinality: Cardinality; - query: string; - imports: Set; -}; -export async function generateQueryType( - client: Client, - query: string -): Promise { - let parseResult: ParseResult; - const pool: ClientPool = (client as any).pool; - - const holder = await pool.acquireHolder(Options.defaults()); - try { - const cxn = await holder._getConnection(); - parseResult = await cxn._parse( - query, - OutputFormat.BINARY, - Cardinality.MANY, - Session.defaults(), - false - ); - } catch (err) { - throw new Error(prettyPrintError(err, query)); - } finally { - await holder.release(); - } - - const cardinality = parseResult[0]; - const inCodec = parseResult[1]; - const outCodec = parseResult[2]; - const imports = new Set(); - const args = walkCodec(inCodec, { - indent: "", - optionalNulls: true, - imports - }); - - const out = generateSetType( - walkCodec(outCodec, { - indent: "", - optionalNulls: false, - imports - }), - cardinality - ); - - return { - out, - args, - cardinality, - query, - imports - }; -} - -function generateSetType(type: string, cardinality: Cardinality): string { - switch (cardinality) { - case Cardinality.MANY: - return `${type}[]`; - case Cardinality.ONE: - return type; - case Cardinality.AT_MOST_ONE: - return `${type} | null`; - case Cardinality.AT_LEAST_ONE: - return `AtLeastOne<${type}>`; - } - throw Error(`unexpected cardinality: ${cardinality}`); -} - -// type AtLeastOne = [T, ...T[]]; - -function walkCodec( - codec: ICodec, - ctx: {indent: string; optionalNulls: boolean; imports: Set} -): string { - if (codec instanceof ScalarCodec) { - if (codec instanceof EnumCodec) { - return codec.values.map(val => JSON.stringify(val)).join(" | "); - } - if (codec.importedType) { - ctx.imports.add(codec.tsType); - } - return codec.tsType; - } - if (codec instanceof ObjectCodec || codec instanceof NamedTupleCodec) { - const fields = - codec instanceof ObjectCodec - ? codec.getFields() - : codec.getNames().map(name => ({name, cardinality: ONE})); - const subCodecs = codec.getSubcodecs(); - return `{\n${fields - .map((field, i) => { - let subCodec = subCodecs[i]; - if (subCodec instanceof SetCodec) { - if ( - !(field.cardinality === MANY || field.cardinality === AT_LEAST_ONE) - ) { - throw Error("subcodec is SetCodec, but upper cardinality is one"); - } - subCodec = subCodec.getSubcodecs()[0]; - } - return `${ctx.indent} ${JSON.stringify(field.name)}${ - ctx.optionalNulls && field.cardinality === AT_MOST_ONE ? "?" : "" - }: ${generateSetType( - walkCodec(subCodec, {...ctx, indent: ctx.indent + " "}), - field.cardinality - )};`; - }) - .join("\n")}\n${ctx.indent}}`; - } - if (codec instanceof ArrayCodec) { - return `${walkCodec(codec.getSubcodecs()[0], ctx)}[]`; - } - if (codec instanceof TupleCodec) { - return `[${codec - .getSubcodecs() - .map(subCodec => walkCodec(subCodec, ctx)) - .join(", ")}]`; - } - if (codec instanceof RangeCodec) { - const subCodec = codec.getSubcodecs()[0]; - if (!(subCodec instanceof ScalarCodec)) { - throw Error("expected range subtype to be scalar type"); - } - ctx.imports.add("Range"); - return `Range<${subCodec.tsType}>`; - } - throw Error(`unexpected codec kind: ${codec.getKind()}`); -} diff --git a/_generate/commandutil.ts b/_generate/commandutil.ts index ca284cd..53ddbcb 100644 --- a/_generate/commandutil.ts +++ b/_generate/commandutil.ts @@ -1,8 +1,8 @@ #!/usr/bin/env node -// tslint:disable no-console +// tslint:disable:no-console import {adapter} from "../mod.ts"; -import {exitWithError, Target} from "./generate.ts"; +import {exitWithError, Target} from "./genutil.ts"; export interface CommandOptions { showHelp?: boolean; diff --git a/_generate/edgeql-js.ts b/_generate/edgeql-js.ts index 4a2cec6..8db16e6 100644 --- a/_generate/edgeql-js.ts +++ b/_generate/edgeql-js.ts @@ -1,9 +1,50 @@ +// tslint:disable:no-console + import {adapter} from "../mod.ts"; -import {configFileHeader, exitWithError, generateQB} from "./generate.ts"; -import {isTTY, CommandOptions, promptBoolean} from "./commandutil.ts"; import type {ConnectConfig} from "../_src/conUtils.ts"; +import {CommandOptions, isTTY, promptBoolean} from "./commandutil.ts"; +import {$, Client, createClient} from "../mod.ts"; +import {DirBuilder} from "./builders.ts"; +import {syntax} from "./FILES.ts"; + +import {generateCastMaps} from "./edgeql-js/generateCastMaps.ts"; +import {generateFunctionTypes} from "./edgeql-js/generateFunctionTypes.ts"; +import {generateGlobals} from "./edgeql-js/generateGlobals.ts"; +import {generateIndex} from "./edgeql-js/generateIndex.ts"; +import {generateObjectTypes} from "./edgeql-js/generateObjectTypes.ts"; +import {generateOperators} from "./edgeql-js/generateOperatorTypes.ts"; +import {generateRuntimeSpec} from "./edgeql-js/generateRuntimeSpec.ts"; +import {generateScalars} from "./edgeql-js/generateScalars.ts"; +import {generateSetImpl} from "./edgeql-js/generateSetImpl.ts"; + +const {path, fs, readFileUtf8, exists, exit, walk} = adapter; + +// tslint:disable-next-line +export const configFileHeader = `// EdgeDB query builder. To update, run \`npx @edgedb/generate edgeql-js\``; + +export type GeneratorParams = { + dir: DirBuilder; + types: $.introspect.Types; + typesByName: Record; + casts: $.introspect.Casts; + scalars: $.introspect.ScalarTypes; + functions: $.introspect.FunctionTypes; + globals: $.introspect.Globals; + operators: $.introspect.OperatorTypes; +}; -const {path, fs, readFileUtf8, exists} = adapter; +export function exitWithError(message: string): never { + // tslint:disable-next-line + console.error(message); + exit(1); + throw new Error(); +} + +export type Target = "ts" | "esm" | "cjs" | "mts" | "deno"; +export type Version = { + major: number; + minor: number; +}; export async function generateQueryBuilder(params: { root: string | null; @@ -49,7 +90,178 @@ export async function generateQueryBuilder(params: { options.updateIgnoreFile = true; } - await generateQB({outputDir, connectionConfig, target: options.target!}); + // generate query builder + const target = options.target!; + let cxn: Client; + try { + cxn = createClient({ + ...connectionConfig, + concurrency: 5 + }); + } catch (e) { + exitWithError(`Failed to connect: ${(e as Error).message}`); + } + + const dir = new DirBuilder(); + + try { + // tslint:disable-next-line + console.log(`Introspecting database schema...`); + + const [types, scalars, casts, functions, operators, globals] = + await Promise.all([ + $.introspect.types(cxn), + $.introspect.scalars(cxn), + $.introspect.casts(cxn), + $.introspect.functions(cxn), + $.introspect.operators(cxn), + $.introspect.globals(cxn) + ]); + + const typesByName: Record = {}; + for (const type of types.values()) { + typesByName[type.name] = type; + + // skip "anytype" and "anytuple" + if (!type.name.includes("::")) continue; + } + + const generatorParams: GeneratorParams = { + dir, + types, + typesByName, + casts, + scalars, + functions, + globals, + operators + }; + generateRuntimeSpec(generatorParams); + generateCastMaps(generatorParams); + generateScalars(generatorParams); + generateObjectTypes(generatorParams); + generateFunctionTypes(generatorParams); + generateOperators(generatorParams); + generateSetImpl(generatorParams); + generateGlobals(generatorParams); + generateIndex(generatorParams); + + // generate module imports + + const importsFile = dir.getPath("imports"); + + importsFile.addExportStar("edgedb", {as: "edgedb"}); + importsFile.addExportFrom({spec: true}, "./__spec__", { + allowFileExt: true + }); + importsFile.addExportStar("./syntax", { + allowFileExt: true, + as: "syntax" + }); + importsFile.addExportStar("./castMaps", { + allowFileExt: true, + as: "castMaps" + }); + } finally { + await cxn.close(); + } + + const initialFiles = new Set(await walk(outputDir)); + const written = new Set(); + + // write syntax files + const syntaxOutDir = path.join(outputDir); + if (!(await exists(syntaxOutDir))) { + await fs.mkdir(syntaxOutDir); + } + + const syntaxFiles = syntax[target]; + if (!syntaxFiles) { + throw new Error(`Error: no syntax files found for target "${target}"`); + } + + for (const f of syntaxFiles) { + const outputPath = path.join(syntaxOutDir, f.path); + written.add(outputPath); + let oldContents = ""; + try { + oldContents = await readFileUtf8(outputPath); + } catch {} + if (oldContents !== f.content) { + await fs.writeFile(outputPath, f.content); + } + } + + if (target === "ts") { + await dir.write(outputDir, { + mode: "ts", + moduleKind: "esm", + fileExtension: ".ts", + moduleExtension: "", + written + }); + } else if (target === "mts") { + await dir.write(outputDir, { + mode: "ts", + moduleKind: "esm", + fileExtension: ".mts", + moduleExtension: ".mjs", + written + }); + } else if (target === "cjs") { + await dir.write(outputDir, { + mode: "js", + moduleKind: "cjs", + fileExtension: ".js", + moduleExtension: "", + written + }); + await dir.write(outputDir, { + mode: "dts", + moduleKind: "esm", + fileExtension: ".d.ts", + moduleExtension: "", + written + }); + } else if (target === "esm") { + await dir.write(outputDir, { + mode: "js", + moduleKind: "esm", + fileExtension: ".mjs", + moduleExtension: ".mjs", + written + }); + await dir.write(outputDir, { + mode: "dts", + moduleKind: "esm", + fileExtension: ".d.ts", + moduleExtension: "", + written + }); + } else if (target === "deno") { + await dir.write(outputDir, { + mode: "ts", + moduleKind: "esm", + fileExtension: ".ts", + moduleExtension: ".ts", + written + }); + } + + const configPath = path.join(outputDir, "config.json"); + await fs.writeFile( + configPath, + `${configFileHeader}\n${JSON.stringify({target})}\n` + ); + written.add(configPath); + + // delete all vestigial files + for (const file of initialFiles) { + if (written.has(file)) { + continue; + } + await fs.rm(file); + } console.log(`Writing files to ${prettyOutputDir}`); console.log(`Generation complete! 🤘`); @@ -78,13 +290,13 @@ project to exclude these files.` await promptBoolean( gitIgnoreFile === null ? `Checking the generated query builder into version control -is NOT RECOMMENDED. Would you like to create a .gitignore file to ignore +is not recommended. Would you like to create a .gitignore file to ignore the query builder directory? ` : `Checking the generated query builder into version control -is NOT RECOMMENDED. Would you like to update .gitignore to ignore +is not recommended. Would you like to update .gitignore to ignore the query builder directory? The following line will be added: - ${vcsLine}\n\n`, + ${vcsLine}\n\n`, true ) ) { diff --git a/_generate/edgeql-js/generateCastMaps.ts b/_generate/edgeql-js/generateCastMaps.ts index 74672ce..bdf35fe 100644 --- a/_generate/edgeql-js/generateCastMaps.ts +++ b/_generate/edgeql-js/generateCastMaps.ts @@ -1,5 +1,5 @@ import {CodeBuffer, dts, r, t, ts, all} from "../builders.ts"; -import type {GeneratorParams} from "../generate.ts"; +import type {GeneratorParams} from "../genutil.ts"; import { getRef, joinFrags, @@ -17,20 +17,12 @@ export const generateCastMaps = (params: GeneratorParams) => { const {implicitCastMap} = casts; const f = dir.getPath("castMaps"); - const edgedb = "edgedb"; - f.addImportStar("edgedb", edgedb); - f.addImport({$: true}, edgedb, {modes: ["ts", "dts"], typeOnly: true}); - - // if is Deno - // @ts-ignore - const isDeno = typeof Deno !== "undefined"; - if (isDeno) { - f.addImport( - {Buffer: true}, - "https://deno.land/std@0.114.0/node/buffer.ts", - {modes: ["ts", "dts"]} - ); - } + f.addImportStar("edgedb", "edgedb"); + f.addImportStar("$", "./reflection", { + modes: ["ts", "dts"], + allowFileExt: true, + typeOnly: true + }); const reverseTopo = Array.from(types) .reverse() // reverse topological order @@ -293,7 +285,7 @@ export const generateCastMaps = (params: GeneratorParams) => { !type.is_abstract && !type.enum_values && !type.material_id && - !type.castType && + !type.cast_type && (!scalarToLiteralMapping[type.name] || !scalarToLiteralMapping[type.name].literalKind) ); @@ -366,7 +358,7 @@ export const generateCastMaps = (params: GeneratorParams) => { f.writeln([t` [k in keyof T]: literalToTypeSet;`]); f.writeln([t`};\n\n`]); - f.addImportStar("literal", "./syntax/literal", {allowFileExt: true}); + f.addImportStar("literal", "./literal", {allowFileExt: true}); f.writeln([ dts`declare `, diff --git a/_generate/edgeql-js/generateFunctionTypes.ts b/_generate/edgeql-js/generateFunctionTypes.ts index a9cd3e3..9b4ddab 100644 --- a/_generate/edgeql-js/generateFunctionTypes.ts +++ b/_generate/edgeql-js/generateFunctionTypes.ts @@ -1,4 +1,4 @@ -import type {GeneratorParams} from "../generate.ts"; +import type {GeneratorParams} from "../genutil.ts"; import {frag, getRef, quote, splitName} from "../genutil.ts"; import { all, @@ -41,11 +41,11 @@ export const generateFunctionTypes = ({ true, (code, funcDef, args, namedArgs, returnType) => { // Name - code.writeln([t`${quote(funcDef.name)},`]); + // code.writeln([t`${quote(funcDef.name)},`]); // Args - code.writeln([t`${args}`]); + // code.writeln([t`${args}`]); // NamedArgs - code.writeln([t`${namedArgs}`]); + // code.writeln([t`${namedArgs}`]); // ReturnType code.writeln([t`${returnType}`]); }, @@ -73,8 +73,8 @@ export interface FuncopDef { kind?: string; description?: string; return_type: {id: string; name: string}; - return_typemod: $.introspect.Typemod; - params: $.introspect.Param[]; + return_typemod: $.introspect.FuncopTypemod; + params: $.introspect.FuncopParam[]; preserves_optionality?: boolean; } @@ -380,16 +380,14 @@ export function generateFuncopTypes( : "{}" },`, // return type - frag`$.TypeSet<${ - returnType.staticType - }, ${generateReturnCardinality( + frag`${returnType.staticType}, ${generateReturnCardinality( funcName, params, funcDef.return_typemod, hasNamedParams, anytypes, funcDef.preserves_optionality - )}>` + )}` ); }); @@ -490,7 +488,7 @@ export function generateFuncopDef(funcopDef: FuncopDefOverload) { export function generateReturnCardinality( name: string, params: GroupedParams, - returnTypemod: $.introspect.Typemod, + returnTypemod: $.introspect.FuncopTypemod, hasNamedParams: boolean, anytypes: AnytypeDef | null, preservesOptionality: boolean = false diff --git a/_generate/edgeql-js/generateGlobals.ts b/_generate/edgeql-js/generateGlobals.ts index d6fc320..2215662 100644 --- a/_generate/edgeql-js/generateGlobals.ts +++ b/_generate/edgeql-js/generateGlobals.ts @@ -1,4 +1,4 @@ -import type {GeneratorParams} from "../generate.ts"; +import type {GeneratorParams} from "../genutil.ts"; import {frag, getRef, splitName} from "../genutil.ts"; import {dts, r, t, ts} from "../builders.ts"; @@ -6,7 +6,7 @@ import {getStringRepresentation} from "./generateObjectTypes.ts"; import type {$} from "../genutil.ts"; export const generateGlobals = ({dir, globals, types}: GeneratorParams) => { - const globalsByMod: {[k: string]: $.introspect.GlobalType[]} = {}; + const globalsByMod: {[k: string]: $.introspect.Global[]} = {}; for (const [_id, g] of globals.entries()) { const {mod} = splitName(g.name); globalsByMod[mod] = globalsByMod[mod] || []; @@ -26,9 +26,9 @@ export const generateGlobals = ({dir, globals, types}: GeneratorParams) => { const targetTypeRep = getStringRepresentation(targetType, {types}); return [ t` ${name}: _.syntax.$expr_Global< - "${g.name}", + // "${g.name}", ${targetTypeRep.staticType}, - $.Cardinality.${g.real_cardinality} + $.Cardinality.${g.card} >`, t`,` ]; @@ -43,7 +43,7 @@ export const generateGlobals = ({dir, globals, types}: GeneratorParams) => { r` ${name}: _.syntax.makeGlobal( "${g.name}", $.makeType(_.spec, "${g.target_id}", _.syntax.literal), - $.Cardinality.${g.real_cardinality})`, + $.Cardinality.${g.card})`, ts` as any`, r`,` ]; diff --git a/_generate/edgeql-js/generateIndex.ts b/_generate/edgeql-js/generateIndex.ts new file mode 100644 index 0000000..8a161ef --- /dev/null +++ b/_generate/edgeql-js/generateIndex.ts @@ -0,0 +1,139 @@ +import {dts, r, t} from "../builders.ts"; +import type {GeneratorParams} from "../genutil.ts"; +import * as genutil from "../genutil.ts"; + +export function generateIndex(params: GeneratorParams) { + ///////////////////////// + // generate index file + ///////////////////////// + const {dir} = params; + const index = dir.getPath("index"); + // index.addExportStar(null, "./castMaps", true); + index.addExportStar("./external", { + allowFileExt: true + }); + // index.addExportStar("./types", { + // allowFileExt: true, + // modes: ["ts", "dts", "js"] + // }); + + index.addImportStar("$", "./reflection"); + index.addExportFrom({createClient: true}, "edgedb"); + index.addImportStar("$syntax", "./syntax", {allowFileExt: true}); + index.addImportStar("$op", "./operators", {allowFileExt: true}); + + const spreadModules = [ + { + name: "$op", + keys: ["op"] + }, + { + name: "$syntax", + keys: [ + "ASC", + "DESC", + "EMPTY_FIRST", + "EMPTY_LAST", + "alias", + "array", + "cast", + "detached", + "for", + "insert", + "is", + "literal", + "namedTuple", + "optional", + "select", + "set", + "tuple", + "with", + "withParams" + ] + }, + { + name: "_default", + module: dir.getModule("default") + }, + {name: "_std", module: dir.getModule("std")} + ]; + const excludedKeys = new Set(dir._modules.keys()); + + const spreadTypes: string[] = []; + for (let {name, keys, module} of spreadModules) { + if (module?.isEmpty()) { + continue; + } + keys = keys ?? module!.getDefaultExportKeys(); + const conflictingKeys = keys.filter(key => excludedKeys.has(key)); + let typeStr: string; + if (conflictingKeys.length) { + typeStr = `Omit`; + } else { + typeStr = `typeof ${name}`; + } + spreadTypes.push( + name === "$syntax" ? `$.util.OmitDollarPrefixed<${typeStr}>` : typeStr + ); + for (const key of keys) { + excludedKeys.add(key); + } + } + + index.nl(); + index.writeln([ + dts`declare `, + `const ExportDefault`, + t`: ${spreadTypes.reverse().join(" & \n ")} & {` + ]); + index.indented(() => { + for (const [moduleName, internalName] of dir._modules) { + if (dir.getModule(moduleName).isEmpty()) continue; + index.writeln([ + t`${genutil.quote(moduleName)}: typeof _${internalName};` + ]); + } + }); + + index.writeln([t`}`, r` = {`]); + index.indented(() => { + for (const {name, module} of [...spreadModules].reverse()) { + if (module?.isEmpty()) { + continue; + } + index.writeln([ + r`...${ + name === "$syntax" ? `$.util.omitDollarPrefixed($syntax)` : name + },` + ]); + } + + for (const [moduleName, internalName] of dir._modules) { + if (dir.getModule(moduleName).isEmpty()) { + continue; + } + index.addImportDefault(`_${internalName}`, `./modules/${internalName}`, { + allowFileExt: true + }); + + index.writeln([r`${genutil.quote(moduleName)}: _${internalName},`]); + } + }); + index.writeln([r`};`]); + index.addExportDefault("ExportDefault"); + + // re-export some reflection types + index.writeln([r`const Cardinality = $.Cardinality;`]); + index.writeln([dts`declare `, t`type Cardinality = $.Cardinality;`]); + index.addExport("Cardinality"); + index.writeln([ + t`export `, + dts`declare `, + t`type Set< + Type extends $.BaseType, + Card extends $.Cardinality = $.Cardinality.Many +> = $.TypeSet;` + ]); +} diff --git a/_generate/edgeql-js/generateInterfaces.ts b/_generate/edgeql-js/generateInterfaces.ts new file mode 100644 index 0000000..890536f --- /dev/null +++ b/_generate/edgeql-js/generateInterfaces.ts @@ -0,0 +1,202 @@ +import {CodeBuffer, js, t} from "../builders.ts"; +import type {GeneratorParams} from "../genutil.ts"; +import {$} from "../genutil.ts"; +import {makePlainIdent, quote, splitName, toTSScalarType} from "../genutil.ts"; + +export type GenerateInterfacesParams = Pick; + +export const generateInterfaces = (params: GenerateInterfacesParams) => { + const {dir, types} = params; + + const plainTypesCode = dir.getPath("interfaces"); + plainTypesCode.addImportStar("edgedb", "edgedb", { + typeOnly: true + }); + const plainTypeModules = new Map< + string, + {internalName: string; buf: CodeBuffer; types: Map} + >(); + + const getPlainTypeModule = ( + typeName: string + ): { + tMod: string; + tName: string; + module: { + internalName: string; + buf: CodeBuffer; + types: Map; + }; + } => { + const {mod: tMod, name: tName} = splitName(typeName); + if (!plainTypeModules.has(tMod)) { + plainTypeModules.set(tMod, { + internalName: makePlainIdent(tMod), + buf: new CodeBuffer(), + types: new Map() + }); + } + return {tMod, tName, module: plainTypeModules.get(tMod)!}; + }; + + const _getTypeName = + (mod: string) => + (typeName: string, withModule: boolean = false): string => { + const {tMod, tName, module} = getPlainTypeModule(typeName); + return ( + ((mod !== tMod || withModule) && tMod !== "default" + ? `${module.internalName}.` + : "") + `${makePlainIdent(tName)}` + ); + }; + + for (const type of types.values()) { + if (type.kind === "scalar" && type.enum_values?.length) { + // generate plain enum type + const {mod: enumMod, name: enumName} = splitName(type.name); + const getEnumTypeName = _getTypeName(enumMod); + + const {module} = getPlainTypeModule(type.name); + module.types.set(enumName, getEnumTypeName(type.name, true)); + module.buf.writeln( + [ + t`export type ${getEnumTypeName(type.name)} = ${type.enum_values + .map(val => quote(val)) + .join(" | ")};` + ] + // ...type.enum_values.map(val => [t`${quote(val)}`]).join(" | "), + // [t`}`] + ); + + // if (enumMod === "default") { + // module.buf.writeln( + // [js`const ${getEnumTypeName(type.name)} = {`], + // ...type.enum_values.map(val => [ + // js` ${makePlainIdent(val)}: ${quote(val)},` + // ]), + // [js`}`] + // ); + // plainTypesCode.addExport(getEnumTypeName(type.name), { + // modes: ["js"] + // }); + // } else { + // module.buf.writeln( + // [js`"${getEnumTypeName(type.name)}": {`], + // ...type.enum_values.map(val => [ + // js` ${makePlainIdent(val)}: ${quote(val)},` + // ]), + // [js`},`] + // ); + // } + } + if (type.kind !== "object") { + continue; + } + if ( + (type.union_of && type.union_of.length) || + (type.intersection_of && type.intersection_of.length) + ) { + continue; + } + + const {mod, name} = splitName(type.name); + const body = dir.getModule(mod); + body.registerRef(type.name, type.id); + + ///////// + // generate plain type + ///////// + + const getTypeName = _getTypeName(mod); + + const getTSType = (pointer: $.introspect.Pointer): string => { + const targetType = types.get(pointer.target_id); + if (pointer.kind === "link") { + return getTypeName(targetType.name); + } else { + return toTSScalarType( + targetType as $.introspect.PrimitiveType, + types, + { + getEnumRef: enumType => getTypeName(enumType.name), + edgedbDatatypePrefix: "" + } + ).join(""); + } + }; + + const {module: plainTypeModule} = getPlainTypeModule(type.name); + const pointers = type.pointers.filter(ptr => ptr.name !== "__type__"); + plainTypeModule.types.set(name, getTypeName(type.name, true)); + plainTypeModule.buf.writeln([ + t`export interface ${getTypeName(type.name)}${ + type.bases.length + ? ` extends ${type.bases + .map(({id}) => { + const baseType = types.get(id); + return getTypeName(baseType.name); + }) + .join(", ")}` + : "" + } ${ + pointers.length + ? `{\n${pointers + .map(pointer => { + const isOptional = pointer.card === $.Cardinality.AtMostOne; + return ` ${quote(pointer.name)}${ + isOptional ? "?" : "" + }: ${getTSType(pointer)}${ + pointer.card === $.Cardinality.Many || + pointer.card === $.Cardinality.AtLeastOne + ? "[]" + : "" + }${isOptional ? " | null" : ""};`; + }) + .join("\n")}\n}` + : "{}" + }\n` + ]); + } + + // plain types export + const plainTypesExportBuf = new CodeBuffer(); + for (const [moduleName, module] of plainTypeModules) { + if (moduleName === "default") { + plainTypesCode.writeBuf(module.buf); + } else { + plainTypesCode.writeln([t`export namespace ${module.internalName} {`]); + plainTypesCode.writeln([js`const ${module.internalName} = {`]); + plainTypesCode.indented(() => plainTypesCode.writeBuf(module.buf)); + plainTypesCode.writeln([t`}`]); + plainTypesCode.writeln([js`}`]); + plainTypesCode.addExport(module.internalName, {modes: ["js"]}); + } + + plainTypesExportBuf.writeln([ + t` ${quote(moduleName)}: {\n${[...module.types.entries()] + .map(([name, typeName]) => ` ${quote(name)}: ${typeName};`) + .join("\n")}\n };` + ]); + } + plainTypesCode.writeln([t`export interface types {`]); + plainTypesCode.writeBuf(plainTypesExportBuf); + plainTypesCode.writeln([t`}`]); + + plainTypesCode.writeln([ + t` + +export namespace helper { + export type propertyKeys = { + [k in keyof T]: NonNullable extends object ? never : k; + }[keyof T]; + + export type linkKeys = { + [k in keyof T]: NonNullable extends object ? k : never; + }[keyof T]; + + export type Props = Pick>; + export type Links = Pick>; +} +` + ]); +}; diff --git a/_generate/edgeql-js/generateObjectTypes.ts b/_generate/edgeql-js/generateObjectTypes.ts index 84f8159..741864b 100644 --- a/_generate/edgeql-js/generateObjectTypes.ts +++ b/_generate/edgeql-js/generateObjectTypes.ts @@ -1,15 +1,14 @@ -import {CodeBuffer, CodeFragment, dts, js, r, t, ts} from "../builders.ts"; -// import {Cardinality} from "edgedb/dist/reflection"; -import type {GeneratorParams} from "../generate.ts"; -import {$} from "../genutil.ts"; +import {CodeFragment, dts, r, t, ts} from "../builders.ts"; +import type {GeneratorParams} from "../genutil.ts"; +import type {$} from "../genutil.ts"; import { frag, getRef, joinFrags, - makePlainIdent, + // makePlainIdent, quote, - splitName, - toTSScalarType + splitName + // toTSScalarType } from "../genutil.ts"; const singletonObjectTypes = new Set(["std::FreeObject"]); @@ -144,87 +143,86 @@ export const getStringRepresentation: ( export const generateObjectTypes = (params: GeneratorParams) => { const {dir, types} = params; - const plainTypesCode = dir.getPath("types"); - const edgedb = "edgedb"; - plainTypesCode.addImportStar("edgedb", edgedb, { - typeOnly: true - }); - const plainTypeModules = new Map< - string, - {internalName: string; buf: CodeBuffer; types: Map} - >(); - - const getPlainTypeModule = ( - typeName: string - ): { - tMod: string; - tName: string; - module: { - internalName: string; - buf: CodeBuffer; - types: Map; - }; - } => { - const {mod: tMod, name: tName} = splitName(typeName); - if (!plainTypeModules.has(tMod)) { - plainTypeModules.set(tMod, { - internalName: makePlainIdent(tMod), - buf: new CodeBuffer(), - types: new Map() - }); - } - return {tMod, tName, module: plainTypeModules.get(tMod)!}; - }; - - const _getTypeName = - (mod: string) => - (typeName: string, withModule: boolean = false): string => { - const {tMod, tName, module} = getPlainTypeModule(typeName); - return ( - ((mod !== tMod || withModule) && tMod !== "default" - ? `${module.internalName}.` - : "") + `${makePlainIdent(tName)}` - ); - }; + // const plainTypesCode = dir.getPath("types"); + // plainTypesCode.addImportStar("edgedb", "edgedb", { + // typeOnly: true + // }); + // const plainTypeModules = new Map< + // string, + // {internalName: string; buf: CodeBuffer; types: Map} + // >(); + + // const getPlainTypeModule = ( + // typeName: string + // ): { + // tMod: string; + // tName: string; + // module: { + // internalName: string; + // buf: CodeBuffer; + // types: Map; + // }; + // } => { + // const {mod: tMod, name: tName} = splitName(typeName); + // if (!plainTypeModules.has(tMod)) { + // plainTypeModules.set(tMod, { + // internalName: makePlainIdent(tMod), + // buf: new CodeBuffer(), + // types: new Map() + // }); + // } + // return {tMod, tName, module: plainTypeModules.get(tMod)!}; + // }; + + // const _getTypeName = + // (mod: string) => + // (typeName: string, withModule: boolean = false): string => { + // const {tMod, tName, module} = getPlainTypeModule(typeName); + // return ( + // ((mod !== tMod || withModule) && tMod !== "default" + // ? `${module.internalName}.` + // : "") + `${makePlainIdent(tName)}` + // ); + // }; for (const type of types.values()) { if (type.kind !== "object") { - if (type.kind === "scalar" && type.enum_values?.length) { - // generate plain enum type - const {mod: enumMod, name: enumName} = splitName(type.name); - const getEnumTypeName = _getTypeName(enumMod); - - const {module} = getPlainTypeModule(type.name); - module.types.set(enumName, getEnumTypeName(type.name, true)); - module.buf.writeln( - [t`export enum ${getEnumTypeName(type.name)} {`], - ...type.enum_values.map(val => [ - t` ${makePlainIdent(val)} = ${quote(val)},` - ]), - [t`}`] - ); - - if (enumMod === "default") { - module.buf.writeln( - [js`const ${getEnumTypeName(type.name)} = {`], - ...type.enum_values.map(val => [ - js` ${makePlainIdent(val)}: ${quote(val)},` - ]), - [js`}`] - ); - plainTypesCode.addExport(getEnumTypeName(type.name), { - modes: ["js"] - }); - } else { - module.buf.writeln( - [js`"${getEnumTypeName(type.name)}": {`], - ...type.enum_values.map(val => [ - js` ${makePlainIdent(val)}: ${quote(val)},` - ]), - [js`},`] - ); - } - } + // if (type.kind === "scalar" && type.enum_values?.length) { + // // generate plain enum type + // const {mod: enumMod, name: enumName} = splitName(type.name); + // const getEnumTypeName = _getTypeName(enumMod); + + // const {module} = getPlainTypeModule(type.name); + // module.types.set(enumName, getEnumTypeName(type.name, true)); + // module.buf.writeln( + // [t`export enum ${getEnumTypeName(type.name)} {`], + // ...type.enum_values.map(val => [ + // t` ${makePlainIdent(val)} = ${quote(val)},` + // ]), + // [t`}`] + // ); + + // if (enumMod === "default") { + // module.buf.writeln( + // [js`const ${getEnumTypeName(type.name)} = {`], + // ...type.enum_values.map(val => [ + // js` ${makePlainIdent(val)}: ${quote(val)},` + // ]), + // [js`}`] + // ); + // plainTypesCode.addExport(getEnumTypeName(type.name), { + // modes: ["js"] + // }); + // } else { + // module.buf.writeln( + // [js`"${getEnumTypeName(type.name)}": {`], + // ...type.enum_values.map(val => [ + // js` ${makePlainIdent(val)}: ${quote(val)},` + // ]), + // [js`},`] + // ); + // } + // } continue; } if ( @@ -246,56 +244,55 @@ export const generateObjectTypes = (params: GeneratorParams) => { // generate plain type ///////// - const getTypeName = _getTypeName(mod); - - const getTSType = (pointer: $.introspect.Pointer): string => { - const targetType = types.get(pointer.target_id); - if (pointer.kind === "link") { - return getTypeName(targetType.name); - } else { - return toTSScalarType( - targetType as $.introspect.PrimitiveType, - types, - { - getEnumRef: enumType => getTypeName(enumType.name), - edgedbDatatypePrefix: "" - } - ).join(""); - } - }; - - const {module: plainTypeModule} = getPlainTypeModule(type.name); - - plainTypeModule.types.set(name, getTypeName(type.name, true)); - plainTypeModule.buf.writeln([ - t`export interface ${getTypeName(type.name)}${ - type.bases.length - ? ` extends ${type.bases - .map(({id}) => { - const baseType = types.get(id); - return getTypeName(baseType.name); - }) - .join(", ")}` - : "" - } ${ - type.pointers.length - ? `{\n${type.pointers - .map(pointer => { - const isOptional = - pointer.real_cardinality === $.Cardinality.AtMostOne; - return ` ${quote(pointer.name)}${ - isOptional ? "?" : "" - }: ${getTSType(pointer)}${ - pointer.real_cardinality === $.Cardinality.Many || - pointer.real_cardinality === $.Cardinality.AtLeastOne - ? "[]" - : "" - }${isOptional ? " | null" : ""};`; - }) - .join("\n")}\n}` - : "{}" - }\n` - ]); + // const getTypeName = _getTypeName(mod); + + // const getTSType = (pointer: $.introspect.Pointer): string => { + // const targetType = types.get(pointer.target_id); + // if (pointer.kind === "link") { + // return getTypeName(targetType.name); + // } else { + // return toTSScalarType( + // targetType as $.introspect.PrimitiveType, + // types, + // { + // getEnumRef: enumType => getTypeName(enumType.name), + // edgedbDatatypePrefix: "" + // } + // ).join(""); + // } + // }; + + // const {module: plainTypeModule} = getPlainTypeModule(type.name); + + // plainTypeModule.types.set(name, getTypeName(type.name, true)); + // plainTypeModule.buf.writeln([ + // t`export interface ${getTypeName(type.name)}${ + // type.bases.length + // ? ` extends ${type.bases + // .map(({id}) => { + // const baseType = types.get(id); + // return getTypeName(baseType.name); + // }) + // .join(", ")}` + // : "" + // } ${ + // type.pointers.length + // ? `{\n${type.pointers + // .map(pointer => { + // const isOptional = pointer.card === $.Cardinality.AtMostOne; + // return ` ${quote(pointer.name)}${ + // isOptional ? "?" : "" + // }: ${getTSType(pointer)}${ + // pointer.card === $.Cardinality.Many || + // pointer.card === $.Cardinality.AtLeastOne + // ? "[]" + // : "" + // }${isOptional ? " | null" : ""};`; + // }) + // .join("\n")}\n}` + // : "{}" + // }\n` + // ]); ///////// // generate interface @@ -317,7 +314,7 @@ export const generateObjectTypes = (params: GeneratorParams) => { const ptrToLine: ( ptr: $.introspect.Pointer | $.introspect.Backlink ) => Line = ptr => { - const card = `$.Cardinality.${ptr.real_cardinality}`; + const card = `$.Cardinality.${ptr.card}`; const target = types.get(ptr.target_id); const {staticType, runtimeType} = getStringRepresentation(target, { types @@ -344,7 +341,7 @@ export const generateObjectTypes = (params: GeneratorParams) => { // const uniqueStubs = [...new Set(type.backlinks.map((bl) => bl.stub))]; // const stubLines = uniqueStubs.map((stub): $.introspect.Pointer => { // return { - // real_cardinality: Cardinality.Many, + // card: Cardinality.Many, // kind: "link", // name: `<${stub}`, // target_id: BaseObject.id, @@ -426,9 +423,35 @@ export const generateObjectTypes = (params: GeneratorParams) => { // instantiate ObjectType subtype from shape body.writeln([ dts`declare `, - t`type ${ref} = $.ObjectType<${quote(type.name)}, ${ref}λShape, null>;` + t`type ${ref} = $.ObjectType<${quote(type.name)}, ${ref}λShape, null, [` ]); + const bases = type.bases + .map(b => types.get(b.id)) + .map(b => getRef(b.name)); + body.indented(() => { + for (const b of bases) { + body.writeln([t`...${b}['__exclusives__'],`]); + } + }); + + // const ref = getRef(type.name); + for (const ex of type.exclusives) { + body.writeln([ + t` {`, + ...Object.keys(ex).map(key => { + const target = types.get(ex[key].target_id); + const {staticType} = getStringRepresentation(target, {types}); + const card = `$.Cardinality.${ex[key].card}`; + return t`${key}: {__element__: ${staticType}, __cardinality__: ${card}},`; + }), + t`},` + ]); + // body.writeln([t`\n {${lines.join(", ")}}`]); + } + + body.writeln([t`]>;`]); + if (type.name === "std::Object") { body.writeln([t`export `, dts`declare `, t`type $Object = ${ref}`]); } @@ -456,8 +479,8 @@ export const generateObjectTypes = (params: GeneratorParams) => { dts`declare `, ...frag`const ${literal}`, // tslint:disable-next-line - t`: $.$expr_PathNode<$.TypeSet<${ref}, $.Cardinality.${typeCard}>, null, true> `, - r`= _.syntax.$PathNode($.$toSet(${ref}, $.Cardinality.${typeCard}), null, true);` + t`: $.$expr_PathNode<$.TypeSet<${ref}, $.Cardinality.${typeCard}>, null> `, + r`= _.syntax.$PathNode($.$toSet(${ref}, $.Cardinality.${typeCard}), null);` ]); body.nl(); @@ -466,26 +489,26 @@ export const generateObjectTypes = (params: GeneratorParams) => { } // plain types export - const plainTypesExportBuf = new CodeBuffer(); - for (const [moduleName, module] of plainTypeModules) { - if (moduleName === "default") { - plainTypesCode.writeBuf(module.buf); - } else { - plainTypesCode.writeln([t`export namespace ${module.internalName} {`]); - plainTypesCode.writeln([js`const ${module.internalName} = {`]); - plainTypesCode.indented(() => plainTypesCode.writeBuf(module.buf)); - plainTypesCode.writeln([t`}`]); - plainTypesCode.writeln([js`}`]); - plainTypesCode.addExport(module.internalName, {modes: ["js"]}); - } - - plainTypesExportBuf.writeln([ - t` ${quote(moduleName)}: {\n${[...module.types.entries()] - .map(([name, typeName]) => ` ${quote(name)}: ${typeName};`) - .join("\n")}\n };` - ]); - } - plainTypesCode.writeln([t`export interface types {`]); - plainTypesCode.writeBuf(plainTypesExportBuf); - plainTypesCode.writeln([t`}`]); + // const plainTypesExportBuf = new CodeBuffer(); + // for (const [moduleName, module] of plainTypeModules) { + // if (moduleName === "default") { + // plainTypesCode.writeBuf(module.buf); + // } else { + // plainTypesCode.writeln([t`export namespace ${module.internalName} {`]); + // plainTypesCode.writeln([js`const ${module.internalName} = {`]); + // plainTypesCode.indented(() => plainTypesCode.writeBuf(module.buf)); + // plainTypesCode.writeln([t`}`]); + // plainTypesCode.writeln([js`}`]); + // plainTypesCode.addExport(module.internalName, {modes: ["js"]}); + // } + + // plainTypesExportBuf.writeln([ + // t` ${quote(moduleName)}: {\n${[...module.types.entries()] + // .map(([name, typeName]) => ` ${quote(name)}: ${typeName};`) + // .join("\n")}\n };` + // ]); + // } + // plainTypesCode.writeln([t`export interface types {`]); + // plainTypesCode.writeBuf(plainTypesExportBuf); + // plainTypesCode.writeln([t`}`]); }; diff --git a/_generate/edgeql-js/generateOperatorTypes.ts b/_generate/edgeql-js/generateOperatorTypes.ts index 8257085..e43b7ff 100644 --- a/_generate/edgeql-js/generateOperatorTypes.ts +++ b/_generate/edgeql-js/generateOperatorTypes.ts @@ -1,5 +1,5 @@ import {CodeBuffer, dts, r, t, ts} from "../builders.ts"; -import type {GeneratorParams} from "../generate.ts"; +import type {GeneratorParams} from "../genutil.ts"; import {frag, quote, splitName} from "../genutil.ts"; import { allowsLiterals, @@ -33,11 +33,11 @@ export function generateOperatorFunctions({ false, (code, opDef, args, namedArgs, returnType) => { // Name - code.writeln([t`${quote(opDef.originalName)},`]); + // code.writeln([t`${quote(opDef.originalName)},`]); // OperatorKind - code.writeln([t`$.OperatorKind.${opDef.operator_kind},`]); + // code.writeln([t`$.OperatorKind.${opDef.operator_kind},`]); // Args - code.writeln([t`${args}`]); + // code.writeln([t`${args}`]); // ReturnType code.writeln([t`${returnType}`]); }, @@ -64,9 +64,8 @@ export function generateOperators({ const typeSpecificities = getTypesSpecificity(types, casts); const implicitCastableRootTypes = getImplicitCastableRootTypes(casts); const code = dir.getPath("operators"); - const edgedb = "edgedb"; - code.addImport({$: true}, edgedb); + code.addImportStar("$", "./reflection", {allowFileExt: true}); code.addImportStar("_", "./imports", {allowFileExt: true}); const overloadsBuf = new CodeBuffer(); @@ -146,7 +145,7 @@ export function generateOperators({ } } - let hasLiterals = false; + // let hasLiterals = false; overloadsBuf.indented(() => { for (const param of params.positional) { const anytype = getParamAnytype(param.typeName, param.type); @@ -161,7 +160,7 @@ export function generateOperators({ if (allowsLiterals(param.type, anytypes)) { type = frag`_.castMaps.orScalarLiteral<${type}>`; - hasLiterals = true; + // hasLiterals = true; } overloadsBuf.writeln([t`${param.typeName} extends ${type},`]); @@ -200,9 +199,9 @@ export function generateOperators({ } }); - const paramTypeNames = params.positional - .map(param => param.typeName) - .join(", "); + // const paramTypeNames = params.positional + // .map(param => param.typeName) + // .join(", "); const returnAnytype = anytypes ? anytypes.kind === "castable" @@ -229,23 +228,23 @@ export function generateOperators({ overloadsBuf.writeln([t`): $.$expr_Operator<`]); overloadsBuf.indented(() => { - overloadsBuf.writeln([t`${quote(opSymbol)},`]); - overloadsBuf.writeln([t`$.OperatorKind.${opDef.operator_kind},`]); + // overloadsBuf.writeln([t`${quote(opSymbol)},`]); + // overloadsBuf.writeln([t`$.OperatorKind.${opDef.operator_kind},`]); + // overloadsBuf.writeln([ + // t`${ + // hasLiterals + // ? `_.castMaps.mapLiteralToTypeSet<[${paramTypeNames}]>` + // : `[${paramTypeNames}]` + // },` + // ]); overloadsBuf.writeln([ - t`${ - hasLiterals - ? `_.castMaps.mapLiteralToTypeSet<[${paramTypeNames}]>` - : `[${paramTypeNames}]` - },` - ]); - overloadsBuf.writeln([ - t`$.TypeSet<${returnType.staticType}, ${generateReturnCardinality( + t`${returnType.staticType}, ${generateReturnCardinality( opName, params, opDef.return_typemod, false, anytypes - )}>` + )}` ]); }); overloadsBuf.writeln([t`>;`]); diff --git a/_generate/edgeql-js/generateRuntimeSpec.ts b/_generate/edgeql-js/generateRuntimeSpec.ts index ccaaa41..a51d617 100644 --- a/_generate/edgeql-js/generateRuntimeSpec.ts +++ b/_generate/edgeql-js/generateRuntimeSpec.ts @@ -1,18 +1,18 @@ import {dts, t, r, ts} from "../builders.ts"; -import type {GeneratorParams} from "../generate.ts"; +import type {GeneratorParams} from "../genutil.ts"; export const generateRuntimeSpec = (params: GeneratorParams) => { const {dir, types} = params; const spec = dir.getPath("__spec__"); - const edgedb = "edgedb"; - spec.addImport({$: true}, edgedb); + + spec.addImportStar("$", "./reflection", {allowFileExt: true}); spec.writeln([ dts`declare `, `const spec`, t`: $.introspect.Types`, r` = new $.StrictMap()`, - `;`, + `;` ]); spec.nl(); @@ -20,7 +20,7 @@ export const generateRuntimeSpec = (params: GeneratorParams) => { spec.writeln([ r`spec.set("${type.id}", ${JSON.stringify(type)}`, ts` as any`, - r`);`, + r`);` ]); } diff --git a/_generate/edgeql-js/generateScalars.ts b/_generate/edgeql-js/generateScalars.ts index 1993c3e..4bbf861 100644 --- a/_generate/edgeql-js/generateScalars.ts +++ b/_generate/edgeql-js/generateScalars.ts @@ -9,7 +9,7 @@ import { scalarToLiteralMapping } from "../genutil.ts"; import {dts, r, t, ts} from "../builders.ts"; -import type {GeneratorParams} from "../generate.ts"; +import type {GeneratorParams} from "../genutil.ts"; import {$} from "../genutil.ts"; export const generateScalars = (params: GeneratorParams) => { @@ -121,8 +121,8 @@ export const generateScalars = (params: GeneratorParams) => { // const extraTypes = scalarToLiteralMapping[type.name]?.extraTypes; // const extraTypesUnion = extraTypes ? `, ${extraTypes.join(" | ")}` : ""; - if (type.castType) { - const mapped = types.get(type.castType); + if (type.cast_type) { + const mapped = types.get(type.cast_type); const mappedRef = getRef(mapped.name); const extraTypes = ( diff --git a/_generate/edgeql-js/generateSetImpl.ts b/_generate/edgeql-js/generateSetImpl.ts index 147c47a..ce944e8 100644 --- a/_generate/edgeql-js/generateSetImpl.ts +++ b/_generate/edgeql-js/generateSetImpl.ts @@ -1,22 +1,15 @@ import {dts, r, t, ts} from "../builders.ts"; -import type {GeneratorParams} from "../generate.ts"; +import type {GeneratorParams} from "../genutil.ts"; import {getImplicitCastableRootTypes} from "../funcoputil.ts"; import {getStringRepresentation} from "./generateObjectTypes.ts"; export const generateSetImpl = ({dir, types, casts}: GeneratorParams) => { - const code = dir.getPath("syntax/setImpl"); + const code = dir.getPath("setImpl"); const implicitCastableRootTypes = getImplicitCastableRootTypes(casts); - const edgedb = "edgedb"; - code.addImport( - { - $: true - }, - edgedb, - {allowFileExt: false} - ); - code.addImportStar("castMaps", "../castMaps", { + code.addImportStar("$", "./reflection", {allowFileExt: true}); + code.addImportStar("castMaps", "./castMaps", { allowFileExt: true, modes: ["ts", "js", "dts"] }); diff --git a/_generate/funcoputil.ts b/_generate/funcoputil.ts index d1f8e6c..18131c0 100644 --- a/_generate/funcoputil.ts +++ b/_generate/funcoputil.ts @@ -150,7 +150,10 @@ export function expandFuncopAnytypeOverloads( }); } -function groupParams(params: $.introspect.Param[], types: $.introspect.Types) { +function groupParams( + params: $.introspect.FuncopParam[], + types: $.introspect.Types +) { return { positional: params .filter( @@ -231,8 +234,8 @@ export function sortFuncopOverloads( return [...overloads].sort((a, b) => { let i = 0; while (true) { - let paramA: $.introspect.Param | null = a.params[i] ?? null; - let paramB: $.introspect.Param | null = b.params[i] ?? null; + let paramA: $.introspect.FuncopParam | null = a.params[i] ?? null; + let paramB: $.introspect.FuncopParam | null = b.params[i] ?? null; if (paramA?.kind === "NamedOnlyParam") paramA = null; if (paramB?.kind === "NamedOnlyParam") paramB = null; diff --git a/_generate/generate.ts b/_generate/generate.ts deleted file mode 100644 index 3af9cfd..0000000 --- a/_generate/generate.ts +++ /dev/null @@ -1,447 +0,0 @@ -import {DirBuilder, dts, r, t} from "./builders.ts"; -import {createClient, Client, _edgedbJsVersion, adapter, $} from "../mod.ts"; - -import type {ConnectConfig} from "../_src/conUtils.ts"; - -import * as genutil from "./genutil.ts"; - -import {generateCastMaps} from "./edgeql-js/generateCastMaps.ts"; -import {generateScalars} from "./edgeql-js/generateScalars.ts"; -import {generateObjectTypes} from "./edgeql-js/generateObjectTypes.ts"; -import {generateRuntimeSpec} from "./edgeql-js/generateRuntimeSpec.ts"; -import {generateFunctionTypes} from "./edgeql-js/generateFunctionTypes.ts"; -import {generateOperators} from "./edgeql-js/generateOperatorTypes.ts"; -import {generateGlobals} from "./edgeql-js/generateGlobals.ts"; -import {generateSetImpl} from "./edgeql-js/generateSetImpl.ts"; - -const {fs, path, exists, readFileUtf8, exit, walk} = adapter; -const DEBUG = false; - -export const configFileHeader = `// EdgeDB query builder. To update, run \`npx edgeql-js\``; - -export type GeneratorParams = { - dir: DirBuilder; - types: $.introspect.Types; - typesByName: Record; - casts: $.introspect.Casts; - scalars: $.introspect.ScalarTypes; - functions: $.introspect.FunctionTypes; - globals: $.introspect.Globals; - operators: $.introspect.OperatorTypes; -}; - -export function exitWithError(message: string): never { - // tslint:disable-next-line - console.error(message); - exit(1); - throw new Error(); -} - -export type Target = "ts" | "esm" | "cjs" | "mts" | "deno"; -export type Version = { - major: number; - minor: number; -}; - -export async function generateQB(params: { - outputDir: string; - connectionConfig: ConnectConfig; - target: Target; -}): Promise { - const {outputDir, connectionConfig, target} = params; - // tslint:disable-next-line - // console.log(`Connecting to EdgeDB instance...`); - let cxn: Client; - try { - cxn = createClient({ - ...connectionConfig, - concurrency: 5 - }); - } catch (e) { - return exitWithError(`Failed to connect: ${(e as Error).message}`); - } - - const dir = new DirBuilder(); - - try { - // tslint:disable-next-line - console.log(`Introspecting database schema...`); - const version = await cxn.queryRequiredSingle( - `select sys::get_version();` - ); - const [types, scalars, casts, functions, operators, globals] = - await Promise.all([ - $.introspect.getTypes(cxn, {debug: DEBUG, version}), - $.introspect.getScalars(cxn, {version}), - $.introspect.getCasts(cxn, {debug: DEBUG, version}), - $.introspect.getFunctions(cxn, {version}), - $.introspect.getOperators(cxn, {version}), - $.introspect.getGlobals(cxn, {version}) - ]); - - const typesByName: Record = {}; - for (const type of types.values()) { - typesByName[type.name] = type; - - // skip "anytype" and "anytuple" - if (!type.name.includes("::")) continue; - } - - const generatorParams: GeneratorParams = { - dir, - types, - typesByName, - casts, - scalars, - functions, - globals, - operators - }; - generateRuntimeSpec(generatorParams); - generateCastMaps(generatorParams); - generateScalars(generatorParams); - generateObjectTypes(generatorParams); - generateFunctionTypes(generatorParams); - generateOperators(generatorParams); - generateSetImpl(generatorParams); - generateGlobals(generatorParams); - - // generate module imports - - const importsFile = dir.getPath("imports"); - const edgedb = "edgedb"; - - importsFile.addExportStar(edgedb, {as: "edgedb"}); - importsFile.addExportFrom({spec: true}, "./__spec__", { - allowFileExt: true - }); - importsFile.addExportStar("./syntax/syntax", { - allowFileExt: true, - as: "syntax" - }); - importsFile.addExportStar("./castMaps", { - allowFileExt: true, - as: "castMaps" - }); - - ///////////////////////// - // generate index file - ///////////////////////// - - const index = dir.getPath("index"); - // index.addExportStar(null, "./castMaps", true); - index.addExportStar("./syntax/external", { - allowFileExt: true - }); - index.addExportStar("./types", { - allowFileExt: true, - modes: ["ts", "dts", "js"] - }); - - index.addImport({$: true, _edgedbJsVersion: true}, edgedb); - index.addExportFrom({createClient: true}, edgedb); - index.addImportStar("$syntax", "./syntax/syntax", {allowFileExt: true}); - index.addImportStar("$op", "./operators", {allowFileExt: true}); - - index.writeln([ - r`\nif (_edgedbJsVersion !== "${_edgedbJsVersion}") { - throw new Error( - \`The query builder was generated by a different version of edgedb-js (v${_edgedbJsVersion})\` + - \` than the one currently installed (v\${_edgedbJsVersion}).\\n\` + - \`Run 'npx edgeql-js' to re-generate a compatible version.\\n\` - ); -}` - ]); - - const spreadModules = [ - { - name: "$op", - keys: ["op"] - }, - { - name: "$syntax", - keys: [ - "ASC", - "DESC", - "EMPTY_FIRST", - "EMPTY_LAST", - "alias", - "array", - "cast", - "detached", - "for", - "insert", - "is", - "literal", - "namedTuple", - "optional", - "select", - "set", - "tuple", - "with", - "withParams" - ] - }, - { - name: "_default", - module: dir.getModule("default") - }, - {name: "_std", module: dir.getModule("std")} - ]; - const excludedKeys = new Set(dir._modules.keys()); - - const spreadTypes: string[] = []; - for (let {name, keys, module} of spreadModules) { - if (module?.isEmpty()) { - continue; - } - keys = keys ?? module!.getDefaultExportKeys(); - const conflictingKeys = keys.filter(key => excludedKeys.has(key)); - let typeStr: string; - if (conflictingKeys.length) { - typeStr = `Omit`; - } else { - typeStr = `typeof ${name}`; - } - spreadTypes.push( - name === "$syntax" ? `$.util.OmitDollarPrefixed<${typeStr}>` : typeStr - ); - for (const key of keys) { - excludedKeys.add(key); - } - } - - index.nl(); - index.writeln([ - dts`declare `, - `const ExportDefault`, - t`: ${spreadTypes.reverse().join(" & \n ")} & {` - ]); - index.indented(() => { - for (const [moduleName, internalName] of dir._modules) { - if (dir.getModule(moduleName).isEmpty()) continue; - index.writeln([ - t`${genutil.quote(moduleName)}: typeof _${internalName};` - ]); - } - }); - - index.writeln([t`}`, r` = {`]); - index.indented(() => { - for (const {name, module} of [...spreadModules].reverse()) { - if (module?.isEmpty()) { - continue; - } - index.writeln([ - r`...${ - name === "$syntax" ? `$.util.omitDollarPrefixed($syntax)` : name - },` - ]); - } - - for (const [moduleName, internalName] of dir._modules) { - if (dir.getModule(moduleName).isEmpty()) { - continue; - } - index.addImportDefault( - `_${internalName}`, - `./modules/${internalName}`, - {allowFileExt: true} - ); - - index.writeln([r`${genutil.quote(moduleName)}: _${internalName},`]); - } - }); - index.writeln([r`};`]); - index.addExportDefault("ExportDefault"); - - // re-export some reflection types - index.writeln([r`const Cardinality = $.Cardinality;`]); - index.writeln([dts`declare `, t`type Cardinality = $.Cardinality;`]); - index.addExport("Cardinality"); - index.writeln([ - t`export `, - dts`declare `, - t`type Set< - Type extends $.BaseType, - Card extends $.Cardinality = $.Cardinality.Many -> = $.TypeSet;` - ]); - } finally { - await cxn.close(); - } - - const initialFiles = new Set(await walk(outputDir)); - const written = new Set(); - - if (target === "ts") { - await dir.write(outputDir, { - mode: "ts", - moduleKind: "esm", - fileExtension: ".ts", - moduleExtension: "", - written - }); - } else if (target === "mts") { - await dir.write(outputDir, { - mode: "ts", - moduleKind: "esm", - fileExtension: ".mts", - moduleExtension: ".mjs", - written - }); - } else if (target === "cjs") { - await dir.write(outputDir, { - mode: "js", - moduleKind: "cjs", - fileExtension: ".js", - moduleExtension: "", - written - }); - await dir.write(outputDir, { - mode: "dts", - moduleKind: "esm", - fileExtension: ".d.ts", - moduleExtension: "", - written - }); - } else if (target === "esm") { - await dir.write(outputDir, { - mode: "js", - moduleKind: "esm", - fileExtension: ".mjs", - moduleExtension: ".mjs", - written - }); - await dir.write(outputDir, { - mode: "dts", - moduleKind: "esm", - fileExtension: ".d.ts", - moduleExtension: "", - written - }); - } else if (target === "deno") { - await dir.write(outputDir, { - mode: "ts", - moduleKind: "esm", - fileExtension: ".ts", - moduleExtension: ".ts", - written - }); - } - - const syntaxOutDir = path.join(outputDir, "syntax"); - if (!(await exists(syntaxOutDir))) { - await fs.mkdir(syntaxOutDir); - } - - const syntaxFiles = $.syntax[target]; - if (!syntaxFiles) { - throw new Error(`Error: no syntax files found for target "${target}"`); - } - - for (const f of syntaxFiles) { - const outputPath = path.join(syntaxOutDir, f.path); - written.add(outputPath); - let oldContents = ""; - try { - oldContents = await readFileUtf8(outputPath); - } catch {} - if (oldContents !== f.content) { - await fs.writeFile(outputPath, f.content); - } - } - - // const syntaxFiles = await readDir(syntaxDir); - // for (const fileName of syntaxFiles) { - // const filetype = fileName.endsWith(".js") - // ? "js" - // : fileName.endsWith(".mjs") - // ? "esm" - // : fileName.endsWith(".mts") - // ? "mts" - // : fileName.endsWith(".d.ts") - // ? "dts" - // : fileName.endsWith(".ts") - // ? "ts" - // : null; - // if ( - // (target === "deno" && filetype !== "ts") || - // (target === "ts" && filetype !== "ts") || - // (target === "mts" && filetype !== "mts") || - // (target === "esm" && !(filetype === "esm" || filetype === "dts")) || - // (target === "cjs" && !(filetype === "js" || filetype === "dts")) - // ) { - // continue; - // } - // const filePath = path.join(syntaxDir, fileName); - // let contents = await readFileUtf8(filePath); - - // if (contents.indexOf(`"edgedb/dist/reflection"`) !== -1) { - // throw new Error("No directory imports allowed in `syntax` files."); - // } - - // const localExtMap: Record = { - // esm: ".mjs", - // mts: ".mjs", - // deno: "", // uses pre-transpiles files - // cjs: "", - // ts: "", - // }; - // const localExt = localExtMap[target]; - // const pkgExtMap: Record = { - // esm: ".js", - // mts: ".js", - // deno: "", // uses pre-transpiles files - // cjs: "", - // ts: "", - // }; - // const pkgExt = pkgExtMap[target]; - - // if (target === "deno") { - // contents = contents - // .replace( - // /"\.\.\/reflection([a-zA-Z0-9\.\_\/]*)"/g, - // `"edgedb/_src/reflection$1"` - // ) - // .replace(/"@generated\/(.*)"/g, `"../$1"`); - // } else { - // contents = contents - // .replace( - // /"\.\.\/reflection([a-zA-Z0-9\_\/]*)\.?(.*)"/g, - // `"edgedb/dist/reflection$1${pkgExt}"` - // ) - // .replace(/"@generated\/(.*)"/g, `"../$1"`); - // } - - // if (localExt) { - // contents = contents.replace(/"(\.?\.\/.+)"/g, `"$1${localExt}"`); - // } - // const outputPath = path.join(syntaxOutDir, fileName); - // written.add(outputPath); - // let oldContents = ""; - // try { - // oldContents = await readFileUtf8(outputPath); - // } catch {} - // if (oldContents !== contents) { - // await fs.writeFile(outputPath, contents); - // } - // } - - const configPath = path.join(outputDir, "config.json"); - await fs.writeFile( - configPath, - `${configFileHeader}\n${JSON.stringify({target})}\n` - ); - written.add(configPath); - - // delete all vestigial files - for (const file of initialFiles) { - if (written.has(file)) { - continue; - } - await fs.rm(file); - } -} diff --git a/_generate/genutil.ts b/_generate/genutil.ts index d626221..93b9913 100644 --- a/_generate/genutil.ts +++ b/_generate/genutil.ts @@ -1,7 +1,15 @@ -import type {CodeBuilder, CodeFragment, IdentRef} from "./builders.ts"; +import type { + CodeBuilder, + CodeFragment, + DirBuilder, + IdentRef +} from "./builders.ts"; import type * as introspect from "../_src/reflection/queries/types.ts"; -import {util} from "../_src/reflection/util.ts"; +import {util} from "../_src/reflection/index.ts"; + export {$} from "../mod.ts"; +import type {$} from "../mod.ts"; +import {adapter} from "../mod.ts"; export function splitName(name: string) { if (!name.includes("::")) throw new Error(`Invalid FQN ${name}`); @@ -55,7 +63,7 @@ export const scalarToLiteralMapping: { "std::json": {type: "unknown"}, "std::bool": {type: "boolean", literalKind: "typeof"}, "std::bigint": {type: "bigint", literalKind: "typeof"}, - "std::bytes": {type: "Buffer", literalKind: "instanceof"}, + "std::bytes": {type: "Uint8Array", literalKind: "instanceof"}, "std::datetime": { type: "Date", literalKind: "instanceof", @@ -371,3 +379,90 @@ export const reservedIdents = new Set([ "instanceof", "Object" ]); + +export async function writeDirWithTarget( + dir: DirBuilder, + target: Target, + params: {outputDir: string; written?: Set} +) { + const {outputDir, written = new Set()} = params; + if (target === "ts") { + await dir.write(outputDir, { + mode: "ts", + moduleKind: "esm", + fileExtension: ".ts", + moduleExtension: "", + written + }); + } else if (target === "mts") { + await dir.write(outputDir, { + mode: "ts", + moduleKind: "esm", + fileExtension: ".mts", + moduleExtension: ".mjs", + written + }); + } else if (target === "cjs") { + await dir.write(outputDir, { + mode: "js", + moduleKind: "cjs", + fileExtension: ".js", + moduleExtension: "", + written + }); + await dir.write(outputDir, { + mode: "dts", + moduleKind: "esm", + fileExtension: ".d.ts", + moduleExtension: "", + written + }); + } else if (target === "esm") { + await dir.write(outputDir, { + mode: "js", + moduleKind: "esm", + fileExtension: ".mjs", + moduleExtension: ".mjs", + written + }); + await dir.write(outputDir, { + mode: "dts", + moduleKind: "esm", + fileExtension: ".d.ts", + moduleExtension: "", + written + }); + } else if (target === "deno") { + await dir.write(outputDir, { + mode: "ts", + moduleKind: "esm", + fileExtension: ".ts", + moduleExtension: ".ts", + written + }); + } +} + +export type GeneratorParams = { + dir: DirBuilder; + types: $.introspect.Types; + typesByName: Record; + casts: $.introspect.Casts; + scalars: $.introspect.ScalarTypes; + functions: $.introspect.FunctionTypes; + globals: $.introspect.Globals; + operators: $.introspect.OperatorTypes; +}; + +export function exitWithError(message: string): never { + // tslint:disable-next-line + console.error(message); + adapter.exit(1); + throw new Error(); +} + +export type Target = "ts" | "esm" | "cjs" | "mts" | "deno"; +export type Version = { + major: number; + minor: number; +}; diff --git a/_generate/interfaces.ts b/_generate/interfaces.ts new file mode 100644 index 0000000..fe1f9f3 --- /dev/null +++ b/_generate/interfaces.ts @@ -0,0 +1,79 @@ +// tslint:disable:no-console +import type {CommandOptions} from "./commandutil.ts"; +import {exitWithError} from "./genutil.ts"; + +import {$, adapter, Client, createClient} from "../mod.ts"; +import {DirBuilder} from "./builders.ts"; + +import type {ConnectConfig} from "../_src/conUtils.ts"; +import {generateInterfaces} from "./edgeql-js/generateInterfaces.ts"; + +const {path} = adapter; + +export async function runInterfacesGenerator(params: { + root: string | null; + options: CommandOptions; + connectionConfig: ConnectConfig; +}) { + const {root, options, connectionConfig} = params; + + let outFile: string; + if (options.file) { + outFile = path.isAbsolute(options.file) + ? options.file + : path.join(adapter.process.cwd(), options.file); + } else if (root) { + outFile = path.join(root, "dbschema/interfaces.ts"); + } else { + throw new Error( + `No edgedb.toml found. Initialize an EdgeDB project with\n\`edgedb project init\` or specify an output file with \`--file\`` + ); + } + + let outputDirIsInProject = false; + let prettyOutputDir; + if (root) { + const relativeOutputDir = path.posix.relative(root, outFile); + outputDirIsInProject = !relativeOutputDir.startsWith(".."); + prettyOutputDir = outputDirIsInProject + ? `./${relativeOutputDir}` + : outFile; + } else { + prettyOutputDir = outFile; + } + + let cxn: Client; + try { + cxn = createClient({ + ...connectionConfig, + concurrency: 5 + }); + } catch (e) { + exitWithError(`Failed to connect: ${(e as Error).message}`); + } + + const dir = new DirBuilder(); + + // tslint:disable-next-line + console.log(`Introspecting database schema...`); + const types = await $.introspect.types(cxn); + const generatorParams = { + dir, + types + }; + console.log(`Generating interfaces...`); + generateInterfaces(generatorParams); + + const file = dir.getPath("interfaces"); + const rendered = file.render({ + mode: "ts", + moduleKind: "esm", + moduleExtension: "" + }); + + console.log(`Writing interfaces file...`); + console.log(" " + prettyOutputDir); + await adapter.fs.writeFile(outFile, rendered); + + console.log(`Generation complete! 🤘`); +} diff --git a/_generate/prettyPrint.ts b/_generate/prettyPrint.ts deleted file mode 100644 index 8fb325b..0000000 --- a/_generate/prettyPrint.ts +++ /dev/null @@ -1,68 +0,0 @@ -enum ErrorAttr { - hint = 1, - details = 2, - serverTraceback = 257, - positionStart = -15, - positionEnd = -14, - lineStart = -13, - columnStart = -12, - utf16ColumnStart = -11, - lineEnd = -10, - columnEnd = -9, - utf16ColumnEnd = -8, - characterStart = -7, - characterEnd = -6 -} - -function tryParseInt(val: any) { - if (Buffer.isBuffer(val)) { - try { - return parseInt(val.toString("utf8"), 10); - } catch {} - } - return null; -} - -export function prettyPrintError(err: any, query: string) { - const attrs = err.attrs; - - if (attrs == null || !(attrs instanceof Map)) { - return err.toString(); - } - - const lineStart = tryParseInt(attrs.get(ErrorAttr.lineStart)); - const lineEnd = tryParseInt(attrs.get(ErrorAttr.lineEnd)); - const colStart = tryParseInt(attrs.get(ErrorAttr.utf16ColumnStart)); - const colEnd = tryParseInt(attrs.get(ErrorAttr.utf16ColumnEnd)); - - if ( - lineStart == null || - lineEnd == null || - colStart == null || - colEnd == null - ) { - return err.toString(); - } - - const queryLines = query.split("\n"); - - const lineNoWidth = lineEnd.toString().length; - let errMessage = err.toString() + "\n"; - - errMessage += "|".padStart(lineNoWidth + 3) + "\n"; - - for (let i = lineStart; i < lineEnd + 1; i++) { - const line = queryLines[i - 1]; - const start = i === lineStart ? colStart : 0; - const end = i === lineEnd ? colEnd : line.length; - errMessage += ` ${i.toString().padStart(lineNoWidth)} | ${line}\n`; - errMessage += `${"|".padStart(lineNoWidth + 3)} ${"" - .padStart(end - start, "^") - .padStart(end)}\n`; - } - if (attrs.has(ErrorAttr.hint)) { - errMessage += `Hint: ${attrs.get(ErrorAttr.hint).toString("utf8")}\n`; - } - - return errMessage; -} diff --git a/_generate/queries.ts b/_generate/queries.ts index fb016fa..aff6498 100644 --- a/_generate/queries.ts +++ b/_generate/queries.ts @@ -1,10 +1,10 @@ // tslint:disable -import {createClient, adapter} from "../mod.ts"; +import {createClient, adapter, $} from "../mod.ts"; import type {ConnectConfig} from "../_src/conUtils.ts"; import type {CommandOptions} from "./commandutil.ts"; -import {generateQueryType} from "./codecToType.ts"; -import type {QueryType} from "./codecToType.ts"; -import type {Target} from "./generate.ts"; +// import {$} from "./codecToType"; +// import type {QueryType} from "./codecToType"; +import type {Target} from "./genutil.ts"; import {Cardinality} from "../_src/ifaces.ts"; // generate per-file queries @@ -47,7 +47,7 @@ currently supported.`); console.log(`Connecting to database...`); await client.ensureConnected(); - console.log(`Searching for .edgeql files...`); + console.log(`Analyzing .edgeql files...`); // generate all queries in single file if (params.options.file) { @@ -58,7 +58,7 @@ currently supported.`); const prettyPath = "./" + adapter.path.posix.relative(root, path); console.log(` ${prettyPath}`); const query = await adapter.readFileUtf8(path); - const types = await generateQueryType(client, query); + const types = await $.analyzeQuery(client, query); const files = await generateFiles({ target: params.options.target!, path, @@ -82,11 +82,16 @@ currently supported.`); }...` ); for (const [extension, file] of Object.entries(filesByExtension)) { - const filePath = adapter.path.join( - root, - params.options.file + extension - ); - const prettyPath = "./" + adapter.path.posix.relative(root, filePath); + const filePath = + (adapter.path.isAbsolute(params.options.file) + ? params.options.file + : adapter.path.join( + adapter.process.cwd(), // all paths computed relative to cwd + params.options.file + )) + extension; + const prettyPath = adapter.path.isAbsolute(params.options.file) + ? params.options.file + extension + : "./" + adapter.path.posix.relative(root, filePath); console.log(` ${prettyPath}`); await adapter.fs.writeFile( filePath, @@ -100,7 +105,7 @@ currently supported.`); async function generateFilesForQuery(path: string) { const query = await adapter.readFileUtf8(path); if (!query) return; - const types = await generateQueryType(client, query); + const types = await $.analyzeQuery(client, query); const files = await generateFiles({ target: params.options.target!, path, @@ -157,6 +162,8 @@ async function getMatches(root: string) { // ts: `.ts` // }; +type QueryType = Awaited>; + function generateFiles(params: { target: Target; path: string; @@ -184,17 +191,26 @@ function generateFiles(params: { } const tsImports = {Client: true, ...imports}; - const tsImpl = `async function ${functionName}(client: Client, args: ${ - params.types.args - }): Promise<${params.types.out}> { - return client.${method}(\`${params.types.query.replace("`", "`")}\`, args) + const hasArgs = params.types.args && params.types.args !== "null"; + const tsImpl = `async function ${functionName}(client: Client${ + hasArgs ? `, args: ${params.types.args}` : "" + }): Promise<${params.types.result}> { + return client.${method}(\`${params.types.query.replace("`", "`")}\`${ + hasArgs ? `, args` : "" + }); }`; - const jsImpl = `async function ${functionName}(client, args){ - return client.${method}(\`${params.types.query.replace("`", "`")}\`, args); + const jsImpl = `async function ${functionName}(client${ + hasArgs ? `, args` : "" + }) { + return client.${method}(\`${params.types.query.replace("`", "`")}\`${ + hasArgs ? `, args` : "" + }); }`; - const dtsImpl = `function ${functionName}(client: Client, params: ${params.types.args}): Promise<${params.types.out}>;`; + const dtsImpl = `function ${functionName}(client: Client${ + hasArgs ? `, args: ${params.types.args}` : "" + }): Promise<${params.types.result}>;`; switch (params.target) { case "cjs": diff --git a/generate.ts b/generate.ts index 7fdf399..e75563f 100644 --- a/generate.ts +++ b/generate.ts @@ -1,3 +1,3 @@ -export * from "./_src/reflection/cli.ts"; +export * from "./_generate/cli.ts"; \ No newline at end of file