@owlmeans/resource 0.1.18-rc.2 → 0.1.18-rc.21

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/utils/query.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/resource",
3
- "version": "0.1.18-rc.2",
3
+ "version": "0.1.18-rc.21",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -21,10 +21,8 @@
21
21
  }
22
22
  },
23
23
  "dependencies": {
24
- "@noble/hashes": "^1.5.0",
25
- "@owlmeans/context": "^0.1.18-rc.2",
26
- "@owlmeans/error": "^0.1.18-rc.2",
27
- "@scure/base": "^2.3.0"
24
+ "@owlmeans/context": "^0.1.18-rc.20",
25
+ "@owlmeans/error": "^0.1.18-rc.20"
28
26
  },
29
27
  "peerDependencies": {
30
28
  "ajv": "*"
package/src/consts.ts CHANGED
@@ -34,33 +34,10 @@ export const createListSchema = <T extends ResourceRecord>(schema: JSONSchemaTyp
34
34
  additionalProperties: false,
35
35
  }
36
36
  },
37
- pager: {
38
- type: 'object',
39
- properties: {
40
- sort: {
41
- type: 'array',
42
- items: {
43
- oneOf: [
44
- { type: 'string' },
45
- {
46
- type: 'array', items: [
47
- { type: 'string' },
48
- { type: 'boolean', nullable: true }
49
- ], minItems: 1, maxItems: 2
50
- }
51
- ]
52
- },
53
- nullable: true
54
- },
55
- page: { type: 'number', nullable: true },
56
- size: { type: 'number', nullable: true },
57
- total: { type: 'number', nullable: true }
58
- },
59
- required: [],
60
- nullable: true,
61
- additionalProperties: false,
62
- }
37
+ total: { type: 'number' },
38
+ page: { type: 'number', nullable: true },
39
+ size: { type: 'number', nullable: true }
63
40
  },
64
- required: ['items'],
41
+ required: ['items', 'total'],
65
42
  additionalProperties: false,
66
43
  })
package/src/helper.ts CHANGED
@@ -1,31 +1,3 @@
1
- import type { ListCriteria, ListOptions, ListPager } from './types.js'
2
-
3
- export const prepareListOptions = (defPageSize: number = 10, criteria?: ListOptions | ListCriteria, opts?: ListOptions): ListOptions => {
4
- if (opts == null) {
5
- if (criteria == null) {
6
- criteria = {}
7
- opts = {}
8
- } else if ('criteria' in criteria || 'pager' in criteria) {
9
- /**
10
- * Both keys have to be read off the original object before it's reassigned —
11
- * reading `pager` after narrowing to `.criteria` silently drops the pager.
12
- */
13
- const options = criteria as ListOptions
14
- opts = { pager: options.pager }
15
- criteria = (options.criteria ?? {}) as ListCriteria
16
- }
17
- }
18
-
19
- const size = (opts?.pager?.size ?? defPageSize)
20
- const pager: ListPager = {
21
- sort: opts?.pager?.sort,
22
- page: opts?.pager?.page ?? 0,
23
- size, total: 0
24
- }
25
-
26
- return { criteria: criteria as ListCriteria, pager }
27
- }
28
-
29
1
  export const filterObject = <T extends {}>(obj: T, keep?: string[]): T =>
