Skip to content

Commit 70ca0b0

Browse files
committed
Improve types on Surreal
1 parent 46bba84 commit 70ca0b0

File tree

3 files changed

+49
-133
lines changed

3 files changed

+49
-133
lines changed

src/library/tagged-template.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PreparedQuery } from "./PreparedQuery.ts";
22

3-
export function surrealql(query_raw: string[], ...values: unknown[]) {
3+
export function surrealql(query_raw: TemplateStringsArray, ...values: unknown[]) {
44
const mapped_bindings = values.map((v, i) =>
55
[`__tagged_template_literal_binding__${i}`, v] as const
66
);

src/surreal.ts

+44-37
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ import {
1919
type StatusHooks,
2020
Token,
2121
TransformAuth,
22+
Prettify,
2223
} from "./types.ts";
2324

2425
type Engines = Record<string, new (emitter: Emitter<EmitterEvents>) => Engine>;
26+
type R = Prettify<Record<string, unknown>>;
2527

2628
export class Surreal {
2729
public connection: Engine | undefined;
@@ -397,44 +399,44 @@ export class Surreal {
397399
* Selects all records in a table, or a specific record, from the database.
398400
* @param thing - The table name or a record ID to select.
399401
*/
400-
async select<T extends Record<string, unknown>>(thing: string | RecordId) {
402+
async select<T extends R>(thing: string): Promise<ActionResult<T>[]>;
403+
async select<T extends R>(thing: RecordId): Promise<ActionResult<T>>;
404+
async select<T extends R>(thing: RecordId | string) {
401405
await this.ready;
402406
const res = await this.rpc<ActionResult<T>>("select", [thing]);
403-
return this.outputHandler(res);
407+
return this.outputHandler(res, thing instanceof RecordId);
404408
}
405409

406410
/**
407411
* Creates a record in the database.
408412
* @param thing - The table name or the specific record ID to create.
409413
* @param data - The document / record data to insert.
410414
*/
411-
async create<
412-
T extends Record<string, unknown>,
413-
U extends Record<string, unknown> = T
414-
>(thing: string | RecordId, data?: U) {
415+
async create<T extends R, U extends R = T>(thing: string, data?: U): Promise<ActionResult<T>[]>;
416+
async create<T extends R, U extends R = T>(thing: RecordId, data?: U): Promise<ActionResult<T>[]>;
417+
async create<T extends R, U extends R = T>(thing: RecordId | string, data?: U) {
415418
await this.ready;
416-
const res = await this.rpc<ActionResult<T, U>>("create", [
419+
const res = await this.rpc<ActionResult<T>>("create", [
417420
thing,
418421
data,
419422
]);
420-
return this.outputHandler(res);
423+
return this.outputHandler(res, thing instanceof RecordId);
421424
}
422425

423426
/**
424427
* Inserts one or multiple records in the database.
425428
* @param thing - The table name or the specific record ID to create.
426429
* @param data - The document(s) / record(s) to insert.
427430
*/
428-
async insert<
429-
T extends Record<string, unknown>,
430-
U extends Record<string, unknown> = T
431-
>(thing: string | RecordId, data?: U | U[]) {
431+
async insert<T extends R, U extends R = T>(thing: string, data?: U | U[]): Promise<ActionResult<T>[]>;
432+
async insert<T extends R, U extends R = T>(thing: RecordId, data?: U): Promise<ActionResult<T>>;
433+
async insert<T extends R, U extends R = T>(thing: RecordId | string, data?: U | U[]) {
432434
await this.ready;
433-
const res = await this.rpc<ActionResult<T, U>>("insert", [
435+
const res = await this.rpc<ActionResult<T>>("insert", [
434436
thing,
435437
data,
436438
]);
437-
return this.outputHandler(res);
439+
return this.outputHandler(res, thing instanceof RecordId);
438440
}
439441

440442
/**
@@ -444,16 +446,15 @@ export class Surreal {
444446
* @param thing - The table name or the specific record ID to update.
445447
* @param data - The document / record data to insert.
446448
*/
447-
async update<
448-
T extends Record<string, unknown>,
449-
U extends Record<string, unknown> = T
450-
>(thing: string | RecordId, data?: U) {
449+
async update<T extends R, U extends R = T>(thing: string, data?: U): Promise<ActionResult<T>[]>;
450+
async update<T extends R, U extends R = T>(thing: RecordId, data?: U): Promise<ActionResult<T>>;
451+
async update<T extends R, U extends R = T>(thing: RecordId | string, data?: U) {
451452
await this.ready;
452-
const res = await this.rpc<ActionResult<T, U>>("update", [
453+
const res = await this.rpc<ActionResult<T>>("update", [
453454
thing,
454455
data,
455456
]);
456-
return this.outputHandler(res);
457+
return this.outputHandler(res, thing instanceof RecordId);
457458
}
458459

459460
/**
@@ -463,13 +464,15 @@ export class Surreal {
463464
* @param thing - The table name or the specific record ID to change.
464465
* @param data - The document / record data to insert.
465466
*/
466-
async merge<
467-
T extends Record<string, unknown>,
468-
U extends Record<string, unknown> = Partial<T>
469-
>(thing: string | RecordId, data?: U) {
467+
async merge<T extends R, U extends R = T>(thing: string, data?: U): Promise<ActionResult<T>[]>;
468+
async merge<T extends R, U extends R = T>(thing: RecordId, data?: U): Promise<ActionResult<T>>;
469+
async merge<T extends R, U extends R = T>(thing: RecordId | string, data?: U) {
470470
await this.ready;
471-
const res = await this.rpc<ActionResult<U>>("merge", [thing, data]);
472-
return this.outputHandler(res);
471+
const res = await this.rpc<ActionResult<T>>("merge", [
472+
thing,
473+
data,
474+
]);
475+
return this.outputHandler(res, thing instanceof RecordId);
473476
}
474477

475478
/**
@@ -479,22 +482,25 @@ export class Surreal {
479482
* @param thing - The table name or the specific record ID to modify.
480483
* @param data - The JSON Patch data with which to modify the records.
481484
*/
482-
async patch(thing: RecordId, data?: Patch[]) {
485+
async patch<T extends R>(thing: RecordId, data?: Patch[], diff?: false): Promise<ActionResult<T>>;
486+
async patch<T extends R>(thing: string, data?: Patch[], diff?: false): Promise<ActionResult<T>[]>;
487+
async patch(thing: RecordId | string, data: undefined | Patch[], diff: true): Promise<Patch[]>;
488+
async patch(thing: RecordId | string, data?: Patch[], diff?: boolean) {
483489
await this.ready;
484-
const res = await this.rpc<Patch>("patch", [thing, data]);
485-
return this.outputHandler(res);
490+
const res = await this.rpc<any>("patch", [thing, data, diff]);
491+
return this.outputHandler(res, thing instanceof RecordId);
486492
}
487493

488494
/**
489495
* Deletes all records in a table, or a specific record, from the database.
490496
* @param thing - The table name or a record ID to select.
491497
*/
492-
async delete<T extends Record<string, unknown> = Record<string, unknown>>(
493-
thing: string | RecordId<string>
494-
) {
498+
async delete<T extends R>(thing: string): Promise<ActionResult<T>[]>;
499+
async delete<T extends R>(thing: RecordId): Promise<ActionResult<T>>;
500+
async delete<T extends R>(thing: RecordId | string) {
495501
await this.ready;
496502
const res = await this.rpc<ActionResult<T>>("delete", [thing]);
497-
return this.outputHandler(res);
503+
return this.outputHandler(res, thing instanceof RecordId);
498504
}
499505

500506
/**
@@ -516,15 +522,16 @@ export class Surreal {
516522
* @param thing - What thing did you query (table vs record).
517523
*/
518524
private outputHandler<T extends Record<string, unknown>>(
519-
res: RpcResponse<T>
525+
res: RpcResponse<T>,
526+
single?: boolean,
520527
) {
521528
if (res.error) throw new ResponseError(res.error.message);
522529
if (Array.isArray(res.result)) {
523-
return res.result as T[];
530+
return single ? res.result as T[] : res.result[0] as T | undefined;
524531
} else if ("id" in (res.result ?? {})) {
525-
return [res.result] as T[];
532+
return single ? res.result as T | undefined : [res.result] as T[];
526533
} else if (res.result === null) {
527-
return [] as T[];
534+
return single ? undefined : [] as T[];
528535
}
529536

530537
throw new UnexpectedResponse();

src/types.ts

+4-95
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,7 @@
11
import { z } from "zod";
2-
import { PreparedQuery } from "./index.ts";
32
import { RecordId } from "./library/data/recordid.ts";
43
import { Surreal } from "./surreal.ts";
54

6-
export type ConnectionStrategy = "websocket" | "experimental_http";
7-
export interface Connection {
8-
constructor: Constructor<(hooks: StatusHooks) => void>;
9-
10-
strategy: "ws" | "http";
11-
connect: (url: string, options?: ConnectionOptions) => void;
12-
ping: () => Promise<void>;
13-
use: (opt: { namespace: string; database: string }) => MaybePromise<void>;
14-
15-
// Info method is not available in the HTTP REST API
16-
info?: <T extends Record<string, unknown> = Record<string, unknown>>() =>
17-
Promise<T | undefined>;
18-
19-
signup: (vars: ScopeAuth) => Promise<Token>;
20-
signin: (vars: AnyAuth) => Promise<Token | void>;
21-
authenticate: (token: Token) => MaybePromise<boolean>;
22-
invalidate: () => MaybePromise<void>;
23-
24-
// Let/unset methods are not available in the HTTP REST API
25-
let?: (variable: string, value: unknown) => Promise<void>;
26-
unset?: (variable: string) => Promise<void>;
27-
28-
// Live query functions
29-
live?: <T extends Record<string, unknown>>(
30-
table: string,
31-
callback?: (data: LiveQueryResponse<T>) => unknown,
32-
diff?: boolean,
33-
) => Promise<string>;
34-
listenLive?: <T extends Record<string, unknown>>(
35-
queryUuid: string,
36-
callback: (data: LiveQueryResponse<T>) => unknown,
37-
) => Promise<void>;
38-
kill?: (queryUuid: string) => Promise<void>;
39-
40-
query: <T extends RawQueryResult[]>(
41-
query: string | PreparedQuery,
42-
bindings?: Record<string, unknown>,
43-
) => Promise<T>;
44-
45-
query_raw: <T extends RawQueryResult[]>(
46-
query: string | PreparedQuery,
47-
bindings?: Record<string, unknown>,
48-
) => Promise<MapQueryResult<T>>;
49-
50-
select: <T extends Record<string, unknown>>(
51-
thing: string,
52-
) => Promise<ActionResult<T>[]>;
53-
54-
create: <
55-
T extends Record<string, unknown>,
56-
U extends Record<string, unknown> = T,
57-
>(
58-
thing: string,
59-
data?: U,
60-
) => Promise<ActionResult<T, U>[]>;
61-
62-
// Insert method is not available in the HTTP REST API
63-
insert?: <
64-
T extends Record<string, unknown>,
65-
U extends Record<string, unknown> = T,
66-
>(
67-
thing: string,
68-
data?: U | U[],
69-
) => Promise<ActionResult<T, U>[]>;
70-
71-
update: <
72-
T extends Record<string, unknown>,
73-
U extends Record<string, unknown> = T,
74-
>(
75-
thing: string,
76-
data?: U,
77-
) => Promise<ActionResult<T, U>[]>;
78-
79-
merge: <
80-
T extends Record<string, unknown>,
81-
U extends Record<string, unknown> = Partial<T>,
82-
>(
83-
thing: string,
84-
data?: U,
85-
) => Promise<ActionResult<T, U>[]>;
86-
87-
// Patch method is not available in the HTTP REST API
88-
patch?: (thing: string, data?: Patch[]) => Promise<Patch[]>;
89-
90-
delete: <T extends Record<string, unknown>>(
91-
thing: string,
92-
) => Promise<ActionResult<T>[]>;
93-
}
94-
955
export type StatusHooks = {
966
onConnect?: () => unknown;
977
onReconnect?: () => unknown;
@@ -108,12 +18,11 @@ export type UseOptions = z.infer<typeof UseOptions>;
10818

10919
export type ActionResult<
11020
T extends Record<string, unknown>,
111-
U extends Record<string, unknown> = T,
112-
> = TidyObject<T & U & { id: RecordId }>;
21+
> = Prettify<T['id'] extends RecordId ? T : { id: RecordId } & T>
11322

114-
type TidyObject<T extends Record<string, unknown>> = {
115-
[K in keyof T]: T[K]
116-
};
23+
export type Prettify<T> = {
24+
[K in keyof T]: T[K];
25+
} & {};
11726

11827
//////////////////////////////////////////////
11928
////////// AUTHENTICATION TYPES //////////

0 commit comments

Comments
 (0)