@reventlessdev/reventless-core 3.0.0-alpha.141 → 3.0.0-alpha.143

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/CHANGELOG.md CHANGED
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.143 (2026-07-06)
7
+
8
+ ### Features
9
+
10
+ * **reventless-aws:** classic EventLog Postgres deploy-time wiring + relay (B1 vertical) ([8235ba4](https://github.com/ReventlessDev/reventless-core/commit/8235ba44e506f7094d17251405c6a05c39789805))
11
+
12
+
13
+ # 3.0.0-alpha.142 (2026-07-05)
14
+
15
+ **Note:** Version bump only for package @reventlessdev/reventless-core
16
+
17
+
18
+
19
+
20
+
6
21
  # 3.0.0-alpha.141 (2026-07-05)
7
22
 
8
23
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-core",
3
- "version": "3.0.0-alpha.141",
3
+ "version": "3.0.0-alpha.143",
4
4
  "description": "Core package for Reventless framework",
5
5
  "license": "Apache-2.0",
6
6
  "jest": {
@@ -28,17 +28,17 @@
28
28
  "dependencies": {
29
29
  "sury": "11.0.0-alpha.4",
30
30
  "uuid": "^13.0.0",
31
- "@reventlessdev/rescript-effect": "0.1.0-alpha.24",
31
+ "@reventlessdev/rescript-effect": "0.1.0-alpha.25",
32
32
  "@reventlessdev/rescript-fast-csv": "1.2.0-alpha.11",
33
33
  "@reventlessdev/rescript-hash-object": "1.2.0-alpha.10",
34
- "@reventlessdev/rescript-jest": "1.0.0-alpha.5",
35
34
  "@reventlessdev/rescript-node-streams": "1.1.0-alpha.10",
35
+ "@reventlessdev/rescript-jest": "1.0.0-alpha.6",
36
36
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.14",
37
- "@reventlessdev/rescript-ssh2": "1.1.0-alpha.11",
38
- "@reventlessdev/rescript-uuid": "1.1.0-alpha.13",
39
- "@reventlessdev/reventless-interop": "3.0.0-alpha.23",
40
- "@reventlessdev/reventless-spec": "3.0.0-alpha.65",
41
- "@reventlessdev/reventless-infra": "3.0.0-alpha.87"
37
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.89",
38
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.67",
39
+ "@reventlessdev/reventless-interop": "3.0.0-alpha.24",
40
+ "@reventlessdev/rescript-uuid": "1.1.0-alpha.14",
41
+ "@reventlessdev/rescript-ssh2": "1.1.0-alpha.11"
42
42
  },
43
43
  "devDependencies": {
44
44
  "rescript": "^12.3.0",
@@ -61,7 +61,7 @@
61
61
  "build": "rescript build",
62
62
  "start": "rescript watch",
63
63
  "clean": "rescript clean",
64
- "rebuild": "pnpm run clean && pnpm run build -- -with-deps",
64
+ "rebuild": "pnpm run clean && pnpm run build",
65
65
  "deploy": "./scripts/deploy.sh",
66
66
  "test": "NODE_OPTIONS='--experimental-vm-modules' jest",
67
67
  "test:watch": "jest --watchAll",
@@ -0,0 +1,264 @@
1
+ // The connection-list filter / sort / keyset-paginate logic, extracted verbatim
2
+ // from QueryDbResolvers_GraphQL so there is ONE source of truth for the
3
+ // semantics. The in-memory / GraphQL resolver calls `run` over the materialised
4
+ // items; the SQLite backend's list push-down (reventless-local) and the Postgres
5
+ // resolver Lambda (reventless-aws) must reproduce these exact semantics, and the
6
+ // parity harness asserts they do. Kept pure (no server / storage dependencies —
7
+ // the one server helper it needs, global-id decoding for the `ids` filter, is
8
+ // passed in) so it can be the shared spec every backend is tested against.
9
+ //
10
+ // Lives in reventless-core (not reventless-local) so both the local SQLite path
11
+ // and the AWS Postgres resolver path can share it without a layering violation —
12
+ // `GraphQL_FragmentGenerator.serverCapability`, its only dependency, is a sibling
13
+ // here.
14
+
15
+ // base64 cursor of the active sort field's value. Shared with the resolver's
16
+ // items (sub-id) connection so cursor encoding stays in lockstep.
17
+ @val external btoa: string => string = "btoa"
18
+ @val external atob: string => string = "atob"
19
+ let encodeCursor = (value: string): string => btoa(value)
20
+ let decodeCursor = (cursor: string): string => atob(cursor)
21
+
22
+ // Default page size when neither `first` nor `last` is supplied — a bound is
23
+ // required for keyset `pageInfo` to be reported correctly.
24
+ let defaultListPageSize = 50
25
+
26
+ // The effective id of an item (its "id" field). Shared with the SQLite
27
+ // push-down so both compute the tiebreak / default-cursor value identically.
28
+ let getId = (item: JSON.t): string =>
29
+ item
30
+ ->JSON.Decode.object
31
+ ->Option.flatMap(d => d->Dict.get("id"))
32
+ ->Option.flatMap(JSON.Decode.string)
33
+ ->Option.getOr("")
34
+
35
+ // String form of a field for comparison / cursor purposes: the string itself,
36
+ // or a number rendered via Float.toString, else None. The push-down must render
37
+ // the same string in SQL (CAST … AS TEXT) for cursor/order parity.
38
+ let getFieldString = (item: JSON.t, field: string): option<string> =>
39
+ item
40
+ ->JSON.Decode.object
41
+ ->Option.flatMap(d => d->Dict.get(field))
42
+ ->Option.flatMap(v =>
43
+ switch v->JSON.Decode.string {
44
+ | Some(s) => Some(s)
45
+ | None => v->JSON.Decode.float->Option.map(f => Float.toString(f))
46
+ }
47
+ )
48
+
49
+ // Build the Relay connection object from an already-ordered page. Shared by
50
+ // `run` and the SQLite push-down so edges / cursors / pageInfo have one shape.
51
+ let buildConnection = (
52
+ ~pageItems: array<JSON.t>,
53
+ ~hasNextPage: bool,
54
+ ~hasPreviousPage: bool,
55
+ ~cursorValueOf: JSON.t => string,
56
+ ): JSON.t => {
57
+ let edges =
58
+ pageItems->Array.map(item => Obj.magic({"node": item, "cursor": encodeCursor(cursorValueOf(item))}))
59
+ let startCursor = pageItems->Array.get(0)->Option.map(item => encodeCursor(cursorValueOf(item)))
60
+ let endCursor =
61
+ pageItems->Array.get(pageItems->Array.length - 1)->Option.map(item => encodeCursor(cursorValueOf(item)))
62
+ Obj.magic({
63
+ "edges": edges,
64
+ "pageInfo": {
65
+ "hasNextPage": hasNextPage,
66
+ "hasPreviousPage": hasPreviousPage,
67
+ "startCursor": startCursor->Nullable.fromOption,
68
+ "endCursor": endCursor->Nullable.fromOption,
69
+ },
70
+ })
71
+ }
72
+
73
+ // Compute the Relay connection response (edges + pageInfo) for `items` under the
74
+ // GraphQL args. `decodeLocalId` maps a possibly-Relay-encoded id to its local id
75
+ // (the resolver passes DomainGraphQL_Server.decodeGlobalId); everything else is
76
+ // pure over the item array.
77
+ let run = (
78
+ ~items: array<JSON.t>,
79
+ ~argsDict: Dict.t<JSON.t>,
80
+ ~capability: GraphQL_FragmentGenerator.serverCapability,
81
+ ~labelField: string,
82
+ ~decodeLocalId: string => option<string>,
83
+ ): JSON.t => {
84
+ let filterDict =
85
+ argsDict->Dict.get("filter")->Option.flatMap(JSON.Decode.object)->Option.getOr(Dict.make())
86
+ let search = filterDict->Dict.get("search")->Option.flatMap(JSON.Decode.string)
87
+ let searchPrefix = filterDict->Dict.get("searchPrefix")->Option.flatMap(JSON.Decode.string)
88
+ let ids =
89
+ filterDict
90
+ ->Dict.get("ids")
91
+ ->Option.flatMap(JSON.Decode.array)
92
+ ->Option.map(arr => arr->Array.filterMap(JSON.Decode.string))
93
+ let getLabel = item =>
94
+ item
95
+ ->JSON.Decode.object
96
+ ->Option.flatMap(d => d->Dict.get(labelField))
97
+ ->Option.flatMap(JSON.Decode.string)
98
+ ->Option.getOr("")
99
+ // Per-field eq / from / to filters derived from capability — applied alongside
100
+ // the legacy search/searchPrefix/ids block.
101
+ let perFieldChecks: array<JSON.t => bool> = capability.filterFields->Array.flatMap(f => {
102
+ let checks: array<JSON.t => bool> = []
103
+ switch filterDict->Dict.get(f.name ++ "Eq") {
104
+ | Some(v) when v != JSON.Encode.null =>
105
+ let expected = switch v->JSON.Decode.string {
106
+ | Some(s) => s
107
+ | None => v->JSON.Decode.float->Option.map(f => Float.toString(f))->Option.getOr("")
108
+ }
109
+ checks->Array.push(item =>
110
+ getFieldString(item, f.name)->Option.mapOr(false, v => v == expected)
111
+ )
112
+ | _ => ()
113
+ }
114
+ if f.range {
115
+ switch filterDict->Dict.get(f.name ++ "From") {
116
+ | Some(v) when v != JSON.Encode.null =>
117
+ let from =
118
+ v
119
+ ->JSON.Decode.string
120
+ ->Option.getOr(v->JSON.Decode.float->Option.map(f => Float.toString(f))->Option.getOr(""))
121
+ checks->Array.push(item => getFieldString(item, f.name)->Option.mapOr(false, v => v >= from))
122
+ | _ => ()
123
+ }
124
+ switch filterDict->Dict.get(f.name ++ "To") {
125
+ | Some(v) when v != JSON.Encode.null =>
126
+ let to_ =
127
+ v
128
+ ->JSON.Decode.string
129
+ ->Option.getOr(v->JSON.Decode.float->Option.map(f => Float.toString(f))->Option.getOr(""))
130
+ checks->Array.push(item => getFieldString(item, f.name)->Option.mapOr(false, v => v <= to_))
131
+ | _ => ()
132
+ }
133
+ }
134
+ checks
135
+ })
136
+
137
+ let filtered = items->Array.filter(item => {
138
+ let passSearch = switch search {
139
+ | Some(s) if s->String.length > 0 =>
140
+ getLabel(item)->String.toLowerCase->String.includes(s->String.toLowerCase)
141
+ | _ => true
142
+ }
143
+ let passPrefix = switch searchPrefix {
144
+ | Some(p) if p->String.length > 0 =>
145
+ getLabel(item)->String.toLowerCase->String.startsWith(p->String.toLowerCase)
146
+ | _ => true
147
+ }
148
+ let passIds = switch ids {
149
+ | Some(idList) if idList->Array.length > 0 =>
150
+ let itemId = getId(item)
151
+ let itemLocalId = decodeLocalId(itemId)
152
+ idList->Array.some(i => i == itemId || itemLocalId == Some(i))
153
+ | _ => true
154
+ }
155
+ let passPerField = perFieldChecks->Array.every(check => check(item))
156
+ passSearch && passPrefix && passIds && passPerField
157
+ })
158
+
159
+ let orderByDict = argsDict->Dict.get("orderBy")->Option.flatMap(JSON.Decode.object)
160
+ let orderByField =
161
+ orderByDict->Option.flatMap(ob => ob->Dict.get("field"))->Option.flatMap(JSON.Decode.string)
162
+ let direction =
163
+ orderByDict
164
+ ->Option.flatMap(ob => ob->Dict.get("direction"))
165
+ ->Option.flatMap(JSON.Decode.string)
166
+ ->Option.getOr("ASC")
167
+ let isDesc = direction == "DESC"
168
+ let sorted = switch orderByField {
169
+ | Some(f) =>
170
+ let cmp = (a, b) => {
171
+ let av = getFieldString(a, f)->Option.getOr("")
172
+ let bv = getFieldString(b, f)->Option.getOr("")
173
+ let primary = if av < bv {
174
+ -1
175
+ } else if av > bv {
176
+ 1
177
+ } else {
178
+ 0
179
+ }
180
+ let primary = isDesc ? -primary : primary
181
+ if primary != 0 {
182
+ primary
183
+ } else {
184
+ let aid = getId(a)
185
+ let bid = getId(b)
186
+ if aid < bid {
187
+ -1
188
+ } else if aid > bid {
189
+ 1
190
+ } else {
191
+ 0
192
+ }
193
+ }
194
+ }
195
+ filtered->Array.toSorted((a, b) => cmp(a, b)->Int.toFloat)
196
+ | None =>
197
+ filtered->Array.toSorted((a, b) => {
198
+ let aid = getId(a)
199
+ let bid = getId(b)
200
+ if aid < bid {
201
+ -1.
202
+ } else if aid > bid {
203
+ 1.
204
+ } else {
205
+ 0.
206
+ }
207
+ })
208
+ }
209
+
210
+ let first =
211
+ argsDict->Dict.get("first")->Option.flatMap(JSON.Decode.float)->Option.map(Float.toInt)
212
+ let after = argsDict->Dict.get("after")->Option.flatMap(JSON.Decode.string)
213
+ let last = argsDict->Dict.get("last")->Option.flatMap(JSON.Decode.float)->Option.map(Float.toInt)
214
+ let before = argsDict->Dict.get("before")->Option.flatMap(JSON.Decode.string)
215
+ let isBackward = last->Option.isSome
216
+ let cursorField = orderByField->Option.getOr("id")
217
+ let getCursorValue = item => getFieldString(item, cursorField)->Option.getOr(getId(item))
218
+
219
+ let cursorBounded = switch (isBackward, after, before) {
220
+ | (false, Some(c), _) =>
221
+ let cv = decodeCursor(c)
222
+ sorted->Array.filter(item => {
223
+ let v = getCursorValue(item)
224
+ isDesc ? v < cv : v > cv
225
+ })
226
+ | (true, _, Some(c)) =>
227
+ let cv = decodeCursor(c)
228
+ sorted->Array.filter(item => {
229
+ let v = getCursorValue(item)
230
+ isDesc ? v > cv : v < cv
231
+ })
232
+ | _ => sorted
233
+ }
234
+
235
+ let pageSize = if isBackward {
236
+ last->Option.getOr(defaultListPageSize)
237
+ } else {
238
+ first->Option.getOr(defaultListPageSize)
239
+ }
240
+ let take = pageSize + 1
241
+ let (pageItems, hasMore) = if isBackward {
242
+ let len = cursorBounded->Array.length
243
+ let startIdx = len > take ? len - take : 0
244
+ let arr = cursorBounded->Array.slice(~start=startIdx, ~end=len)
245
+ let hasMore = arr->Array.length > pageSize
246
+ let result = if hasMore {
247
+ arr->Array.slice(~start=1, ~end=arr->Array.length)
248
+ } else {
249
+ arr
250
+ }
251
+ (result, hasMore)
252
+ } else {
253
+ let arr = cursorBounded->Array.slice(~start=0, ~end=take)
254
+ let hasMore = arr->Array.length > pageSize
255
+ (arr->Array.slice(~start=0, ~end=pageSize), hasMore)
256
+ }
257
+
258
+ buildConnection(
259
+ ~pageItems,
260
+ ~hasNextPage=!isBackward && hasMore,
261
+ ~hasPreviousPage=isBackward && hasMore,
262
+ ~cursorValueOf=getCursorValue,
263
+ )
264
+ }
@@ -0,0 +1,212 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
4
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
5
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+ import * as Stdlib_Nullable from "@rescript/runtime/lib/es6/Stdlib_Nullable.js";
7
+ import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
8
+
9
+ function encodeCursor(value) {
10
+ return btoa(value);
11
+ }
12
+
13
+ function decodeCursor(cursor) {
14
+ return atob(cursor);
15
+ }
16
+
17
+ function getId(item) {
18
+ return Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(item), d => d["id"]), Stdlib_JSON.Decode.string), "");
19
+ }
20
+
21
+ function getFieldString(item, field) {
22
+ return Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(item), d => d[field]), v => {
23
+ let s = Stdlib_JSON.Decode.string(v);
24
+ if (s !== undefined) {
25
+ return s;
26
+ } else {
27
+ return Stdlib_Option.map(Stdlib_JSON.Decode.float(v), f => f.toString());
28
+ }
29
+ });
30
+ }
31
+
32
+ function buildConnection(pageItems, hasNextPage, hasPreviousPage, cursorValueOf) {
33
+ let edges = pageItems.map(item => ({
34
+ node: item,
35
+ cursor: btoa(cursorValueOf(item))
36
+ }));
37
+ let startCursor = Stdlib_Option.map(pageItems[0], item => btoa(cursorValueOf(item)));
38
+ let endCursor = Stdlib_Option.map(pageItems[pageItems.length - 1 | 0], item => btoa(cursorValueOf(item)));
39
+ return {
40
+ edges: edges,
41
+ pageInfo: {
42
+ hasNextPage: hasNextPage,
43
+ hasPreviousPage: hasPreviousPage,
44
+ startCursor: Stdlib_Nullable.fromOption(startCursor),
45
+ endCursor: Stdlib_Nullable.fromOption(endCursor)
46
+ }
47
+ };
48
+ }
49
+
50
+ function run(items, argsDict, capability, labelField, decodeLocalId) {
51
+ let filterDict = Stdlib_Option.getOr(Stdlib_Option.flatMap(argsDict["filter"], Stdlib_JSON.Decode.object), {});
52
+ let search = Stdlib_Option.flatMap(filterDict["search"], Stdlib_JSON.Decode.string);
53
+ let searchPrefix = Stdlib_Option.flatMap(filterDict["searchPrefix"], Stdlib_JSON.Decode.string);
54
+ let ids = Stdlib_Option.map(Stdlib_Option.flatMap(filterDict["ids"], Stdlib_JSON.Decode.array), arr => Stdlib_Array.filterMap(arr, Stdlib_JSON.Decode.string));
55
+ let getLabel = item => Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(item), d => d[labelField]), Stdlib_JSON.Decode.string), "");
56
+ let perFieldChecks = capability.filterFields.flatMap(f => {
57
+ let checks = [];
58
+ let v = filterDict[f.name + "Eq"];
59
+ if (v !== undefined && v !== null) {
60
+ let s = Stdlib_JSON.Decode.string(v);
61
+ let expected = s !== undefined ? s : Stdlib_Option.getOr(Stdlib_Option.map(Stdlib_JSON.Decode.float(v), f => f.toString()), "");
62
+ checks.push(item => Stdlib_Option.mapOr(getFieldString(item, f.name), false, v => v === expected));
63
+ }
64
+ if (f.range) {
65
+ let v$1 = filterDict[f.name + "From"];
66
+ if (v$1 !== undefined && v$1 !== null) {
67
+ let from = Stdlib_Option.getOr(Stdlib_JSON.Decode.string(v$1), Stdlib_Option.getOr(Stdlib_Option.map(Stdlib_JSON.Decode.float(v$1), f => f.toString()), ""));
68
+ checks.push(item => Stdlib_Option.mapOr(getFieldString(item, f.name), false, v => v >= from));
69
+ }
70
+ let v$2 = filterDict[f.name + "To"];
71
+ if (v$2 !== undefined && v$2 !== null) {
72
+ let to_ = Stdlib_Option.getOr(Stdlib_JSON.Decode.string(v$2), Stdlib_Option.getOr(Stdlib_Option.map(Stdlib_JSON.Decode.float(v$2), f => f.toString()), ""));
73
+ checks.push(item => Stdlib_Option.mapOr(getFieldString(item, f.name), false, v => v <= to_));
74
+ }
75
+ }
76
+ return checks;
77
+ });
78
+ let filtered = items.filter(item => {
79
+ let passSearch = search !== undefined && search.length > 0 ? getLabel(item).toLowerCase().includes(search.toLowerCase()) : true;
80
+ let passPrefix = searchPrefix !== undefined && searchPrefix.length > 0 ? getLabel(item).toLowerCase().startsWith(searchPrefix.toLowerCase()) : true;
81
+ let passIds;
82
+ if (ids !== undefined && ids.length !== 0) {
83
+ let itemId = getId(item);
84
+ let itemLocalId = decodeLocalId(itemId);
85
+ passIds = ids.some(i => {
86
+ if (i === itemId) {
87
+ return true;
88
+ } else {
89
+ return Primitive_object.equal(itemLocalId, i);
90
+ }
91
+ });
92
+ } else {
93
+ passIds = true;
94
+ }
95
+ let passPerField = perFieldChecks.every(check => check(item));
96
+ if (passSearch && passPrefix && passIds) {
97
+ return passPerField;
98
+ } else {
99
+ return false;
100
+ }
101
+ });
102
+ let orderByDict = Stdlib_Option.flatMap(argsDict["orderBy"], Stdlib_JSON.Decode.object);
103
+ let orderByField = Stdlib_Option.flatMap(Stdlib_Option.flatMap(orderByDict, ob => ob["field"]), Stdlib_JSON.Decode.string);
104
+ let direction = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(orderByDict, ob => ob["direction"]), Stdlib_JSON.Decode.string), "ASC");
105
+ let isDesc = direction === "DESC";
106
+ let sorted;
107
+ if (orderByField !== undefined) {
108
+ sorted = filtered.toSorted((a, b) => {
109
+ let av = Stdlib_Option.getOr(getFieldString(a, orderByField), "");
110
+ let bv = Stdlib_Option.getOr(getFieldString(b, orderByField), "");
111
+ let primary = av < bv ? -1 : (
112
+ av > bv ? 1 : 0
113
+ );
114
+ let primary$1 = isDesc ? -primary | 0 : primary;
115
+ if (primary$1 !== 0) {
116
+ return primary$1;
117
+ }
118
+ let aid = getId(a);
119
+ let bid = getId(b);
120
+ if (aid < bid) {
121
+ return -1;
122
+ } else if (aid > bid) {
123
+ return 1;
124
+ } else {
125
+ return 0;
126
+ }
127
+ });
128
+ } else {
129
+ sorted = filtered.toSorted((a, b) => {
130
+ let aid = getId(a);
131
+ let bid = getId(b);
132
+ if (aid < bid) {
133
+ return -1;
134
+ } else if (aid > bid) {
135
+ return 1;
136
+ } else {
137
+ return 0;
138
+ }
139
+ });
140
+ }
141
+ let first = Stdlib_Option.map(Stdlib_Option.flatMap(argsDict["first"], Stdlib_JSON.Decode.float), prim => prim | 0);
142
+ let after = Stdlib_Option.flatMap(argsDict["after"], Stdlib_JSON.Decode.string);
143
+ let last = Stdlib_Option.map(Stdlib_Option.flatMap(argsDict["last"], Stdlib_JSON.Decode.float), prim => prim | 0);
144
+ let before = Stdlib_Option.flatMap(argsDict["before"], Stdlib_JSON.Decode.string);
145
+ let isBackward = Stdlib_Option.isSome(last);
146
+ let cursorField = Stdlib_Option.getOr(orderByField, "id");
147
+ let getCursorValue = item => Stdlib_Option.getOr(getFieldString(item, cursorField), getId(item));
148
+ let cursorBounded;
149
+ if (isBackward) {
150
+ if (before !== undefined) {
151
+ let cv = atob(before);
152
+ cursorBounded = sorted.filter(item => {
153
+ let v = getCursorValue(item);
154
+ if (isDesc) {
155
+ return v > cv;
156
+ } else {
157
+ return v < cv;
158
+ }
159
+ });
160
+ } else {
161
+ cursorBounded = sorted;
162
+ }
163
+ } else if (after !== undefined) {
164
+ let cv$1 = atob(after);
165
+ cursorBounded = sorted.filter(item => {
166
+ let v = getCursorValue(item);
167
+ if (isDesc) {
168
+ return v < cv$1;
169
+ } else {
170
+ return v > cv$1;
171
+ }
172
+ });
173
+ } else {
174
+ cursorBounded = sorted;
175
+ }
176
+ let pageSize = isBackward ? Stdlib_Option.getOr(last, 50) : Stdlib_Option.getOr(first, 50);
177
+ let take = pageSize + 1 | 0;
178
+ let match;
179
+ if (isBackward) {
180
+ let len = cursorBounded.length;
181
+ let startIdx = len > take ? len - take | 0 : 0;
182
+ let arr = cursorBounded.slice(startIdx, len);
183
+ let hasMore = arr.length > pageSize;
184
+ let result = hasMore ? arr.slice(1, arr.length) : arr;
185
+ match = [
186
+ result,
187
+ hasMore
188
+ ];
189
+ } else {
190
+ let arr$1 = cursorBounded.slice(0, take);
191
+ let hasMore$1 = arr$1.length > pageSize;
192
+ match = [
193
+ arr$1.slice(0, pageSize),
194
+ hasMore$1
195
+ ];
196
+ }
197
+ let hasMore$2 = match[1];
198
+ return buildConnection(match[0], !isBackward && hasMore$2, isBackward && hasMore$2, getCursorValue);
199
+ }
200
+
201
+ let defaultListPageSize = 50;
202
+
203
+ export {
204
+ encodeCursor,
205
+ decodeCursor,
206
+ defaultListPageSize,
207
+ getId,
208
+ getFieldString,
209
+ buildConnection,
210
+ run,
211
+ }
212
+ /* No side effect */