Skip to content

Commit 3651538

Browse files
committed
Merge branch 'master' into shub/table-name-to-accessor
2 parents d1f208a + 253095a commit 3651538

16 files changed

Lines changed: 674 additions & 566 deletions

File tree

Cargo.lock

Lines changed: 311 additions & 256 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ rayon = "1.8"
254254
rayon-core = "1.11.0"
255255
regex = "1"
256256
reqwest = { version = "0.12", features = ["stream", "json"] }
257-
rolldown = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-beta.42" }
258-
rolldown_common = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-beta.42" }
259-
rolldown_utils = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-beta.42" }
257+
rolldown = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-rc.3" }
258+
rolldown_common = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-rc.3" }
259+
rolldown_utils = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-rc.3" }
260260
ron = "0.8"
261261
rusqlite = { version = "0.29.0", features = ["bundled", "column_decltype"] }
262262
rust_decimal = { version = "1.29.1", features = ["db-tokio-postgres"] }
Lines changed: 40 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,13 @@
11
/**
22
* Base class for all Spacetime host errors (i.e. errors that may be thrown
33
* by database functions).
4-
*
5-
* Instances of SpacetimeError can be created with just an error code,
6-
* which will return the appropriate subclass instance.
74
*/
85
export class SpacetimeHostError extends Error {
9-
public readonly code: number;
10-
public readonly message: string;
11-
constructor(code: number, message?: string) {
12-
super();
13-
const proto = Object.getPrototypeOf(this);
14-
let cls;
15-
if (errorProtoypes.has(proto)) {
16-
cls = proto.constructor;
17-
if (code !== cls.CODE)
18-
throw new TypeError(`invalid error code for ${cls.name}`);
19-
} else if (proto === SpacetimeHostError.prototype) {
20-
cls = errnoToClass.get(code);
21-
if (!cls) throw new RangeError(`unknown error code ${code}`);
22-
} else {
23-
throw new TypeError('cannot subclass SpacetimeError');
24-
}
25-
Object.setPrototypeOf(this, cls.prototype);
26-
this.code = cls.CODE;
27-
this.message = message ?? cls.MESSAGE;
6+
constructor(message: string) {
7+
super(message);
288
}
299
get name(): string {
30-
return errnoToClass.get(this.code)?.name ?? 'SpacetimeHostError';
10+
return 'SpacetimeHostError';
3111
}
3212
}
3313

@@ -50,110 +30,89 @@ const errorData = {
5030
/**
5131
* A generic error class for unknown error codes.
5232
*/
53-
HostCallFailure: [1, 'ABI called by host returned an error'],
33+
HostCallFailure: 1,
5434

5535
/**
5636
* Error indicating that an ABI call was made outside of a transaction.
5737
*/
58-
NotInTransaction: [2, 'ABI call can only be made while in a transaction'],
38+
NotInTransaction: 2,
5939

6040
/**
6141
* Error indicating that BSATN decoding failed.
6242
* This typically means that the data could not be decoded to the expected type.
6343
*/
64-
BsatnDecodeError: [3, "Couldn't decode the BSATN to the expected type"],
44+
BsatnDecodeError: 3,
6545

6646
/**
6747
* Error indicating that a specified table does not exist.
6848
*/
69-
NoSuchTable: [4, 'No such table'],
49+
NoSuchTable: 4,
7050

7151
/**
7252
* Error indicating that a specified index does not exist.
7353
*/
74-
NoSuchIndex: [5, 'No such index'],
54+
NoSuchIndex: 5,
7555

7656
/**
7757
* Error indicating that a specified row iterator is not valid.
7858
*/
79-
NoSuchIter: [6, 'The provided row iterator is not valid'],
59+
NoSuchIter: 6,
8060

8161
/**
8262
* Error indicating that a specified console timer does not exist.
8363
*/
84-
NoSuchConsoleTimer: [7, 'The provided console timer does not exist'],
64+
NoSuchConsoleTimer: 7,
8565

8666
/**
8767
* Error indicating that a specified bytes source or sink is not valid.
8868
*/
89-
NoSuchBytes: [8, 'The provided bytes source or sink is not valid'],
69+
NoSuchBytes: 8,
9070

9171
/**
9272
* Error indicating that a provided sink has no more space left.
9373
*/
94-
NoSpace: [9, 'The provided sink has no more space left'],
74+
NoSpace: 9,
9575

9676
/**
9777
* Error indicating that there is no more space in the database.
9878
*/
99-
BufferTooSmall: [
100-
11,
101-
'The provided buffer is not large enough to store the data',
102-
],
79+
BufferTooSmall: 11,
10380

10481
/**
10582
* Error indicating that a value with a given unique identifier already exists.
10683
*/
107-
UniqueAlreadyExists: [
108-
12,
109-
'Value with given unique identifier already exists',
110-
],
84+
UniqueAlreadyExists: 12,
11185

11286
/**
11387
* Error indicating that the specified delay in scheduling a row was too long.
11488
*/
115-
ScheduleAtDelayTooLong: [
116-
13,
117-
'Specified delay in scheduling row was too long',
118-
],
89+
ScheduleAtDelayTooLong: 13,
11990

12091
/**
12192
* Error indicating that an index was not unique when it was expected to be.
12293
*/
123-
IndexNotUnique: [14, 'The index was not unique'],
94+
IndexNotUnique: 14,
12495

12596
/**
12697
* Error indicating that an index was not unique when it was expected to be.
12798
*/
128-
NoSuchRow: [15, 'The row was not found, e.g., in an update call'],
99+
NoSuchRow: 15,
129100

130101
/**
131102
* Error indicating that an auto-increment sequence has overflowed.
132103
*/
133-
AutoIncOverflow: [16, 'The auto-increment sequence overflowed'],
104+
AutoIncOverflow: 16,
134105

135-
WouldBlockTransaction: [
136-
17,
137-
'Attempted async or blocking op while holding open a transaction',
138-
],
106+
WouldBlockTransaction: 17,
139107

140-
TransactionNotAnonymous: [
141-
18,
142-
'Not in an anonymous transaction. Called by a reducer?',
143-
],
108+
TransactionNotAnonymous: 18,
144109

145-
TransactionIsReadOnly: [
146-
19,
147-
'ABI call can only be made while within a mutable transaction',
148-
],
110+
TransactionIsReadOnly: 19,
149111

150-
TransactionIsMut: [
151-
20,
152-
'ABI call can only be made while within a read-only transaction',
153-
],
112+
TransactionIsMut: 20,
154113

155-
HttpError: [21, 'The HTTP request failed'],
156-
} as const;
114+
HttpError: 21,
115+
};
157116

