From 5eeaf4948d8378ff42098f7bf257fbd072d64e3c Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Thu, 13 Nov 2025 00:31:51 +0100 Subject: [PATCH 1/8] Snapshot 2025-11-12T24:30:00 First draft of db cursor refinement. Expect this commit to VANISH in the future. --- docs/scripting/db/cursor/array.mdx | 31 ++++++++++ docs/scripting/db/cursor/close.mdx | 31 ++++++++++ docs/scripting/db/cursor/count.mdx | 33 +++++++++++ docs/scripting/db/cursor/distinct.mdx | 35 ++++++++++++ docs/scripting/db/cursor/first.mdx | 56 +++++++++++++++++++ .../db/cursor/first_and_keep_open.mdx | 42 ++++++++++++++ docs/scripting/db/cursor/index.mdx | 55 ++++++++++++++++++ docs/scripting/db/cursor/limit.mdx | 25 +++++++++ docs/scripting/db/cursor/skip.mdx | 25 +++++++++ 9 files changed, 333 insertions(+) create mode 100644 docs/scripting/db/cursor/array.mdx create mode 100644 docs/scripting/db/cursor/close.mdx create mode 100644 docs/scripting/db/cursor/count.mdx create mode 100644 docs/scripting/db/cursor/distinct.mdx create mode 100644 docs/scripting/db/cursor/first.mdx create mode 100644 docs/scripting/db/cursor/first_and_keep_open.mdx create mode 100644 docs/scripting/db/cursor/index.mdx create mode 100644 docs/scripting/db/cursor/limit.mdx create mode 100644 docs/scripting/db/cursor/skip.mdx diff --git a/docs/scripting/db/cursor/array.mdx b/docs/scripting/db/cursor/array.mdx new file mode 100644 index 00000000..762a3390 --- /dev/null +++ b/docs/scripting/db/cursor/array.mdx @@ -0,0 +1,31 @@ +--- +title: array(_and_close) +alias: array_and_close +--- + +Retrieve all documents of the cursor, and close it. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.array() +``` + +or +``` +let cursor = #db.f(query, projection) +cursor.array_and_close() +``` + +### Parameters + +No parameters. + +### Return + +Returns all documents from the cursor, as an array of objects. + +## Cursor State + +This function closes the cursor. If this is undesirable, try [array_and_keep_open](./array_and_keep_open). diff --git a/docs/scripting/db/cursor/close.mdx b/docs/scripting/db/cursor/close.mdx new file mode 100644 index 00000000..da421f39 --- /dev/null +++ b/docs/scripting/db/cursor/close.mdx @@ -0,0 +1,31 @@ +Close the cursor. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.close() +``` + +### Parameters + +No parameters. + +### Return + +Always returns ((%Vnull%)). + +## Cursor State + +This function closes the cursor. + +## Example + +```js +function(context, args) { + let cursor = #db.f({ type: "my_data" }); + + // removing the following line causes an error: + cursor.close(); +} +``` diff --git a/docs/scripting/db/cursor/count.mdx b/docs/scripting/db/cursor/count.mdx new file mode 100644 index 00000000..ebcede91 --- /dev/null +++ b/docs/scripting/db/cursor/count.mdx @@ -0,0 +1,33 @@ +--- +title: count(_and_close) +alias: count_and_close +--- + +Retrieve the total number of documents of the cursor, and close it. + +This method ignores `skip` and `limit` settings. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.count() +``` + +or +``` +let cursor = #db.f(query, projection) +cursor.count_and_close() +``` + +### Parameters + +No parameters. + +### Return + +The total number of documents of this cursor, as a number. + +## Cursor State + +This function closes the cursor. If this is undesirable, try [count_and_keep_open](./count_and_keep_open). diff --git a/docs/scripting/db/cursor/distinct.mdx b/docs/scripting/db/cursor/distinct.mdx new file mode 100644 index 00000000..ce90c8b6 --- /dev/null +++ b/docs/scripting/db/cursor/distinct.mdx @@ -0,0 +1,35 @@ +--- +title: distinct(_and_close) +alias: distinct_and_close +--- + +Retrieve the unique values of a given field for all documents of the cursor, and close it. + +This method ignores `skip` and `limit` settings. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.distinct(field) +``` + +or +``` +let cursor = #db.f(query, projection) +cursor.distinct_and_close(field) +``` + +### Parameters + +#### field + +A string naming the field to pull unique values from. + +### Return + +The unique values of the given field from all documents of the cursor, as an array. + +## Cursor State + +This function closes the cursor. If this is undesirable, try [distinct_and_keep_open](./distinct_and_keep_open). diff --git a/docs/scripting/db/cursor/first.mdx b/docs/scripting/db/cursor/first.mdx new file mode 100644 index 00000000..1cb73853 --- /dev/null +++ b/docs/scripting/db/cursor/first.mdx @@ -0,0 +1,56 @@ +--- +title: first(_and_close) +alias: first_and_close +--- + +Retrieve the first document of the cursor, and close it. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.first() +``` + +or +``` +let cursor = #db.f(query, projection) +cursor.first_and_close() +``` + +### Parameters + +No parameters. + +### Return + +Returns the first document from the cursor as an object. +If the cursor is empty, returns ((%Vnull%)). + +## Cursor State + +This function closes the cursor. If this is undesirable, try [first_and_keep_open](./first_and_keep_open). + +## Example + +For the following examples, assume the database contains the following documents, inserted in that order: +``` +{ type: "my_data", my_key: "foo", order: 2 } +{ type: "my_data", my_key: "bar", order: 1 } +``` + +```js +function(context, args) { + let data = #db.f({ type: "my_data" }).first(); + return data; // { type: "my_data", my_key: "foo", order: 2 } +} +``` + +```js +function(context, args) { + let data = #db.f({ type: "my_data" }).sort({ order: 1 }).first(); + return data; // { type: "my_data", my_key: "bar", order: 1 } +} +``` + + diff --git a/docs/scripting/db/cursor/first_and_keep_open.mdx b/docs/scripting/db/cursor/first_and_keep_open.mdx new file mode 100644 index 00000000..c10fc520 --- /dev/null +++ b/docs/scripting/db/cursor/first_and_keep_open.mdx @@ -0,0 +1,42 @@ + +Retrieve the first document of the cursor, keeping it open. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.first_and_keep_open() +// continue using `cursor`... +``` + +### Parameters + +No parameters. + +### Return + +Returns the first document from the cursor as an object. +If the cursor is empty, returns ((%Vnull%)). + +## Cursor State + +This function keeps the cursor open. + +Try [first](./first) for a variant of this function that automatically closes the cursor. + +## Example + +For the following example, assume the database contains the following documents, inserted in that order: +``` +{ type: "my_data", my_key: "foo", order: 2 } +{ type: "my_data", my_key: "bar", order: 1 } +``` + +```js +function(context, args) { + let cursor = #db.f({ type: "my_data" }); + let a = cursor.skip(1).first_and_keep_open(); + let b = cursor.skip(0).first_and_close(); + return [ a.my_key, b.my_key ]; // [ "bar", "foo" ] +} +``` diff --git a/docs/scripting/db/cursor/index.mdx b/docs/scripting/db/cursor/index.mdx new file mode 100644 index 00000000..3302aab1 --- /dev/null +++ b/docs/scripting/db/cursor/index.mdx @@ -0,0 +1,55 @@ +--- +title: Cursors +sidebar_collapsible: true +sidebar_collapsed: true +--- + +Database cursors are special objects returned from [#db.f(..)](../db.f). + +## Usage + +Cursors are exclusively returned from #db.f(..): + +``` +let cursor = #db.f(query, projection) +``` + +A cursor _MUST_ be closed before the script run finishes, otherwise the following error occurs: + +> `:::TRUST COMMUNICATION::: 1 db cursors were left open at end of script run` + +Cursors can be closed via the [close](./close) method, or by using a terminating method such as [`first`](./first). + +After a cursor is closed, it can no longer be used. Subsequent attempts to use the cursor result in the following error: + +> `:::TRUST COMMUNICATION::: cursor was invalid. this can happen if it was used after being closed` + +### Cursor Handles + +((%FTODO: Write something that people who have never used a file descriptor in their life can understand.%)) + +
+Technical details + +A cursor is a wrapper object around a _"cursor handle"_. +`#db.f` always returns a cursor with a new, unique "cursor handle". + +Multiple cursor objects can refer to the same "cursor handle". +See [skip](./skip) for a method that causes this to happen. + +When _any_ cursor with a given "cursor handle" is closed, _all_ cursors for that "cursor handle" become invalid. +(You only need to close one cursor for each "cursor handle" to avoid the 'cursors were left open' error.) + +Cursor objects that use the same "cursor handle" are nevertheless separate objects, and do not compare equal. + +Note that your code will never interact with a "cursor handle" directly, only with cursor objects. + +
+ +## Methods + +The following is an auto-generated list of cursor methods: + +import DocCardList from '@theme/DocCardList'; + + diff --git a/docs/scripting/db/cursor/limit.mdx b/docs/scripting/db/cursor/limit.mdx new file mode 100644 index 00000000..d52c36fa --- /dev/null +++ b/docs/scripting/db/cursor/limit.mdx @@ -0,0 +1,25 @@ +Set the limit of the cursor. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.limit(count) +``` + +### Parameters + +#### count + +The maximum number of results to return. +If this parameter is `0`, the limit is removed. + +### Return + +Returns a new cursor, with the same handle as the input cursor. + +This can be used to chain into other methods. + +## Cursor State + +This function keeps the cursor open. diff --git a/docs/scripting/db/cursor/skip.mdx b/docs/scripting/db/cursor/skip.mdx new file mode 100644 index 00000000..940cb716 --- /dev/null +++ b/docs/scripting/db/cursor/skip.mdx @@ -0,0 +1,25 @@ +Set the skip count of the cursor. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.skip(skip) +``` + +### Parameters + +#### skip + +The number of results to skip. +Note that this is not cumulative; `cursor.skip(5).skip(1)` will skip 1 document, not 6. + +### Return + +Returns a new cursor, with the same handle as the input cursor. + +This can be used to chain into other methods. + +## Cursor State + +This function keeps the cursor open. From 16a80630e3488174541399ce3942585c205d1cde Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Tue, 16 Dec 2025 23:33:43 +0100 Subject: [PATCH 2/8] Add page for the each family --- docs/scripting/db/cursor/each.mdx | 34 +++++++++++++++++++ .../db/cursor/each_and_keep_open.mdx | 24 +++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 docs/scripting/db/cursor/each.mdx create mode 100644 docs/scripting/db/cursor/each_and_keep_open.mdx diff --git a/docs/scripting/db/cursor/each.mdx b/docs/scripting/db/cursor/each.mdx new file mode 100644 index 00000000..0f04960a --- /dev/null +++ b/docs/scripting/db/cursor/each.mdx @@ -0,0 +1,34 @@ +--- +title: each(_and_close) +alias: each_and_close +--- + +Call a function on all documents of the cursor, and close it. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.each(fn) +``` + +or + +``` +let cursor = #db.f(query, projection) +cursor.each_and_close(fn) +``` + +### Parameters + +#### fn + +The function to call. This function is called once per document, with the document passed as the only argument. + +### Return + +Always returns ((%Vundefined%)). + +## Cursor state + +This function closes the cursor. If this is undesirable, try [each_and_keep_open](./each_and_keep_open). diff --git a/docs/scripting/db/cursor/each_and_keep_open.mdx b/docs/scripting/db/cursor/each_and_keep_open.mdx new file mode 100644 index 00000000..5783726e --- /dev/null +++ b/docs/scripting/db/cursor/each_and_keep_open.mdx @@ -0,0 +1,24 @@ +Call a function on all documents of the cursor, keeping it open. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.each_and_keep_open(fn) +``` + +### Parameters + +#### fn + +The function to call. This function is called once per document, with the document passed as the only argument. + +### Return + +Always returns ((%Vundefined%)). + +## Cursor state + +This function keeps the cursor open. + +Try [each](./each) for a variant of this function that automatically closes the cursor. From 7916a101d287604315bd37c06d03690beecf1c7f Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Tue, 16 Dec 2025 23:38:06 +0100 Subject: [PATCH 3/8] Add page for distinct_and_keep_open --- .../db/cursor/distinct_and_keep_open.mdx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 docs/scripting/db/cursor/distinct_and_keep_open.mdx diff --git a/docs/scripting/db/cursor/distinct_and_keep_open.mdx b/docs/scripting/db/cursor/distinct_and_keep_open.mdx new file mode 100644 index 00000000..613a5ffc --- /dev/null +++ b/docs/scripting/db/cursor/distinct_and_keep_open.mdx @@ -0,0 +1,26 @@ +Retrieve the unique values of a given field for all documents of the cursor, keeping it open. + +This method ignores `skip` and `limit` settings. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.distinct_and_keep_open(field) +``` + +### Parameters + +#### field + +A string naming the field to pull unique values from. + +### Return + +The unique values of the given field from all documents of the cursor, as an array. + +## Cursor State + +This function keeps the cursor open. + +Try [distinct](./distinct) for a variant of this function that automatically closes the cursor. From 2e877ccedd479cc9d0d1bc7ad92d25574f2fafac Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Wed, 17 Dec 2025 00:00:11 +0100 Subject: [PATCH 4/8] Add page for count_and_keep_open --- .../db/cursor/count_and_keep_open.mdx | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 docs/scripting/db/cursor/count_and_keep_open.mdx diff --git a/docs/scripting/db/cursor/count_and_keep_open.mdx b/docs/scripting/db/cursor/count_and_keep_open.mdx new file mode 100644 index 00000000..ece5abe2 --- /dev/null +++ b/docs/scripting/db/cursor/count_and_keep_open.mdx @@ -0,0 +1,24 @@ +Retrieve the total number of documents of the cursor, keeping it open. + +This method ignores `skip` and `limit` settings. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.count_and_keep_open() +``` + +### Parameters + +No parameters. + +### Return + +The total number of documents of this cursor, as a number. + +## Cursor State + +This function keeps the cursor open. + +Try [count](./count) for a variant of this function that automatically closes the cursor. From 951c5d3b9bd5a29273683737410db0ece09d62fa Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Wed, 17 Dec 2025 00:18:44 +0100 Subject: [PATCH 5/8] Add page for sort --- docs/scripting/db/cursor/sort.mdx | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/scripting/db/cursor/sort.mdx diff --git a/docs/scripting/db/cursor/sort.mdx b/docs/scripting/db/cursor/sort.mdx new file mode 100644 index 00000000..ed3f65e1 --- /dev/null +++ b/docs/scripting/db/cursor/sort.mdx @@ -0,0 +1,27 @@ +Set the sort order of the cursor. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.sort(sort) +``` + +### Parameters + +#### sort + +An object specifying the sort order, e.g. (( \{ n_hits: 1, n_fails: -1 \} )). +Each key is the path of a sort key, each value specifies direction (((%V1%)) for ascending, ((%V-1%)) for descending). + +Note that the order of keys in the object matters. + +### Return + +Returns a new cursor, with the same handle as the input cursor. + +This can be used to chain into other methods. + +## Cursor State + +This function keeps the cursor open. From 1945e7a242bd077126858985eb1beb89e1bfec03 Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Wed, 17 Dec 2025 00:43:50 +0100 Subject: [PATCH 6/8] Add idempotent notice to cursor.close --- docs/scripting/db/cursor/close.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/scripting/db/cursor/close.mdx b/docs/scripting/db/cursor/close.mdx index da421f39..88db6326 100644 --- a/docs/scripting/db/cursor/close.mdx +++ b/docs/scripting/db/cursor/close.mdx @@ -1,5 +1,8 @@ Close the cursor. +This method is ((%Fidempotent%)): +calling it multiple times results in identical behavior to calling it once. + ## Syntax ``` From 532703b525af10ae554606a4c4511d4610067024 Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Wed, 17 Dec 2025 00:58:53 +0100 Subject: [PATCH 7/8] Add page for array_and_keep_open --- .../db/cursor/array_and_keep_open.mdx | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/scripting/db/cursor/array_and_keep_open.mdx diff --git a/docs/scripting/db/cursor/array_and_keep_open.mdx b/docs/scripting/db/cursor/array_and_keep_open.mdx new file mode 100644 index 00000000..f2f79282 --- /dev/null +++ b/docs/scripting/db/cursor/array_and_keep_open.mdx @@ -0,0 +1,22 @@ +Retrieve all documents of the cursor, keeping it open. + +## Syntax + +``` +let cursor = #db.f(query, projection) +cursor.array_and_keep_open() +``` + +### Parameters + +No parameters. + +### Return + +Returns all documents from the cursor, as an array of objects. + +## Cursor State + +This function keeps the cursor open. + +Try [array](./array) for a variant of this function that automatically closes the cursor. From 40a60016c4a4f3109eecdb1cc0f794a149a9498f Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Wed, 17 Dec 2025 01:04:13 +0100 Subject: [PATCH 8/8] Run a prettier pass --- docs/scripting/db/cursor/array.mdx | 1 + docs/scripting/db/cursor/count.mdx | 1 + docs/scripting/db/cursor/distinct.mdx | 1 + docs/scripting/db/cursor/first.mdx | 4 ++-- docs/scripting/db/cursor/first_and_keep_open.mdx | 2 +- docs/scripting/db/cursor/index.mdx | 2 +- 6 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/scripting/db/cursor/array.mdx b/docs/scripting/db/cursor/array.mdx index 762a3390..af31bb8b 100644 --- a/docs/scripting/db/cursor/array.mdx +++ b/docs/scripting/db/cursor/array.mdx @@ -13,6 +13,7 @@ cursor.array() ``` or + ``` let cursor = #db.f(query, projection) cursor.array_and_close() diff --git a/docs/scripting/db/cursor/count.mdx b/docs/scripting/db/cursor/count.mdx index ebcede91..b8b7d02b 100644 --- a/docs/scripting/db/cursor/count.mdx +++ b/docs/scripting/db/cursor/count.mdx @@ -15,6 +15,7 @@ cursor.count() ``` or + ``` let cursor = #db.f(query, projection) cursor.count_and_close() diff --git a/docs/scripting/db/cursor/distinct.mdx b/docs/scripting/db/cursor/distinct.mdx index ce90c8b6..3d9acf60 100644 --- a/docs/scripting/db/cursor/distinct.mdx +++ b/docs/scripting/db/cursor/distinct.mdx @@ -15,6 +15,7 @@ cursor.distinct(field) ``` or + ``` let cursor = #db.f(query, projection) cursor.distinct_and_close(field) diff --git a/docs/scripting/db/cursor/first.mdx b/docs/scripting/db/cursor/first.mdx index 1cb73853..9f4f3f0a 100644 --- a/docs/scripting/db/cursor/first.mdx +++ b/docs/scripting/db/cursor/first.mdx @@ -13,6 +13,7 @@ cursor.first() ``` or + ``` let cursor = #db.f(query, projection) cursor.first_and_close() @@ -34,6 +35,7 @@ This function closes the cursor. If this is undesirable, try [first_and_keep_ope ## Example For the following examples, assume the database contains the following documents, inserted in that order: + ``` { type: "my_data", my_key: "foo", order: 2 } { type: "my_data", my_key: "bar", order: 1 } @@ -52,5 +54,3 @@ function(context, args) { return data; // { type: "my_data", my_key: "bar", order: 1 } } ``` - - diff --git a/docs/scripting/db/cursor/first_and_keep_open.mdx b/docs/scripting/db/cursor/first_and_keep_open.mdx index c10fc520..21ea3af1 100644 --- a/docs/scripting/db/cursor/first_and_keep_open.mdx +++ b/docs/scripting/db/cursor/first_and_keep_open.mdx @@ -1,4 +1,3 @@ - Retrieve the first document of the cursor, keeping it open. ## Syntax @@ -27,6 +26,7 @@ Try [first](./first) for a variant of this function that automatically closes th ## Example For the following example, assume the database contains the following documents, inserted in that order: + ``` { type: "my_data", my_key: "foo", order: 2 } { type: "my_data", my_key: "bar", order: 1 } diff --git a/docs/scripting/db/cursor/index.mdx b/docs/scripting/db/cursor/index.mdx index 3302aab1..fe6acecc 100644 --- a/docs/scripting/db/cursor/index.mdx +++ b/docs/scripting/db/cursor/index.mdx @@ -50,6 +50,6 @@ Note that your code will never interact with a "cursor handle" directly, only wi The following is an auto-generated list of cursor methods: -import DocCardList from '@theme/DocCardList'; +import DocCardList from "@theme/DocCardList";