@@ -8,11 +8,11 @@ use core::mem::MaybeUninit;
8
8
use core:: num:: NonZeroU16 ;
9
9
use std:: ptr;
10
10
11
- use spacetimedb_primitives:: { errno, errnos, ColId , TableId } ;
11
+ use spacetimedb_primitives:: { errno, errnos, ColId , IndexId , TableId } ;
12
12
13
13
/// Provides a raw set of sys calls which abstractions can be built atop of.
14
14
pub mod raw {
15
- use spacetimedb_primitives:: { ColId , TableId } ;
15
+ use spacetimedb_primitives:: { ColId , IndexId , TableId } ;
16
16
17
17
// this module identifier determines the abi version that modules built with this crate depend
18
18
// on. Any non-breaking additions to the abi surface should be put in a new `extern {}` block
@@ -40,6 +40,26 @@ pub mod raw {
40
40
/// - `NO_SUCH_TABLE`, when `name` is not the name of a table.
41
41
pub fn _table_id_from_name ( name : * const u8 , name_len : usize , out : * mut TableId ) -> u16 ;
42
42
43
+ /// Queries the `index_id` associated with the given (index) `name`
44
+ /// where `name` is the UTF-8 slice in WASM memory at `name_ptr[..name_len]`.
45
+ ///
46
+ /// The index id is written into the `out` pointer.
47
+ ///
48
+ /// # Traps
49
+ ///
50
+ /// Traps if:
51
+ /// - `name_ptr` is NULL or `name` is not in bounds of WASM memory.
52
+ /// - `name` is not valid UTF-8.
53
+ /// - `out` is NULL or `out[..size_of::<IndexId>()]` is not in bounds of WASM memory.
54
+ ///
55
+ /// # Errors
56
+ ///
57
+ /// Returns an error:
58
+ ///
59
+ /// - `NOT_IN_TRANSACTION`, when called outside of a transaction.
60
+ /// - `NO_SUCH_INDEX`, when `name` is not the name of an index.
61
+ pub fn _index_id_from_name ( name_ptr : * const u8 , name_len : usize , out : * mut IndexId ) -> u16 ;
62
+
43
63
/// Writes the number of rows currently in table identified by `table_id` to `out`.
44
64
///
45
65
/// # Traps
@@ -72,6 +92,80 @@ pub mod raw {
72
92
/// - `NO_SUCH_TABLE`, when `table_id` is not a known ID of a table.
73
93
pub fn _datastore_table_scan_bsatn ( table_id : TableId , out : * mut RowIter ) -> u16 ;
74
94
95
+ /// Finds all rows in the index identified by `index_id`,
96
+ /// according to the:
97
+ /// - `prefix = prefix_ptr[..prefix_len]`,
98
+ /// - `rstart = rstart_ptr[..rstart_len]`,
99
+ /// - `rend = rend_ptr[..rend_len]`,
100
+ /// in WASM memory.
101
+ ///
102
+ /// The index itself has a schema/type.
103
+ /// The `prefix` is decoded to the initial `prefix_elems` `AlgebraicType`s
104
+ /// whereas `rstart` and `rend` are decoded to the `prefix_elems + 1` `AlgebraicType`
105
+ /// where the `AlgebraicValue`s are wrapped in `Bound`.
106
+ /// That is, `rstart, rend` are BSATN-encoded `Bound<AlgebraicValue>`s.
107
+ ///
108
+ /// Matching is then defined by equating `prefix`
109
+ /// to the initial `prefix_elems` columns of the index
110
+ /// and then imposing `rstart` as the starting bound
111
+ /// and `rend` as the ending bound on the `prefix_elems + 1` column of the index.
112
+ /// Remaining columns of the index are then unbounded.
113
+ /// Note that the `prefix` in this case can be empty (`prefix_elems = 0`),
114
+ /// in which case this becomes a ranged index scan on a single-col index
115
+ /// or even a full table scan if `rstart` and `rend` are both unbounded.
116
+ ///
117
+ /// The relevant table for the index is found implicitly via the `index_id`,
118
+ /// which is unique for the module.
119
+ ///
120
+ /// On success, the iterator handle is written to the `out` pointer.
121
+ /// This handle can be advanced by [`row_iter_bsatn_advance`].
122
+ ///
123
+ /// # Non-obvious queries
124
+ ///
125
+ /// For an index on columns `[a, b, c]`:
126
+ ///
127
+ /// - `a = x, b = y` is encoded as a prefix `[x, y]`
128
+ /// and a range `Range::Unbounded`,
129
+ /// or as a prefix `[x]` and a range `rstart = rend = Range::Inclusive(y)`.
130
+ /// - `a = x, b = y, c = z` is encoded as a prefix `[x, y]`
131
+ /// and a range `rstart = rend = Range::Inclusive(z)`.
132
+ /// - A sorted full scan is encoded as an empty prefix
133
+ /// and a range `Range::Unbounded`.
134
+ ///
135
+ /// # Traps
136
+ ///
137
+ /// Traps if:
138
+ /// - `prefix_elems > 0`
139
+ /// and (`prefix_ptr` is NULL or `prefix` is not in bounds of WASM memory).
140
+ /// - `rstart` is NULL or `rstart` is not in bounds of WASM memory.
141
+ /// - `rend` is NULL or `rend` is not in bounds of WASM memory.
142
+ /// - `out` is NULL or `out[..size_of::<RowIter>()]` is not in bounds of WASM memory.
143
+ ///
144
+ /// # Errors
145
+ ///
146
+ /// Returns an error:
147
+ ///
148
+ /// - `NOT_IN_TRANSACTION`, when called outside of a transaction.
149
+ /// - `NO_SUCH_INDEX`, when `index_id` is not a known ID of an index.
150
+ /// - `WRONG_INDEX_ALGO` if the index is not a btree index.
151
+ /// - `BSATN_DECODE_ERROR`, when `prefix` cannot be decoded to
152
+ /// a `prefix_elems` number of `AlgebraicValue`
153
+ /// typed at the initial `prefix_elems` `AlgebraicType`s of the index's key type.
154
+ /// Or when `rstart` or `rend` cannot be decoded to an `Bound<AlgebraicValue>`
155
+ /// where the inner `AlgebraicValue`s are
156
+ /// typed at the `prefix_elems + 1` `AlgebraicType` of the index's key type.
157
+ pub fn _datastore_btree_scan_bsatn (
158
+ index_id : IndexId ,
159
+ prefix_ptr : * const u8 ,
160
+ prefix_len : usize ,
161
+ prefix_elems : ColId ,
162
+ rstart_ptr : * const u8 , // Bound<AlgebraicValue>
163
+ rstart_len : usize ,
164
+ rend_ptr : * const u8 , // Bound<AlgebraicValue>
165
+ rend_len : usize ,
166
+ out : * mut RowIter ,
167
+ ) -> u16 ;
168
+
75
169
/// Finds all rows in the table identified by `table_id`,
76
170
/// where the row has a column, identified by `col_id`,
77
171
/// with data matching the byte string, in WASM memory, pointed to at by `val`.
@@ -597,12 +691,28 @@ unsafe fn call<T: Copy>(f: impl FnOnce(*mut T) -> u16) -> Result<T, Errno> {
597
691
///
598
692
/// Returns an error:
599
693
///
694
+ /// - `NOT_IN_TRANSACTION`, when called outside of a transaction.
600
695
/// - `NO_SUCH_TABLE`, when `name` is not the name of a table.
601
696
#[ inline]
602
697
pub fn table_id_from_name ( name : & str ) -> Result < TableId , Errno > {
603
698
unsafe { call ( |out| raw:: _table_id_from_name ( name. as_ptr ( ) , name. len ( ) , out) ) }
604
699
}
605
700
701
+ /// Queries the `index_id` associated with the given (index) `name`.
702
+ ///
703
+ /// The index id is returned.
704
+ ///
705
+ /// # Errors
706
+ ///
707
+ /// Returns an error:
708
+ ///
709
+ /// - `NOT_IN_TRANSACTION`, when called outside of a transaction.
710
+ /// - `NO_SUCH_INDEX`, when `name` is not the name of an index.
711
+ #[ inline]
712
+ pub fn index_id_from_name ( name : & str ) -> Result < IndexId , Errno > {
713
+ unsafe { call ( |out| raw:: _index_id_from_name ( name. as_ptr ( ) , name. len ( ) , out) ) }
714
+ }
715
+
606
716
/// Returns the number of rows currently in table identified by `table_id`.
607
717
///
608
718
/// # Errors
@@ -714,6 +824,80 @@ pub fn datastore_table_scan_bsatn(table_id: TableId) -> Result<RowIter, Errno> {
714
824
Ok ( RowIter { raw } )
715
825
}
716
826
827
+ /// Finds all rows in the index identified by `index_id`,
828
+ /// according to the `prefix`, `rstart`, and `rend`.
829
+ ///
830
+ /// The index itself has a schema/type.
831
+ /// The `prefix` is decoded to the initial `prefix_elems` `AlgebraicType`s
832
+ /// whereas `rstart` and `rend` are decoded to the `prefix_elems + 1` `AlgebraicType`
833
+ /// where the `AlgebraicValue`s are wrapped in `Bound`.
834
+ /// That is, `rstart, rend` are BSATN-encoded `Bound<AlgebraicValue>`s.
835
+ ///
836
+ /// Matching is then defined by equating `prefix`
837
+ /// to the initial `prefix_elems` columns of the index
838
+ /// and then imposing `rstart` as the starting bound
839
+ /// and `rend` as the ending bound on the `prefix_elems + 1` column of the index.
840
+ /// Remaining columns of the index are then unbounded.
841
+ /// Note that the `prefix` in this case can be empty (`prefix_elems = 0`),
842
+ /// in which case this becomes a ranged index scan on a single-col index
843
+ /// or even a full table scan if `rstart` and `rend` are both unbounded.
844
+ ///
845
+ /// The relevant table for the index is found implicitly via the `index_id`,
846
+ /// which is unique for the module.
847
+ ///
848
+ /// On success, the iterator handle is written to the `out` pointer.
849
+ /// This handle can be advanced by [`row_iter_bsatn_advance`].
850
+ ///
851
+ /// # Non-obvious queries
852
+ ///
853
+ /// For an index on columns `[a, b, c]`:
854
+ ///
855
+ /// - `a = x, b = y` is encoded as a prefix `[x, y]`
856
+ /// and a range `Range::Unbounded`,
857
+ /// or as a prefix `[x]` and a range `rstart = rend = Range::Inclusive(y)`.
858
+ /// - `a = x, b = y, c = z` is encoded as a prefix `[x, y]`
859
+ /// and a range `rstart = rend = Range::Inclusive(z)`.
860
+ /// - A sorted full scan is encoded as an empty prefix
861
+ /// and a range `Range::Unbounded`.
862
+ ///
863
+ /// # Errors
864
+ ///
865
+ /// Returns an error:
866
+ ///
867
+ /// - `NOT_IN_TRANSACTION`, when called outside of a transaction.
868
+ /// - `NO_SUCH_INDEX`, when `index_id` is not a known ID of an index.
869
+ /// - `WRONG_INDEX_ALGO` if the index is not a btree index.
870
+ /// - `BSATN_DECODE_ERROR`, when `prefix` cannot be decoded to
871
+ /// a `prefix_elems` number of `AlgebraicValue`
872
+ /// typed at the initial `prefix_elems` `AlgebraicType`s of the index's key type.
873
+ /// Or when `rstart` or `rend` cannot be decoded to an `Bound<AlgebraicValue>`
874
+ /// where the inner `AlgebraicValue`s are
875
+ /// typed at the `prefix_elems + 1` `AlgebraicType` of the index's key type.
876
+ pub fn datastore_btree_scan_bsatn (
877
+ index_id : IndexId ,
878
+ prefix : & [ u8 ] ,
879
+ prefix_elems : ColId ,
880
+ rstart : & [ u8 ] ,
881
+ rend : & [ u8 ] ,
882
+ ) -> Result < RowIter , Errno > {
883
+ let raw = unsafe {
884
+ call ( |out| {
885
+ raw:: _datastore_btree_scan_bsatn (
886
+ index_id,
887
+ prefix. as_ptr ( ) ,
888
+ prefix. len ( ) ,
889
+ prefix_elems,
890
+ rstart. as_ptr ( ) ,
891
+ rstart. len ( ) ,
892
+ rend. as_ptr ( ) ,
893
+ rend. len ( ) ,
894
+ out,
895
+ )
896
+ } ) ?
897
+ } ;
898
+ Ok ( RowIter { raw } )
899
+ }
900
+
717
901
/// Iterate through a table, filtering by an encoded `spacetimedb_lib::filter::Expr`.
718
902
///
719
903
/// # Errors
0 commit comments