Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions packages/generate/src/syntax/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,34 @@ export type QueryableWithParamsExpression<
runJSON(cxn: Executor, args: paramsToParamArgs<Params>): Promise<string>;
};

type paramOrTsType<Type extends ParamType, Optional extends boolean> =
| $expr_Param<string, Type, Optional>
| Readonly<BaseTypeToTsType<Type, true>>;

type paramsToInputArgs<Params extends ParamsRecord> = {
[key in keyof Params as Params[key] extends ParamType
? key
: never]: Params[key] extends ParamType
? paramOrTsType<Params[key], false>
: never;
} & {
[key in keyof Params as Params[key] extends $expr_OptionalParam
? key
: never]?: Params[key] extends $expr_OptionalParam
? paramOrTsType<Params[key]["__type__"], true>
: never;
};

type CallableWithParamsExpr<
Params extends ParamsRecord = Record<string, never>,
Expr extends TypeSet = TypeSet,
> = {
(args: paramsToInputArgs<Params>): Expression<{
__element__: Expr["__element__"];
__cardinality__: Expr["__cardinality__"];
}>;
};

export type $expr_WithParams<
Params extends ParamsRecord = Record<string, never>,
Expr extends TypeSet = TypeSet,
Expand All @@ -57,7 +85,8 @@ export type $expr_WithParams<
__params__: $expr_Param[];
},
Params
>;
> &
CallableWithParamsExpr<Params, Expr>;

type paramsToParamArgs<Params extends ParamsRecord> = {
[key in keyof Params as Params[key] extends ParamType
Expand Down Expand Up @@ -128,11 +157,26 @@ export function params<
returnExpr = select(returnExpr) as any;
}

return $expressionify({
const withParamsExpr = $expressionify({
__kind__: ExpressionKind.WithParams,
__element__: returnExpr.__element__,
__cardinality__: returnExpr.__cardinality__,
__expr__: returnExpr,
__params__: Object.values(paramExprs),
}) as any;

const callableExpr = function (args: paramsToInputArgs<Params>) {
return $expressionify({
__kind__: ExpressionKind.WithParams,
__element__: returnExpr.__element__,
__cardinality__: returnExpr.__cardinality__,
__expr__: returnExpr,
__params__: Object.values(paramExprs),
__args__: args,
}) as any;
};

Object.assign(callableExpr, withParamsExpr);

return callableExpr as any;
}
30 changes: 25 additions & 5 deletions packages/generate/src/syntax/toEdgeQL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,11 +659,12 @@ function walkExprTree(
break;
}
case ExpressionKind.WithParams: {
if (parentScope !== null) {
throw new Error(
`'withParams' does not support being used as a nested expression`,
);
}
// Does this need to be here?, seems to work fine without it.
// if (parentScope !== null) {
// throw new Error(
// `'withParams' does not support being used as a nested expression`,
// );
// }
childExprs.push(...walkExprTree(expr.__expr__, parentScope, ctx));
break;
}
Expand Down Expand Up @@ -866,6 +867,25 @@ function renderEdgeQL(
if (expr.__kind__ === ExpressionKind.With) {
return renderEdgeQL(expr.__expr__, ctx);
} else if (expr.__kind__ === ExpressionKind.WithParams) {
if ((expr as any).__args__) {
const argList = Object.entries((expr as any).__args__)
.map(([key, value]) => {
if (
value &&
typeof value === "object" &&
(value as any).__kind__ === ExpressionKind.Param
) {
return ` __param__${key} := ${renderEdgeQL(value as any, ctx)}`;
}
const param = expr.__params__.find(
(p: any) => p.__name__ === key,
) as any;
return ` __param__${key} := ${literalToEdgeQL(param.__element__, value)}`;
})
.join(",\n");

return `(WITH\n${argList}\nSELECT ${renderEdgeQL(expr.__expr__, ctx)})`;
}
return `(WITH\n${expr.__params__
.map((param) => {
const optional =
Expand Down