158117
function mapEntries<const T extends Record<string, any>, U>(
159118
x: T,
@@ -164,30 +123,27 @@ function mapEntries<const T extends Record<string, any>, U>(
164123
) as any;
165124
}
166125

126+
/**
127+
* Map from error codes to their corresponding SpacetimeError subclass.
128+
*/
129+
const errnoToClass = new Map<number, new (msg: string) => Error>();
130+
167131
export const errors = Object.freeze(
168-
mapEntries(errorData, (name, [code, message]) =>
169-
Object.defineProperty(
132+
mapEntries(errorData, (name, code) => {
133+
const cls = Object.defineProperty(
170134
class extends SpacetimeHostError {
171-
static CODE = code;
172-
static MESSAGE = message;
173-
constructor() {
174-
super(code);
135+
get name() {
136+
return name;
175137
}
176138
},
177139
'name',
178140
{ value: name, writable: false }
179-
)
180-
)
141+
);
142+
errnoToClass.set(code, cls);
143+
return cls;
144+
})
181145
);
182146

183-
/**
184-
* Set of prototypes of all SpacetimeError subclasses for quick lookup.
185-
*/
186-
const errorProtoypes = new Set(Object.values(errors).map(cls => cls.prototype));
187-
188-
/**
189-
* Map from error codes to their corresponding SpacetimeError subclass.
190-
*/
191-
const errnoToClass = new Map(
192-
Object.values(errors).map(cls => [cls.CODE as number, cls])
193-
);
147+
export function getErrorConstructor(code: number): new (msg: string) => Error {
148+
return errnoToClass.get(code) ?? SpacetimeHostError;
149+
}

crates/bindings-typescript/src/server/runtime.ts

Lines changed: 12 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ import { hasOwn, toCamelCase } from '../lib/util';
3636
import { type AnonymousViewCtx, type ViewCtx } from './views';
3737
import { isRowTypedQuery, makeQueryBuilder, toSql } from './query';
3838
import type { DbView } from './db_view';
39-
import { SenderError, SpacetimeHostError } from './errors';
39+
import { getErrorConstructor, SenderError } from './errors';
4040
import { Range, type Bound } from './range';
4141
import ViewResultHeader from '../lib/autogen/view_result_header_type';
4242
import { makeRandom, type Random } from './rng';
4343
import type { SchemaInner } from './schema';
4444

4545
const { freeze } = Object;
4646

47-
export const sys = freeze(wrapSyscalls(_syscalls2_0));
47+
export const sys = _syscalls2_0;
4848

4949
export function parseJsonObject(json: string): JsonObject {
5050
let value: unknown;
@@ -312,13 +312,21 @@ class ModuleHooksImpl implements ModuleHooks {
312312
return writer.getBuffer();
313313
}
314314

315+
__get_error_constructor__(code: number): new (msg: string) => Error {
316+
return getErrorConstructor(code);
317+
}
318+
319+
get __sender_error_class__() {
320+
return SenderError;
321+
}
322+
315323
__call_reducer__(
316324
reducerId: u32,
317325
sender: u256,
318326
connId: u128,
319327
timestamp: bigint,
320328
argsBuf: DataView
321-
): undefined | { tag: 'err'; value: string } {
329+
): void {
322330
const moduleCtx = this.#schema;
323331
const deserializeArgs = this.#reducerArgsDeserializers[reducerId];
324332
BINARY_READER.reset(argsBuf);
@@ -331,14 +339,7 @@ class ModuleHooksImpl implements ModuleHooks {
331339
new Timestamp(timestamp),
332340
ConnectionId.nullIfZero(new ConnectionId(connId))
333341
);
334-
try {
335-
callUserFunction(moduleCtx.reducers[reducerId], ctx, args);
336-
} catch (e) {
337-
if (e instanceof SenderError) {
338-
return { tag: 'err', value: e.message };
339-
}
340-
throw e;
341-
}
342+
callUserFunction(moduleCtx.reducers[reducerId], ctx, args);
342343
}
343344

344345
__call_view__(
@@ -906,51 +907,6 @@ class IteratorHandle implements Disposable {
906907
}
907908
}
908909

909-
type Intersections<Ts extends readonly any[]> = Ts extends [
910-
infer T,
911-
...infer Rest,
912-
]
913-
? T & Intersections<Rest>
914-
: unknown;
915-
916-
function wrapSyscalls<
917-
Modules extends Record<string, symbol | ((...args: any[]) => any)>[],
918-
>(...modules: Modules): Intersections<Modules> {
919-
return Object.fromEntries(
920-
modules
921-
.flatMap(Object.entries)
922-
.map(([k, v]) => [k, typeof v === 'function' ? wrapSyscall(v) : v])
923-
) as Intersections<Modules>;
924-
}
925-
926-
function wrapSyscall<F extends (...args: any[]) => any>(
927-
func: F
928-
): (...args: Parameters<F>) => ReturnType<F> {
929-
const name = func.name;
930-
return {
931-
[name](...args: Parameters<F>) {
932-
try {
933-
return func(...args);
934-
} catch (e) {
935-
if (
936-
e !== null &&
937-
typeof e === 'object' &&
938-
hasOwn(e, '__code_error__') &&
939-
typeof e.__code_error__ == 'number'
940-
) {
941-
const message =
942-
hasOwn(e, '__error_message__') &&
943-
typeof e.__error_message__ === 'string'
944-
? e.__error_message__
945-
: undefined;
946-
throw new SpacetimeHostError(e.__code_error__, message);
947-
}
948-
throw e;
949-
}
950-
},
951-
}[name];
952-
}
953-
954910
function fmtLog(...data: any[]) {
955911
return data.join(' ');
956912
}

crates/bindings-typescript/src/server/sys.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ declare module 'spacetime:sys@2.0' {
1515
export interface ModuleHooks {
1616
__describe_module__(): Uint8Array;
1717

18+
__get_error_constructor__(code: number): new (msg: string) => Error;
19+
__sender_error_class__: new (msg: string) => Error;
20+
1821
__call_reducer__(
1922
reducerId: u32,
2023
sender: u256,
2124
connId: u128,
2225
timestamp: bigint,
2326
argsBuf: DataView
24-
): undefined | { tag: 'ok' } | { tag: 'err'; value: string };
27+
): void;
2528

2629
__call_view__(id: u32, sender: u256, args: Uint8Array): Uint8Array | object;
2730

0 commit comments

Comments
 (0)