30
2
  Object.entries(obj).reduce((obj, [key, value]) => {
31
3
  if (value == null && !keep?.includes(key)) {
package/src/index.ts CHANGED
@@ -3,5 +3,6 @@ export * from './errors.js'
3
3
  export * from './consts.js'
4
4
  export * from './service.js'
5
5
  export * from './helper.js'
6
+ export * from './utils/query.js'
6
7
  export * from './migration.js'
7
8
  export type * from './types.js'
package/src/types.ts CHANGED
@@ -1,63 +1,150 @@
1
1
  import type { BasicConfig, BasicContext, BasicResource, LazyService } from '@owlmeans/context'
2
2
  import type { MigrationStage } from './consts.js'
3
3
 
4
+ export interface ResourceRecord {
5
+ id?: string
6
+ }
7
+
8
+ /** Operators a single field can be constrained by. */
9
+ export interface FieldOperators<V> {
10
+ $eq?: V
11
+ $ne?: V
12
+ $gt?: V
13
+ $gte?: V
14
+ $lt?: V
15
+ $lte?: V
16
+ $in?: Array<V | null>
17
+ $nin?: Array<V | null>
18
+ $exists?: boolean
19
+ $null?: boolean
20
+ $like?: string
21
+ $ilike?: string
22
+ $regex?: string
23
+ $startsWith?: string
24
+ $endsWith?: string
25
+ $between?: [V, V]
26
+ $contains?: V | V[]
27
+ $contained?: V[]
28
+ $overlaps?: V[]
29
+ }
30
+
31
+ /**
32
+ * How one field is constrained: a bare value is equality, a bare ARRAY is "any of these", `null`
33
+ * asks for the absence of a value, and `undefined` is SKIPPED — an untouched filter must never
34
+ * empty a list.
35
+ */
36
+ export type FieldCriteria<V> = V | Array<V | null> | FieldOperators<NonNullable<V>> | null | undefined
37
+
38
+ /**
39
+ * A query over records of `T`. Keys are the record's own fields, so a typo is a compile error;
40
+ * a dotted key reaches into a nested value (or a jsonb column) and stays open.
41
+ */
42
+ export type Criteria<T> =
43
+ & { [K in keyof T & string]?: FieldCriteria<T[K]> }
44
+ & { [path: `${string}.${string}`]: FieldCriteria<unknown> }
45
+ & { $and?: Criteria<T>[], $or?: Criteria<T>[], $not?: Criteria<T> }
46
+
47
+ export type SortField<T> = (keyof T & string) | `${string}.${string}`
48
+
49
+ /** A bare field name sorts ascending. */
50
+ export type Sort<T> = SortField<T> | { field: SortField<T>, order?: 'asc' | 'desc' }
51
+
52
+ export interface FirstOptions<T> {
53
+ sort?: Sort<T>[]
54
+ }
55
+
56
+ /**
57
+ * Paging is opt-in per call. A backend that cannot afford an unbounded read applies its own
58
+ * default size when none is asked for; the in-memory ones return everything.
59
+ */
60
+ export interface ListOptions<T> extends FirstOptions<T> {
61
+ page?: number
62
+ size?: number
63
+ }
64
+
65
+ /** The same question in one object — the shape an API carries over the wire. */
66
+ export interface ListQuery<T> extends ListOptions<T> {
67
+ where?: Criteria<T>
68
+ }
69
+
70
+ export interface ListResult<T extends ResourceRecord> {
71
+ items: T[]
72
+ total: number
73
+ page?: number
74
+ size?: number
75
+ }
76
+
77
+ export type Ttl = number | Date
78
+
79
+ export interface WriteOptions {
80
+ /** Seconds from now, or the instant to expire at. Backends without expiry refuse it. */
81
+ ttl?: Ttl
82
+ }
83
+
84
+ /**
85
+ * Typed CRUD over records. Reads take either an id or a criteria object, so fetching one record by
86
+ * several fields is a single call rather than a list whose first element is taken.
87
+ */
4
88
  export interface Resource<T extends ResourceRecord> extends BasicResource {
5
89
  /**
6
90
  * @throws {UnknownRecordError}
7
91
  */
8
- get: <Type extends T>(id: string, field?: Getter, opts?: LifecycleOptions) => Promise<Type>
9
- load: <Type extends T>(id: string, field?: Getter, opts?: LifecycleOptions) => Promise<Type | null>
10
- list: <Type extends T>(criteria?: ListOptions | ListCriteria, opts?: ListOptions) => Promise<ListResult<Type>>
11
- save: <Type extends T>(record: Partial<Type>, opts?: Getter) => Promise<Type>
92
+ get(id: string): Promise<T>
93
+ get(where: Criteria<T>, opts?: FirstOptions<T>): Promise<T>
94
+ load(id: string): Promise<T | null>
95
+ load(where: Criteria<T>, opts?: FirstOptions<T>): Promise<T | null>
96
+ list(where?: Criteria<T>, opts?: ListOptions<T>): Promise<ListResult<T>>
97
+ count(where?: Criteria<T>): Promise<number>
12
98
  /**
13
99
  * @throws {RecordExists}
14
100
  */
15
- create: <Type extends T>(record: Partial<Type>, opts?: LifecycleOptions) => Promise<Type>
101
+ create(record: Partial<T>, opts?: WriteOptions): Promise<T>
16
102
  /**
103
+ * Replaces the whole record.
17
104
  * @throws {UnknownRecordError}
18
105
  */
19
- update: <Type extends T>(record: Partial<Type>, opts?: Getter) => Promise<Type>
20
- delete: <Type extends T>(id: string | T, opts?: Getter) => Promise<Type | null>
106
+ update(record: Partial<T>, opts?: WriteOptions): Promise<T>
107
+ /** Creates when the record carries no id, replaces otherwise. */
108
+ save(record: Partial<T>, opts?: WriteOptions): Promise<T>
109
+ delete(id: string): Promise<T | null>
21
110
  /**
111
+ * Delete-and-return — the consume-once read. Absence is an error here; use `delete` when it is not.
22
112
  * @throws {UnknownRecordError}
23
113
  */
24
- pick: <Type extends T>(id: string | T, opts?: Getter) => Promise<Type>
25
- }
26
-
27
- export interface ResourceRecord {
28
- id?: string
114
+ take(id: string): Promise<T>
115
+ /** Bulk delete. Refuses an empty criteria object rather than emptying the resource. */
116
+ purge(where: Criteria<T>): Promise<number>
29
117
  }
30
118
 
31
- type MaybeArray<T> = T | T[]
32
- export interface ListCriteria extends Record<string, MaybeArray<ListCriteria | number | string | undefined>> { }
119
+ export type Unsubscribe = () => Promise<void>
33
120
 
34
- export interface ListOptions {
35
- pager?: ListPager
36
- criteria?: ListCriteria
121
+ export interface SubscribeOptions {
122
+ channel?: string
123
+ once?: boolean
124
+ ttl?: Ttl
37
125
  }
38
126
 
39
- export type ListSort = string | [string, boolean?]
40
-
41
- export interface ListPager {
42
- sort?: ListSort[]
43
- page?: number
44
- size?: number
45
- total?: number
127
+ /** Optional capability: a backend that can carry messages beside its records. */
128
+ export interface PubSubResource<T> {
129
+ publish(value: T, channel?: string): Promise<void>
130
+ subscribe(handler: (value: T) => void | Promise<void>, opts?: SubscribeOptions): Promise<Unsubscribe>
46
131
  }
47
132
 
48
- export interface ListResult<T extends ResourceRecord> {
49
- items: T[]
50
- pager?: ListPager
133
+ /** Optional capability: watching ONE record for changes (redis keyspace notifications). */
134
+ export interface WatchableResource<T> {
135
+ watch(id: string, handler: (value: T | null) => void | Promise<void>, opts?: Omit<SubscribeOptions, 'channel'>): Promise<Unsubscribe>
51
136
  }
52
137
 
53
- type Getter = string | GetterOptions
54
-
55
- export interface GetterOptions extends LifecycleOptions {
56
- field?: string
138
+ /** Optional capability: an append-only log with consumer groups. */
139
+ export interface StreamResource<T> {
140
+ stream(key: string, value: T): Promise<void>
141
+ consume(key: string, opts?: { group?: string, consumer?: string, block?: number }): AsyncGenerator<T>
57
142
  }
58
143
 
59
- export interface LifecycleOptions {
60
- ttl?: number | Date | string
144
+ /** Optional capability: field level encryption at rest. */
145
+ export interface LockableResource<T extends ResourceRecord> {
146
+ lock: (record: Partial<T>, fields?: string[]) => Promise<T>
147
+ unlock: (record: Partial<T>, fields?: string[]) => Promise<T>
61
148
  }
62
149
 
63
150
  export interface ResourceMaker<R extends ResourceRecord, T extends Resource<R> = Resource<R>> {
@@ -102,11 +189,6 @@ export interface DbLocker<T extends ResourceRecord> {
102
189
  unlock: (alias: string, record: Partial<T>, fields: string[]) => Promise<T>
103
190
  }
104
191
 
105
- export interface ResourceLocker<T extends ResourceRecord> {
106
- lock: (record: Partial<T>, fields?: string[]) => Promise<T>
107
- unlock: (record: Partial<T>, fields?: string[]) => Promise<T>
108
- }
109
-
110
192
  export interface DbConfig<P extends {} = {}> {
111
193
  service: string
112
194
  alias?: string
@@ -116,8 +198,6 @@ export interface DbConfig<P extends {} = {}> {
116
198
  secret?: string
117
199
  schema?: string
118
200
  resourcePrefix?: string
119
- entitySensitive?: boolean
120
- serviceSensitive?: boolean
121
201
  encryptionKey?: string
122
202
  meta?: P
123
203
  }
@@ -133,16 +213,15 @@ export interface DbConfig<P extends {} = {}> {
133
213
  * invoked. Backends with a durable structure also implement {@link MigrationStore}, the
134
214
  * register that tracks which migrations have been applied.
135
215
  */
136
- export interface MigratableResource<Tx = unknown> {
216
+ export interface MigratableResource<Tx = unknown, Self = unknown> {
137
217
  /**
138
218
  * Register a migration, applied once per database in declaration order.
139
219
  *
140
- * Chainable and idempotent: re-registering the same name with the same body is a no-op,
141
- * which is what makes it safe to call from a resource maker that `reinitializeContext`
142
- * re-runs. Re-registering a *changed* body under a used name throws
143
- * {@link MigrationConflict}.
220
+ * Chainable and idempotent: re-registering the same name with the same body is a no-op, which is
221
+ * what makes it safe to call from a resource maker that runs more than once for the same alias.
222
+ * Re-registering a *changed* body under a used name throws {@link MigrationConflict}.
144
223
  */
145
- migration: (name: string, apply: (tx: Tx) => Promise<void>, stage?: MigrationStage) => this
224
+ migration: (name: string, apply: (tx: Tx) => Promise<void>, stage?: MigrationStage) => Self
146
225
  /** The registered migrations for this resource's alias. Read-only; use {@link MigratableResource.migration}. */
147
226
  migrations: () => MigrationRegistry<Tx>
148
227
  }
@@ -1,2 +1,3 @@
1
1
 
2
2
  export * from './name.js'
3
+ export * from './query.js'
package/src/utils/name.ts CHANGED
@@ -1,27 +1,5 @@
1
- import { Layer } from '@owlmeans/context'
2
1
  import type {Context, Config, ResourceDbService, DbConfig} from '../types.js'
3
2
 
4
- import { sha256 } from '@noble/hashes/sha256'
5
- import { hex } from '@scure/base'
6
-
7
- export const dbName = <C extends Config, T extends Context<C> = Context<C>>(context: T, service: ResourceDbService<any,any>, config: DbConfig) => {
8
- let name = config.schema ?? config.alias ?? service.alias
9
-
10
- if (context.cfg.layerId != null
11
- && [Layer.Entity, Layer.User].includes(context.cfg.layer)
12
- && service.layers?.includes(Layer.Entity)) {
13
- name = format(name, context.cfg.layerId)
14
- }
15
-
16
- return name
17
- }
18
-
19
- const format = (name: string, suffix: string) => {
20
- name = (name + '_' + suffix).replace(/\W/g, '_')
21
-
22
- if (name.length > 64) {
23
- name = name.substring(0, 31) + '_' + hex.encode(sha256(name.substring(31)))
24
- }
25
-
26
- return name
27
- }
3
+ export const dbName = <C extends Config, T extends Context<C> = Context<C>>(
4
+ _context: T, service: ResourceDbService<any, any>, config: DbConfig
5
+ ) => config.schema ?? config.alias ?? service.alias
@@ -0,0 +1,277 @@
1
+ import { UnsupportedArgumentError } from '../errors.js'
2
+ import type { Criteria, ListOptions, ListResult, ResourceRecord, Sort } from '../types.js'
3
+
4
+ /**
5
+ * In-memory evaluation of `Criteria<any>`.
6
+ *
7
+ * The operator set mirrors `@owlmeans/postgres-resource` on purpose: one criteria shape has to
8
+ * mean the same thing whether a list is filtered in SQL by an endpoint or locally by a screen
9
+ * reading the state resource. A client that learns `{ status: ['open', 'done'] }` means "either
10
+ * of these" must not meet a different answer when the same object reaches the server.
11
+ *
12
+ * Two deliberate differences, both because a state resource carries no schema:
13
+ *
14
+ * - An unknown key cannot be detected. Postgres throws on one (a typo silently widening a query
15
+ * to the whole table is worth being loud about); here the property is simply absent from the
16
+ * record, so the record does not match. There is nothing to compare it against.
17
+ * - There is no jsonb/column distinction, so a dotted key always reaches into the record.
18
+ */
19
+
20
+ const COMPARISON = new Set(['$eq', '$ne', '$gt', '$gte', '$lt', '$lte'])
21
+
22
+ /** Dates compare by instant; everything else compares as it is. */
23
+ const comparable = (value: unknown): unknown =>
24
+ value instanceof Date ? value.getTime() : value
25
+
26
+ /** Reach `profile.city` inside a record. A missing step yields `undefined`, never a throw. */
27
+ const reach = (record: unknown, path: string[]): unknown =>
28
+ path.reduce<unknown>(
29
+ (value, step) => value == null || typeof value !== 'object'
30
+ ? undefined
31
+ : (value as Record<string, unknown>)[step],
32
+ record
33
+ )
34
+
35
+ /**
36
+ * An object naming at least one `$` key is a spec, not a value to compare against.
37
+ * A Date and an array are values even though both are objects.
38
+ */
39
+ const isOperatorSpec = (value: unknown): value is Record<string, unknown> =>
40
+ value != null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date)
41
+ && Object.keys(value).some(key => key.startsWith('$'))
42
+
43
+ const equal = (left: unknown, right: unknown): boolean => {
44
+ if (left instanceof Date || right instanceof Date) {
45
+ return comparable(left) === comparable(right)
46
+ }
47
+ if (Array.isArray(left) && Array.isArray(right)) {
48
+ return left.length === right.length && left.every((entry, index) => equal(entry, right[index]))
49
+ }
50
+ return left === right
51
+ }
52
+
53
+ /** `$in` / `$nin`. `null` in the list matches an absent property, matching the SQL widening. */
54
+ const inList = (value: unknown, operand: unknown): boolean => {
55
+ const values = Array.isArray(operand) ? operand : [operand]
56
+ return values.some(entry => entry == null ? value == null : equal(value, entry))
57
+ }
58
+
59
+ const text = (value: unknown): string => value == null ? '' : `${value}`
60
+
61
+ /** `%` and `_` are the SQL wildcards; `\` escapes them. */
62
+ const likeToRegExp = (pattern: string, flags: string): RegExp => {
63
+ let source = ''
64
+ for (let index = 0; index < pattern.length; index++) {
65
+ const char = pattern[index]!
66
+ if (char === '\\' && index + 1 < pattern.length) {
67
+ source += pattern[++index]!.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
68
+ continue
69
+ }
70
+ if (char === '%') { source += '.*'; continue }
71
+ if (char === '_') { source += '.'; continue }
72
+ source += char.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
73
+ }
74
+
75
+ return new RegExp(`^${source}$`, flags)
76
+ }
77
+
78
+ /**
79
+ * @throws {UnsupportedArgumentError} on an operator this store cannot answer.
80
+ */
81
+ const applyOperators = (value: unknown, spec: Record<string, unknown>): boolean => {
82
+ for (const [operator, operand] of Object.entries(spec)) {
83
+ if (COMPARISON.has(operator)) {
84
+ const left = comparable(value)
85
+ const right = comparable(operand)
86
+ const matched =
87
+ operator === '$eq' ? equal(value, operand)
88
+ : operator === '$ne' ? !equal(value, operand)
89
+ : left == null || right == null ? false
90
+ : operator === '$gt' ? (left as never) > (right as never)
91
+ : operator === '$gte' ? (left as never) >= (right as never)
92
+ : operator === '$lt' ? (left as never) < (right as never)
93
+ : (left as never) <= (right as never)
94
+ if (!matched) return false
95
+ continue
96
+ }
97
+ switch (operator) {
98
+ case '$in':
99
+ if (!inList(value, operand)) return false
100
+ break
101
+ case '$nin':
102
+ if (inList(value, operand)) return false
103
+ break
104
+ case '$exists':
105
+ if ((value != null) !== (operand !== false)) return false
106
+ break
107
+ case '$null':
108
+ if ((value == null) !== (operand !== false)) return false
109
+ break
110
+ case '$like':
111
+ if (!likeToRegExp(text(operand), '').test(text(value))) return false
112
+ break
113
+ case '$ilike':
114
+ if (!likeToRegExp(text(operand), 'i').test(text(value))) return false
115
+ break
116
+ case '$regex':
117
+ if (!new RegExp(text(operand)).test(text(value))) return false
118
+ break
119
+ case '$startsWith':
120
+ if (!text(value).startsWith(text(operand))) return false
121
+ break
122
+ case '$endsWith':
123
+ if (!text(value).endsWith(text(operand))) return false
124
+ break
125
+ case '$between': {
126
+ if (!Array.isArray(operand) || operand.length !== 2) {
127
+ throw new UnsupportedArgumentError(`criteria:$between`)
128
+ }
129
+ const left = comparable(value)
130
+ if (left == null) return false
131
+ const from = comparable(operand[0])
132
+ const to = comparable(operand[1])
133
+ if ((left as never) < (from as never) || (left as never) > (to as never)) return false
134
+ break
135
+ }
136
+ case '$contains': {
137
+ const operands = Array.isArray(operand) ? operand : [operand]
138
+ const values = Array.isArray(value) ? value : [value]
139
+ if (!operands.every(entry => values.some(candidate => equal(candidate, entry)))) return false
140
+ break
141
+ }
142
+ case '$contained': {
143
+ const operands = Array.isArray(operand) ? operand : [operand]
144
+ const values = Array.isArray(value) ? value : [value]
145
+ if (!values.every(candidate => operands.some(entry => equal(candidate, entry)))) return false
146
+ break
147
+ }
148
+ case '$overlaps': {
149
+ const operands = Array.isArray(operand) ? operand : [operand]
150
+ const values = Array.isArray(value) ? value : [value]
151
+ if (!values.some(candidate => operands.some(entry => equal(candidate, entry)))) return false
152
+ break
153
+ }
154
+ default:
155
+ throw new UnsupportedArgumentError(`criteria-operator:${operator}`)
156
+ }
157
+ }
158
+
159
+ return true
160
+ }
161
+
162
+ /**
163
+ * Whether one record satisfies the criteria.
164
+ *
165
+ * `undefined` as a criteria value is skipped rather than compared — it is what an optional filter
166
+ * looks like when nothing was chosen, and treating it as "must be undefined" makes an unset
167
+ * dropdown filter the list down to nothing.
168
+ *
169
+ * @throws {UnsupportedArgumentError} on an unknown operator.
170
+ */
171
+ export const matchCriteria = <T extends ResourceRecord>(
172
+ record: T, criteria?: Criteria<any>
173
+ ): boolean => {
174
+ for (const [key, raw] of Object.entries(criteria ?? {})) {
175
+ if (raw === undefined) {
176
+ continue
177
+ }
178
+
179
+ if (key === '$and' || key === '$or') {
180
+ const parts = (Array.isArray(raw) ? raw : [raw]) as Criteria<any>[]
181
+ if (parts.length < 1) continue
182
+ const matched = key === '$and'
183
+ ? parts.every(part => matchCriteria(record, part))
184
+ : parts.some(part => matchCriteria(record, part))
185
+ if (!matched) return false
186
+ continue
187
+ }
188
+ if (key === '$not') {
189
+ if (matchCriteria(record, raw as Criteria<any>)) return false
190
+ continue
191
+ }
192
+
193
+ const value = reach(record, key.split('.'))
194
+
195
+ if (raw === null) {
196
+ if (value != null) return false
197
+ continue
198
+ }
199
+ if (isOperatorSpec(raw)) {
200
+ if (!applyOperators(value, raw as Record<string, unknown>)) return false
201
+ continue
202
+ }
203
+ if (Array.isArray(raw)) {
204
+ /**
205
+ * A bare array means "any of these", exactly as it does against a relational store.
206
+ * Exact array equality stays reachable as `{ $eq: [...] }`.
207
+ */
208
+ if (!inList(value, raw)) return false
209
+ continue
210
+ }
211
+ if (!equal(value, raw)) return false
212
+ }
213
+
214
+ return true
215
+ }
216
+
217
+ /** Every record the criteria accepts, in insertion order. */
218
+ export const filterRecords = <T extends ResourceRecord>(
219
+ records: T[], criteria?: Criteria<any>
220
+ ): T[] => criteria == null || Object.keys(criteria).length < 1
221
+ ? [...records]
222
+ : records.filter(record => matchCriteria(record, criteria))
223
+
224
+ /**
225
+ * Sort a copy. A bare field name is ascending; `{ field, order: 'desc' }` reverses it — the same
226
+ * meaning every backend gives it, so a sort written for one store orders the same way against
227
+ * another.
228
+ */
229
+ export const sortRecords = <T extends ResourceRecord>(records: T[], sort?: Sort<any>[]): T[] => {
230
+ if (sort == null || sort.length < 1) {
231
+ return [...records]
232
+ }
233
+
234
+ const rules = sort.map(entry => typeof entry === 'string'
235
+ ? { field: entry, desc: false }
236
+ : { field: entry.field, desc: entry.order === 'desc' })
237
+
238
+ return [...records].sort((left, right) => {
239
+ for (const { field, desc } of rules) {
240
+ const a = comparable(reach(left, field.split('.')))
241
+ const b = comparable(reach(right, field.split('.')))
242
+ if (a == null && b == null) continue
243
+ /** An absent value sorts last ascending, which is where a reader expects "no value". */
244
+ if (a == null) return 1
245
+ if (b == null) return -1
246
+ if ((a as never) < (b as never)) return desc ? 1 : -1
247
+ if ((a as never) > (b as never)) return desc ? -1 : 1
248
+ }
249
+
250
+ return 0
251
+ })
252
+ }
253
+
254
+ /** The first record the criteria accepts, honouring the sort. */
255
+ export const firstMatch = <T extends ResourceRecord>(
256
+ records: T[], where?: Criteria<any>, opts?: { sort?: Sort<any>[] }
257
+ ): T | null => sortRecords(filterRecords(records, where), opts?.sort)[0] ?? null
258
+
259
+ /**
260
+ * Filter, sort and page an in-memory record set into the shape every resource answers with.
261
+ * `size` is opt-in: an in-memory store returns everything when none is asked for.
262
+ */
263
+ export const applyQuery = <T extends ResourceRecord>(
264
+ records: T[], where?: Criteria<any>, opts?: ListOptions<any>
265
+ ): ListResult<T> => {
266
+ const matched = sortRecords(filterRecords(records, where), opts?.sort)
267
+ const total = matched.length
268
+ // `size: 0` is the explicit ask for everything — the same meaning the paged backends give it, so
269
+ // one query object means one thing whichever store answers it. An omitted size is unpaged here.
270
+ if (opts?.size == null || opts.size === 0) {
271
+ return { items: matched, total }
272
+ }
273
+ const page = opts.page ?? 0
274
+ const from = page * opts.size
275
+
276
+ return { items: matched.slice(from, from + opts.size), total, page, size: opts.size }
277
+ }
package/build/.gitkeep DELETED
File without changes