toilscript 0.1.56 → 0.1.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/web.js CHANGED
@@ -1,8 +1,8 @@
1
- var ASSEMBLYSCRIPT_VERSION = "0.1.56";
1
+ var ASSEMBLYSCRIPT_VERSION = "0.1.58";
2
2
  var ASSEMBLYSCRIPT_IMPORTMAP = {
3
3
  "imports": {
4
- "toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.56/dist/toilscript.js",
5
- "toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.56/dist/cli.js",
4
+ "toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.58/dist/toilscript.js",
5
+ "toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.58/dist/cli.js",
6
6
  "binaryen": "https://cdn.jsdelivr.net/npm/binaryen@130.0.0-nightly.20260609/index.js",
7
7
  "long": "https://cdn.jsdelivr.net/npm/long@5.3.2/index.js"
8
8
  }
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "toilscript",
9
9
  "wasm"
10
10
  ],
11
- "version": "0.1.56",
11
+ "version": "0.1.58",
12
12
  "author": "Daniel Wirtz <dcode+assemblyscript@dcode.io>",
13
13
  "license": "Apache-2.0",
14
14
  "homepage": "https://github.com/dacely-cloud/toilscript",
@@ -71,6 +71,20 @@ export namespace toildbHost {
71
71
  idemPtr: usize
72
72
  ): i32;
73
73
 
74
+ // record.upsert -> 0 created | 1 updated | 2 @unique-conflict (not written) |
75
+ // negative error. A single blind last-writer-wins put: creates the row if
76
+ // absent, overwrites it if present, in ONE op (no create-then-patch round trip).
77
+ // @ts-ignore: decorator
78
+ @external("env", "data.upsert")
79
+ export declare function upsert(
80
+ handle: u32,
81
+ keyPtr: usize,
82
+ keyLen: i32,
83
+ valPtr: usize,
84
+ valLen: i32,
85
+ idemPtr: usize
86
+ ): i32;
87
+
74
88
  // record.delete -> 0 ok | negative error.
75
89
  // @ts-ignore: decorator
76
90
  @external("env", "data.delete")
@@ -75,6 +75,18 @@ function __toildbTakeGrow(): Uint8Array {
75
75
  /// A mutable keyed-entity collection (spec 7.1). `V` is the `@data` value type,
76
76
  /// `K` the `@data` key type.
77
77
  @global
78
+ /// The outcome of `Documents.upsert` (spec 8.3). The wire bytes are pinned in the
79
+ /// host ABI (`data.upsert`): a non-negative tag the guest returns as-is.
80
+ export enum UpsertResult {
81
+ /// The row did not exist and was created.
82
+ Created = 0,
83
+ /// The row already existed and was overwritten.
84
+ Updated = 1,
85
+ /// A `@unique` field value is already owned by a DIFFERENT record; nothing was
86
+ /// written (the only outcome an upsert cannot auto-resolve).
87
+ Conflict = 2,
88
+ }
89
+
78
90
  export class Documents<K, V> {
79
91
  private __handle: u32;
80
92
 
@@ -158,6 +170,30 @@ export class Documents<K, V> {
158
170
  ) == 0;
159
171
  }
160
172
 
173
+ /// Create-or-overwrite in ONE op (spec 8.3): a blind last-writer-wins put that
174
+ /// creates the row if absent or overwrites it if present, replacing the two-op
175
+ /// `if (!create(k,v)) patch(k,v)` idiom. Returns `UpsertResult.Created` or
176
+ /// `.Updated`; on a `@unique` collection, `.Conflict` when the value's unique
177
+ /// field is already held by ANOTHER record (nothing is written).
178
+ ///
179
+ /// The write is blind: it stores `value` as-is, so concurrent upserts do not
180
+ /// conflict or retry - the later one wins and overwrites the earlier. Correct
181
+ /// for writing a whole value (a profile, a settings blob); wrong for a
182
+ /// read-modify-write of accumulating state (a balance, a like count), where a
183
+ /// concurrent write would be lost - use `counter.add` or version-checked
184
+ /// `patch` there. A lost write is a data-integrity concern, not a boundary one:
185
+ /// the key is tenant-scoped, so a race is only ever one tenant's own concurrent
186
+ /// writes, and `@unique` stays race-safe (claim-once at the value's home).
187
+ upsert(key: K, value: V): UpsertResult {
188
+ const kb = key.encode();
189
+ const vb = value.encode();
190
+ const status = toildbHost.upsert(
191
+ this.__handle, kb.dataStart, kb.byteLength, vb.dataStart, vb.byteLength, 0
192
+ );
193
+ if (status < 0) unreachable();
194
+ return <UpsertResult>status;
195
+ }
196
+
161
197
  /// Apply a write through the key's home cell; returns the stored record.
162
198
  patch(key: K, value: V): V {
163
199
  const kb = key.encode();
@@ -26,6 +26,15 @@ declare function main(): void;
26
26
  */
27
27
  declare function data(target: Function): void;
28
28
 
29
+ /**
30
+ * Marks a FIELD of a `@data` (or `@user`) class as globally unique: the compiler
31
+ * emits a per-field uniqueness constraint into the collection catalog so the edge
32
+ * can enforce it on write (via the `Unique` family). Field-level, unlike the class
33
+ * decorators above; applied bare on a `string` or `Uint8Array` field
34
+ * (`@unique email: string;`). Arrays and nested `@data` fields are not supported.
35
+ */
36
+ declare function unique(target: Object, propertyKey: string | symbol): void;
37
+
29
38
  /**
30
39
  * Marks a function (free, or a method of an `@service` class) as a client-callable
31
40
  * RPC endpoint. The server build emits it onto the typed client `Server` surface.
@@ -220,6 +229,16 @@ declare function admin(target: Object, propertyKey: string | symbol, descriptor:
220
229
  // User>` and `App.users.get(...)`. Every handle is KEY-FIRST (`<K, V>`, matching
221
230
  // `Map`/`Record`). `K`/`V`/`M` are `@data` types (the codec the host marshals).
222
231
 
232
+ /** The outcome of `Documents.upsert` (spec 8.3). */
233
+ declare const enum UpsertResult {
234
+ /** The row did not exist and was created. */
235
+ Created = 0,
236
+ /** The row already existed and was overwritten. */
237
+ Updated = 1,
238
+ /** A `@unique` field value is already owned by another record; nothing written. */
239
+ Conflict = 2,
240
+ }
241
+
223
242
  /** A mutable keyed-entity collection (spec 7.1): user profiles, items, sessions. */
224
243
  declare class Documents<K, V> {
225
244
  get(key: K): V | null;
@@ -228,6 +247,13 @@ declare class Documents<K, V> {
228
247
  getMany(keys: K[]): (V | null)[];
229
248
  create(key: K, value: V): bool;
230
249
  patch(key: K, value: V): V;
250
+ /** Create-or-overwrite in one op (blind last-writer-wins); replaces the two-op
251
+ * `if (!create(k,v)) patch(k,v)` idiom. Right for writing a whole value; wrong
252
+ * for read-modify-write of accumulating state (a balance/count), where a
253
+ * concurrent write would be lost - use `counter.add` or version-checked
254
+ * `patch` there. The key is tenant-scoped, so a race is only ever the same
255
+ * tenant's own writes. See {@link UpsertResult}. */
256
+ upsert(key: K, value: V): UpsertResult;
231
257
  delete(key: K): void;
232
258
  getDelete(key: K): V | null;
233
259
  }