-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2930 from SeedCompany/edgedb/inline-edgeql
- Loading branch information
Showing
6 changed files
with
257 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* eslint-disable @typescript-eslint/unified-signatures */ | ||
import { Injectable } from '@nestjs/common'; | ||
import { $, Executor } from 'edgedb'; | ||
import { TypedEdgeQL } from './edgeql'; | ||
import { InlineQueryCardinalityMap } from './generated-client/inline-queries'; | ||
import { Client } from './reexports'; | ||
|
||
@Injectable() | ||
export class EdgeDB { | ||
constructor(private readonly client: Client) {} | ||
|
||
/** Run a query from an edgeql string */ | ||
run<R>(query: TypedEdgeQL<null, R>): Promise<R>; | ||
/** Run a query from an edgeql string */ | ||
run<Args extends Record<string, any>, R>( | ||
query: TypedEdgeQL<Args, R>, | ||
args: Args, | ||
): Promise<R>; | ||
|
||
/** Run a query from a edgeql file */ | ||
run<Args, R>( | ||
query: (client: Executor, args: Args) => Promise<R>, | ||
args: Args, | ||
): Promise<R>; | ||
/** Run a query from a edgeql file */ | ||
run<R>(query: (client: Executor) => Promise<R>): Promise<R>; | ||
|
||
/** Run a query from the query builder */ | ||
run<R>(query: { run: (client: Executor) => Promise<R> }): Promise<R>; | ||
|
||
async run(query: any, args?: any) { | ||
if (query instanceof TypedEdgeQL) { | ||
const cardinality = InlineQueryCardinalityMap.get(query.query); | ||
if (!cardinality) { | ||
throw new Error(`Query was not found from inline query generation`); | ||
} | ||
const exeMethod = cardinalityToExecutorMethod[cardinality]; | ||
|
||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return await this.client[exeMethod](query.query, args); | ||
} | ||
|
||
if (query.run) { | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return await query.run(this.client); | ||
} | ||
|
||
if (typeof query === 'function') { | ||
// eslint-disable-next-line @typescript-eslint/return-await | ||
return await query(this.client, args); | ||
} | ||
|
||
// For REPL, as this is untyped and assumes many/empty cardinality | ||
if (typeof query === 'string') { | ||
return await this.client.query(query, args); | ||
} | ||
|
||
throw new Error('Could not figure out how to run given query'); | ||
} | ||
} | ||
|
||
const cardinalityToExecutorMethod = { | ||
One: 'queryRequiredSingle', | ||
AtMostOne: 'querySingle', | ||
Many: 'query', | ||
AtLeastOne: 'query', | ||
Empty: 'query', | ||
} satisfies Record<`${$.Cardinality}`, keyof Executor>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { stripIndent } from 'common-tags'; | ||
import { InlineQueryMap as QueryMap } from './generated-client/inline-queries'; | ||
|
||
export const edgeql = <const Query extends string>( | ||
query: Query, | ||
): Query extends keyof QueryMap ? QueryMap[Query] : unknown => { | ||
return new TypedEdgeQL(stripIndent(query)) as any; | ||
}; | ||
|
||
export type EdgeQLArgsOf<T extends TypedEdgeQL<any, any>> = | ||
T extends TypedEdgeQL<infer Args, any> ? Args : never; | ||
|
||
export type EdgeQLReturnOf<T extends TypedEdgeQL<any, any>> = | ||
T extends TypedEdgeQL<any, infer Return> ? Return : never; | ||
|
||
// Internal symbol to mark a query as typed | ||
const edgeqlTS = Symbol('edgeqlTS'); | ||
|
||
export class TypedEdgeQL<Args, Return> { | ||
constructor(readonly query: string) {} | ||
[edgeqlTS]?: { | ||
args: Args; | ||
return: Return; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
export * from './reexports'; | ||
export { edgeql, EdgeQLArgsOf, EdgeQLReturnOf } from './edgeql'; | ||
export * from './edgedb.service'; | ||
export { default as e } from './generated-client/index.mjs'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,3 @@ | ||
import { Transaction } from 'edgedb/dist/transaction.js'; | ||
|
||
// Only use this if you need the extra methods. | ||
// Otherwise, for querying, use EdgeDb from below. | ||
export { Client } from 'edgedb/dist/baseClient.js'; | ||
|
||
// Using this as it's a runtime symbol for the Executor TS shape | ||
// which makes it perfect for injection. | ||
// @ts-expect-error private constructor; doesn't matter that's not how we are using it. | ||
// We could just export the Transaction as an aliased named, but this also | ||
// allows REPL to reference it with the correct name. | ||
export abstract class EdgeDB extends Transaction {} |