@rebasepro/app 0.13.0 → 0.13.1-canary.g249daa1
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/collections/entity-display-cache.d.ts +75 -0
- package/dist/collections/entity-display.d.ts +35 -0
- package/dist/collections/entity_image_preview.d.ts +8 -0
- package/dist/collections/form-layout.d.ts +6 -0
- package/dist/collections/index.d.ts +4 -0
- package/dist/collections/property-path.d.ts +16 -0
- package/dist/collections/property_presentation.d.ts +18 -3
- package/dist/collections/summary-property.d.ts +65 -0
- package/dist/components/common/useColumnsIds.d.ts +22 -0
- package/dist/core/Rebase.d.ts +1 -1
- package/dist/core/RebaseProps.d.ts +10 -2
- package/dist/hooks/data/collectionQuery.d.ts +45 -0
- package/dist/index.es.js +686 -217
- package/dist/index.es.js.map +1 -1
- package/dist/util/entity_cache.d.ts +19 -3
- package/dist/util/previews.d.ts +19 -0
- package/package.json +7 -7
- package/src/auth/useRebaseAuthController.ts +9 -1
- package/src/collections/entity-display-cache.ts +195 -0
- package/src/collections/entity-display.ts +105 -0
- package/src/collections/entity_image_preview.ts +13 -0
- package/src/collections/form-layout.ts +8 -1
- package/src/collections/index.ts +4 -0
- package/src/collections/property-path.ts +30 -0
- package/src/collections/property_presentation.ts +39 -4
- package/src/collections/summary-property.ts +114 -0
- package/src/collections/title-property.ts +13 -16
- package/src/components/common/useColumnsIds.tsx +67 -29
- package/src/components/common/useDataTableController.tsx +10 -14
- package/src/core/Rebase.tsx +20 -2
- package/src/core/RebaseProps.tsx +10 -2
- package/src/hooks/data/collectionQuery.ts +55 -0
- package/src/hooks/data/useCollection.tsx +29 -21
- package/src/hooks/data/useFetch.tsx +17 -2
- package/src/hooks/data/useRelationSelector.tsx +20 -4
- package/src/hooks/useAuthSubscription.ts +18 -2
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +20 -12
- package/src/locales/de.ts +1 -0
- package/src/locales/en.ts +2 -0
- package/src/locales/es.ts +1 -0
- package/src/locales/fr.ts +1 -0
- package/src/locales/hi.ts +2 -1
- package/src/locales/it.ts +1 -0
- package/src/locales/pt.ts +1 -0
- package/src/util/entity_cache.ts +34 -31
- package/src/util/previews.ts +49 -29
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The store behind a computed display value.
|
|
3
|
+
*
|
|
4
|
+
* A record's title is asked for far more often than it changes, and by many
|
|
5
|
+
* components at once: a list of fifty rows, each row's relation chips, the
|
|
6
|
+
* breadcrumb above them. Resolving per component is what makes an async display
|
|
7
|
+
* value a bad idea — fifty rows becomes fifty reads, then fifty more on the next
|
|
8
|
+
* render.
|
|
9
|
+
*
|
|
10
|
+
* So resolution is keyed by record *and* role, in-flight calls are shared, and
|
|
11
|
+
* results are kept until something says otherwise. Deliberately not a React
|
|
12
|
+
* thing: the same store answers an imperative caller (an export, a breadcrumb
|
|
13
|
+
* built outside the tree), and it is testable without a renderer.
|
|
14
|
+
*/
|
|
15
|
+
import type { EntityDisplayRole } from "@rebasepro/admin-types";
|
|
16
|
+
export type EntityDisplayKey = string;
|
|
17
|
+
/** The identity of one role of one record, as a cache key. */
|
|
18
|
+
export declare function entityDisplayKey(path: string, entityId: string | number | undefined, role: EntityDisplayRole): EntityDisplayKey;
|
|
19
|
+
export declare class EntityDisplayCache {
|
|
20
|
+
private readonly entries;
|
|
21
|
+
private readonly listeners;
|
|
22
|
+
/**
|
|
23
|
+
* The resolved value, or `undefined` when this pair has not been resolved
|
|
24
|
+
* yet. `null` is a resolved absence, and the two must stay distinct: a
|
|
25
|
+
* caller that reads "not yet" as "nothing" flickers its fallback in on every
|
|
26
|
+
* mount.
|
|
27
|
+
*/
|
|
28
|
+
peek(key: EntityDisplayKey): unknown | undefined;
|
|
29
|
+
/** True while a resolution for this pair is in flight. */
|
|
30
|
+
isLoading(key: EntityDisplayKey): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Resolve once per record and role. Concurrent callers share the first
|
|
33
|
+
* call's promise; later callers get the cached value with no promise at all.
|
|
34
|
+
*
|
|
35
|
+
* A resolver that throws is recorded as "nothing" rather than retried: the
|
|
36
|
+
* alternative is every render re-running a call that just failed. And it is
|
|
37
|
+
* reported here, which is a correction.
|
|
38
|
+
*
|
|
39
|
+
* It used to say "the caller that saw the rejection is the one that logs
|
|
40
|
+
* it", and `useEntityDisplay` duly attached a `.catch()` that warned. But
|
|
41
|
+
* both failure paths below swallow and return a *resolved* promise, so that
|
|
42
|
+
* catch could never run — the two halves each did the reasonable thing and
|
|
43
|
+
* between them the log was unreachable. A resolver that blew up produced a
|
|
44
|
+
* blank chip and total silence, which is the failure mode
|
|
45
|
+
* `EntityDisplayResolver`'s own contract ("treated as `undefined` and logged
|
|
46
|
+
* once") exists to rule out.
|
|
47
|
+
*
|
|
48
|
+
* Reporting belongs here for the reason the caller could not do it: this is
|
|
49
|
+
* the one place that runs exactly once per key, so "once" is a property of
|
|
50
|
+
* the code rather than a hope about how many components mount.
|
|
51
|
+
*/
|
|
52
|
+
resolve(key: EntityDisplayKey, resolver: () => unknown): Promise<unknown>;
|
|
53
|
+
/**
|
|
54
|
+
* Drop what is known about a record, so the next ask resolves again. Called
|
|
55
|
+
* after a write: the row that just saved may be called something else now.
|
|
56
|
+
*/
|
|
57
|
+
invalidate(path: string, entityId?: string | number): void;
|
|
58
|
+
/** Drop everything. The user signed out, or the app swapped datasource. */
|
|
59
|
+
clear(): void;
|
|
60
|
+
subscribe(listener: () => void): () => void;
|
|
61
|
+
private set;
|
|
62
|
+
/**
|
|
63
|
+
* Record a failed resolution as "nothing", and say so once.
|
|
64
|
+
*
|
|
65
|
+
* The key is the message: it is `<role> <path> <id>`, which is exactly what a
|
|
66
|
+
* reader needs to find the resolver that blew up. A warning with no key would
|
|
67
|
+
* tell them a display resolver failed somewhere in a list of fifty rows.
|
|
68
|
+
*
|
|
69
|
+
* `console.warn` rather than a thrown error, because this runs while a row is
|
|
70
|
+
* rendering: the contract is that a title which cannot be fetched must not
|
|
71
|
+
* take down the row that shows it.
|
|
72
|
+
*/
|
|
73
|
+
private fail;
|
|
74
|
+
private emit;
|
|
75
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a collection's `display` block.
|
|
3
|
+
*
|
|
4
|
+
* Two questions, kept apart because they are answered at different times: which
|
|
5
|
+
* *property* fills a role (readable from values already in hand) and which
|
|
6
|
+
* *resolver* fills it (may have to go to the network). A caller that cannot
|
|
7
|
+
* await — a sort comparator, an export column, a server render — uses the key
|
|
8
|
+
* and is documented to ignore resolvers.
|
|
9
|
+
*/
|
|
10
|
+
import type { AdminCollection, EntityDisplayResolver, EntityDisplayRole } from "@rebasepro/admin-types";
|
|
11
|
+
/**
|
|
12
|
+
* The property path a role is declared to read, when it is declared as a path.
|
|
13
|
+
*
|
|
14
|
+
* Returns `undefined` for a role filled by a resolver — a resolver has no key —
|
|
15
|
+
* and for a role the collection says nothing about, which is then derived.
|
|
16
|
+
*
|
|
17
|
+
* @group Collections
|
|
18
|
+
*/
|
|
19
|
+
export declare function getDisplayPropertyKey<M extends Record<string, unknown>>(collection: AdminCollection<M>, role: EntityDisplayRole): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* The resolver a role is declared to use, when it is declared as one.
|
|
22
|
+
*
|
|
23
|
+
* @group Collections
|
|
24
|
+
*/
|
|
25
|
+
export declare function getDisplayResolver<M extends Record<string, unknown>>(collection: AdminCollection<M>, role: EntityDisplayRole): EntityDisplayResolver<M, unknown> | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* True when the collection states this role at all, in either form.
|
|
28
|
+
*
|
|
29
|
+
* The derivation is a guess about what a collection probably means; a statement
|
|
30
|
+
* outranks it, and the heuristics that look for "the first enum" or "the leading
|
|
31
|
+
* relation" have to stand down when one exists.
|
|
32
|
+
*
|
|
33
|
+
* @group Collections
|
|
34
|
+
*/
|
|
35
|
+
export declare function hasDeclaredDisplay<M extends Record<string, unknown>>(collection: AdminCollection<M>, role: EntityDisplayRole): boolean;
|
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
import { CollectionConfig } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* The property that fills a record's image slot.
|
|
4
|
+
*
|
|
5
|
+
* `admin.display.image` first, then six fallbacks in descending confidence —
|
|
6
|
+
* the first image-typed storage property, an array of them, a URL rendered as an
|
|
7
|
+
* image, and so on. The ladder stays for collections that say nothing; a
|
|
8
|
+
* collection that names its picture is not guessed at.
|
|
9
|
+
*/
|
|
2
10
|
export declare function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection: CollectionConfig<M>): string | undefined;
|
|
@@ -34,6 +34,12 @@ export interface ResolvedFormSection {
|
|
|
34
34
|
/** Initial state only; the form owns it after first interaction. */
|
|
35
35
|
collapsed: boolean;
|
|
36
36
|
fields: ResolvedFormField[];
|
|
37
|
+
/**
|
|
38
|
+
* Declared arrangement for the read-only view. Carried through untouched —
|
|
39
|
+
* the resolver decides *which* fields a section holds, not how the surface
|
|
40
|
+
* that renders it stacks them, and only the read view honours this.
|
|
41
|
+
*/
|
|
42
|
+
readVariant?: "grid" | "summary";
|
|
37
43
|
}
|
|
38
44
|
export interface ResolvedFormLayout {
|
|
39
45
|
sections: ResolvedFormSection[];
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
export * from "./collection_view_config";
|
|
2
2
|
export * from "./entity_image_preview";
|
|
3
|
+
export * from "./entity-display";
|
|
4
|
+
export * from "./entity-display-cache";
|
|
3
5
|
export * from "./filter-operator-resolution";
|
|
4
6
|
export * from "./form-layout";
|
|
5
7
|
export * from "./navigation_from_path";
|
|
6
8
|
export * from "./navigation_utils";
|
|
7
9
|
export * from "./parent_references_from_path";
|
|
10
|
+
export * from "./property-path";
|
|
8
11
|
export * from "./property_presentation";
|
|
12
|
+
export * from "./summary-property";
|
|
9
13
|
export * from "./title-property";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Properties, Property } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* The property at a dotted path, walking `map` children — `address.street`.
|
|
4
|
+
*
|
|
5
|
+
* The value counterpart is `getValueInPath` in `@rebasepro/utils`; this is the
|
|
6
|
+
* schema half, and the two have to be used together. Reading a dotted path off
|
|
7
|
+
* an entity while looking its property up with a flat `properties[path]` gives
|
|
8
|
+
* the value and `undefined` for how to render it, which is how a declared title
|
|
9
|
+
* on a nested field silently fell back to a derived one.
|
|
10
|
+
*
|
|
11
|
+
* There were three copies of this: one private to `useColumnsIds`, one exported
|
|
12
|
+
* from the admin layer, and the flat lookup in the title resolver that was not
|
|
13
|
+
* this function at all. This is the one, in the lowest layer that needs it —
|
|
14
|
+
* admin re-exports it under the name it already published.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getPropertyInPath(properties: Properties, path: string): Property | undefined;
|
|
@@ -10,11 +10,26 @@
|
|
|
10
10
|
* That last one is worth knowing about rather than assuming: the collection editor
|
|
11
11
|
* has a whole Conditions UI, `serializable_utils` persists what it writes, and
|
|
12
12
|
* `BaseProperty.conditions` documents itself as "evaluated at runtime like property
|
|
13
|
-
* builders" — but the evaluator below is reached only from its own tests.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* builders" — but the evaluator below is reached only from its own tests. It lives
|
|
14
|
+
* here because here is where it would be called from once it is wired up.
|
|
15
|
+
*
|
|
16
|
+
* The one part of `conditions` that *is* applied is the literal case:
|
|
17
|
+
* `hidden`/`readOnly`/`disabled` stated as a plain boolean rather than as a rule.
|
|
18
|
+
* A literal needs no context, so `isHidden`/`isReadOnly`/`isDisabled` can answer
|
|
19
|
+
* it directly, and those three gates are consulted everywhere a field is laid
|
|
20
|
+
* out. A *rule* still is not evaluated anywhere in production — the split is
|
|
21
|
+
* deliberate, not an oversight: it is the difference between a condition that
|
|
22
|
+
* needs an entity to be evaluated against and one that does not.
|
|
16
23
|
*/
|
|
17
24
|
import type { ConditionContext, Property } from "@rebasepro/types";
|
|
18
25
|
export declare function isReadOnly(property: Property): boolean;
|
|
19
26
|
export declare function isHidden(property: Property): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the field is disabled by its own declaration, ignoring form state.
|
|
29
|
+
*
|
|
30
|
+
* The `admin.disabled` block and `conditions.disabled: true` say the same thing
|
|
31
|
+
* two ways, so every caller that gated on the first now asks here instead of
|
|
32
|
+
* growing a second check of its own.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isDisabled(property: Property): boolean;
|
|
20
35
|
export declare function applyPropertyConditions(property: Property, context: ConditionContext): Property;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Property } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a property can stand in for a record in *one line*.
|
|
4
|
+
*
|
|
5
|
+
* Preview surfaces — the reference card, a list row, a board card — have a
|
|
6
|
+
* single line per property and no way to grow. That is a constraint on the
|
|
7
|
+
* *value*, not on the property's importance: a Markdown biography is the most
|
|
8
|
+
* interesting column on an author, and it is still the wrong thing to paste
|
|
9
|
+
* into a 44px card. Ranking it here means the picker can skip it without
|
|
10
|
+
* anyone having to configure their way out of a broken card.
|
|
11
|
+
*
|
|
12
|
+
* Kept beside {@link getTitlePropertyCandidates} because the two answer
|
|
13
|
+
* neighbouring questions — "what is this record called" and "what else can be
|
|
14
|
+
* said about it in a line" — from the same property schema.
|
|
15
|
+
*
|
|
16
|
+
* @group Collections
|
|
17
|
+
*/
|
|
18
|
+
export declare const SUMMARY_RANK: {
|
|
19
|
+
/**
|
|
20
|
+
* No single-line form exists. A map renders as a key/value table and an
|
|
21
|
+
* array of maps as a stack of them; there is no first line to take.
|
|
22
|
+
*/
|
|
23
|
+
readonly UNUSABLE: 0;
|
|
24
|
+
/**
|
|
25
|
+
* Readable in one line, but only as an excerpt — the property holds a
|
|
26
|
+
* document, and the line is its opening. Worth showing when nothing better
|
|
27
|
+
* is available, never in preference to a value that fits whole.
|
|
28
|
+
*/
|
|
29
|
+
readonly EXCERPT: 1;
|
|
30
|
+
/** Short and self-contained: the line *is* the value. */
|
|
31
|
+
readonly DIRECT: 2;
|
|
32
|
+
};
|
|
33
|
+
/** One of the three summary ranks. */
|
|
34
|
+
export type SummaryRank = typeof SUMMARY_RANK[keyof typeof SUMMARY_RANK];
|
|
35
|
+
/**
|
|
36
|
+
* File-storage backed content (single image, array of images, generic upload…).
|
|
37
|
+
* Preview surfaces give these their own image slot, so they are never also a
|
|
38
|
+
* text line.
|
|
39
|
+
*
|
|
40
|
+
* @group Collections
|
|
41
|
+
*/
|
|
42
|
+
export declare function isStorageProperty(property: Property | undefined): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* True when the property holds free text long enough to be a document rather
|
|
45
|
+
* than a value — Markdown, or an explicitly multi-line string.
|
|
46
|
+
*
|
|
47
|
+
* @group Collections
|
|
48
|
+
*/
|
|
49
|
+
export declare function isLongTextProperty(property: Property | undefined): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* How well a property reads as one line of a preview. See {@link SUMMARY_RANK}.
|
|
52
|
+
*
|
|
53
|
+
* Decided from the property *schema* only: no values are consulted, so the
|
|
54
|
+
* answer is stable for a collection and can be memoised per collection rather
|
|
55
|
+
* than per row.
|
|
56
|
+
*
|
|
57
|
+
* @group Collections
|
|
58
|
+
*/
|
|
59
|
+
export declare function rankSummaryProperty(property: Property | undefined): SummaryRank;
|
|
60
|
+
/**
|
|
61
|
+
* True when the property has any single-line form at all.
|
|
62
|
+
*
|
|
63
|
+
* @group Collections
|
|
64
|
+
*/
|
|
65
|
+
export declare function canSummariseProperty(property: Property | undefined): boolean;
|
|
@@ -5,6 +5,28 @@ export type PropertyColumnConfig = {
|
|
|
5
5
|
disabled: boolean;
|
|
6
6
|
};
|
|
7
7
|
export declare function getSubcollectionColumnId(collection: AdminCollection<any>): string;
|
|
8
|
+
/**
|
|
9
|
+
* The jump-to-tab columns a collection table does not need, because the relation
|
|
10
|
+
* behind them already has a column of its own.
|
|
11
|
+
*
|
|
12
|
+
* Every child view gets a 200px button column that opens its tab. For a relation
|
|
13
|
+
* declared in `relations` that button is the relation's only presence in the
|
|
14
|
+
* table. For one declared as a property it is the second: the property's own
|
|
15
|
+
* column is already there, hydrated by the list fetch's `include: ["*"]`, showing
|
|
16
|
+
* the child rows themselves — and carrying the *same heading*, because the tab
|
|
17
|
+
* takes its name from the declaring property. Two columns called "Applications",
|
|
18
|
+
* one of them a button, and nothing in the header to tell them apart.
|
|
19
|
+
*
|
|
20
|
+
* The property column wins: it shows what the children are, and each chip in it
|
|
21
|
+
* opens one. The tab stays reachable by opening the record, which is what the
|
|
22
|
+
* rest of the table's rows do anyway.
|
|
23
|
+
*
|
|
24
|
+
* Unless the author hid that column — `hideFromCollection` on the property, or a
|
|
25
|
+
* `propertiesOrder` that omits it, is a statement about the column and not about
|
|
26
|
+
* the relation, so the button comes back rather than the relation dropping out
|
|
27
|
+
* of the table altogether.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getRedundantChildViewColumnIds<M extends Record<string, any>>(collection: AdminCollection<M>): Set<string>;
|
|
8
30
|
export declare function useColumnIds<M extends Record<string, any>>(collection: AdminCollection<M>, includeSubcollections: boolean): PropertyColumnConfig[];
|
|
9
31
|
export declare function getColumnKeysForProperty(property: Property, key: string, disabled?: boolean): PropertyColumnConfig[];
|
|
10
32
|
export declare function getFormFieldKeys(collection: AdminCollection): string[];
|
package/dist/core/Rebase.d.ts
CHANGED
|
@@ -12,4 +12,4 @@ import { User } from "@rebasepro/types";
|
|
|
12
12
|
*
|
|
13
13
|
* @group Core
|
|
14
14
|
*/
|
|
15
|
-
export declare function Rebase<USER extends User>(props: RebaseProps<USER>): React.JSX.Element;
|
|
15
|
+
export declare function Rebase<USER extends User, DB = unknown>(props: RebaseProps<USER, DB>): React.JSX.Element;
|
|
@@ -99,7 +99,7 @@ import type { EffectiveRoleController } from "@rebasepro/types";
|
|
|
99
99
|
*
|
|
100
100
|
* @group Models
|
|
101
101
|
*/
|
|
102
|
-
export type RebaseProps<USER extends User> = {
|
|
102
|
+
export type RebaseProps<USER extends User, DB = unknown> = {
|
|
103
103
|
/**
|
|
104
104
|
* The root components of your application. Use RebaseAdmin, RebaseStudio, and RebaseShell.
|
|
105
105
|
* Alternatively, pass a render function that receives { context, loading }.
|
|
@@ -140,8 +140,16 @@ export type RebaseProps<USER extends User> = {
|
|
|
140
140
|
* entry keyed `"(default)"` carries a driver.
|
|
141
141
|
* `client.auth` is subscribed unless `authController` is provided.
|
|
142
142
|
* `client.storage` is used unless `storageSource` is provided.
|
|
143
|
+
*
|
|
144
|
+
* `DB` is inferred from whatever is passed, and defaults to `unknown` for
|
|
145
|
+
* an untyped client. It has to be a parameter rather than a fixed
|
|
146
|
+
* `RebaseClient`: `RebaseClient<unknown>` is not a supertype of
|
|
147
|
+
* `RebaseClient<Database>` — the dynamic branch of `RebaseSdkData` is an
|
|
148
|
+
* index signature that no concrete instantiation satisfies — so pinning it
|
|
149
|
+
* here rejected the client of every project that generates a `Database`
|
|
150
|
+
* type, which is the whole typed-SDK path.
|
|
143
151
|
*/
|
|
144
|
-
client?: RebaseClient
|
|
152
|
+
client?: RebaseClient<DB>;
|
|
145
153
|
/**
|
|
146
154
|
* The data sources of the app. Each entry pairs a
|
|
147
155
|
* {@link DataSourceDefinition} (key, engine, transport) with an optional
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { FindParams, FilterValues, LogicalCondition } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* The one place a collection read's parameters are assembled.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this exists
|
|
6
|
+
*
|
|
7
|
+
* Four call sites used to build this object by hand — `useCollection` and
|
|
8
|
+
* `useDataTableController`, each in both their `listen` and `find` branches.
|
|
9
|
+
* Every one of them listed the fields it forwarded, so adding an option to
|
|
10
|
+
* `FindParams` meant remembering four places, and forgetting one failed
|
|
11
|
+
* silently: the option simply never reached the server, and the feature it
|
|
12
|
+
* enabled looked broken for reasons nowhere near the code that dropped it.
|
|
13
|
+
*
|
|
14
|
+
* That is not hypothetical. `searchExplain` was added to three of the four and
|
|
15
|
+
* the miss was found by intercepting a WebSocket frame, because nothing else
|
|
16
|
+
* could see it.
|
|
17
|
+
*
|
|
18
|
+
* A field added here reaches every read. `toFindParams` returns `FindParams`
|
|
19
|
+
* itself, so the compiler checks the shape rather than a hand-copied list.
|
|
20
|
+
*/
|
|
21
|
+
export interface CollectionQueryInput<M extends Record<string, unknown>> {
|
|
22
|
+
where?: FilterValues<Extract<keyof M, string>>;
|
|
23
|
+
logical?: LogicalCondition;
|
|
24
|
+
/**
|
|
25
|
+
* Loosened from `FindParams["orderBy"]` on purpose: callers hold the sort
|
|
26
|
+
* as a plain `[string, direction]` read off user config or a URL, where the
|
|
27
|
+
* column is not statically known. Narrowing it here would push a cast onto
|
|
28
|
+
* every call site, which is the kind of friction that sends people back to
|
|
29
|
+
* hand-building the object this exists to replace.
|
|
30
|
+
*/
|
|
31
|
+
orderBy?: [string, "asc" | "desc"];
|
|
32
|
+
limit?: number;
|
|
33
|
+
offset?: number;
|
|
34
|
+
page?: number;
|
|
35
|
+
searchString?: string;
|
|
36
|
+
include?: string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build the parameters for one collection read.
|
|
40
|
+
*
|
|
41
|
+
* Derived options live here rather than at the call sites, so they cannot
|
|
42
|
+
* disagree: `searchExplain` rides along exactly when there is a search string
|
|
43
|
+
* to explain, which is also the only time it costs anything.
|
|
44
|
+
*/
|
|
45
|
+
export declare function toFindParams<M extends Record<string, unknown>>(input: CollectionQueryInput<M>): FindParams<M>;
|