@rebasepro/types 0.8.0 → 0.9.1-canary.09aaf62

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.
Files changed (88) hide show
  1. package/README.md +13 -13
  2. package/dist/controllers/auth.d.ts +7 -1
  3. package/dist/controllers/client.d.ts +204 -6
  4. package/dist/controllers/collection_registry.d.ts +3 -3
  5. package/dist/controllers/customization_controller.d.ts +1 -1
  6. package/dist/controllers/data.d.ts +309 -35
  7. package/dist/controllers/data_driver.d.ts +92 -37
  8. package/dist/controllers/email.d.ts +2 -2
  9. package/dist/controllers/index.d.ts +1 -1
  10. package/dist/controllers/local_config_persistence.d.ts +4 -4
  11. package/dist/controllers/navigation.d.ts +2 -2
  12. package/dist/controllers/registry.d.ts +21 -8
  13. package/dist/controllers/{side_entity_controller.d.ts → side_panel_controller.d.ts} +7 -7
  14. package/dist/controllers/storage.d.ts +39 -0
  15. package/dist/errors.d.ts +64 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.es.js +160 -15
  18. package/dist/index.es.js.map +1 -1
  19. package/dist/rebase_context.d.ts +8 -4
  20. package/dist/types/auth_adapter.d.ts +29 -4
  21. package/dist/types/backend.d.ts +33 -26
  22. package/dist/types/backup.d.ts +20 -0
  23. package/dist/types/builders.d.ts +2 -2
  24. package/dist/types/collections.d.ts +84 -75
  25. package/dist/types/component_overrides.d.ts +61 -3
  26. package/dist/types/cron.d.ts +11 -2
  27. package/dist/types/data_source.d.ts +15 -2
  28. package/dist/types/database_adapter.d.ts +21 -4
  29. package/dist/types/entities.d.ts +7 -7
  30. package/dist/types/entity_actions.d.ts +7 -7
  31. package/dist/types/entity_callbacks.d.ts +39 -39
  32. package/dist/types/entity_views.d.ts +3 -3
  33. package/dist/types/filter-operators.d.ts +62 -17
  34. package/dist/types/index.d.ts +1 -0
  35. package/dist/types/modify_collections.d.ts +2 -2
  36. package/dist/types/plugins.d.ts +9 -9
  37. package/dist/types/policy.d.ts +111 -11
  38. package/dist/types/properties.d.ts +54 -9
  39. package/dist/types/relations.d.ts +3 -3
  40. package/dist/types/slots.d.ts +14 -14
  41. package/dist/types/translations.d.ts +5 -1
  42. package/dist/types/user_management_delegate.d.ts +8 -2
  43. package/dist/types/websockets.d.ts +46 -13
  44. package/dist/users/user.d.ts +21 -9
  45. package/package.json +5 -6
  46. package/src/controllers/auth.tsx +7 -1
  47. package/src/controllers/client.ts +235 -7
  48. package/src/controllers/collection_registry.ts +3 -3
  49. package/src/controllers/customization_controller.tsx +1 -1
  50. package/src/controllers/data.ts +330 -39
  51. package/src/controllers/data_driver.ts +93 -40
  52. package/src/controllers/email.ts +2 -2
  53. package/src/controllers/index.ts +1 -1
  54. package/src/controllers/local_config_persistence.tsx +4 -4
  55. package/src/controllers/navigation.ts +2 -2
  56. package/src/controllers/registry.ts +22 -8
  57. package/src/controllers/{side_entity_controller.tsx → side_panel_controller.tsx} +7 -7
  58. package/src/controllers/storage.ts +60 -1
  59. package/src/errors.ts +80 -0
  60. package/src/index.ts +1 -0
  61. package/src/rebase_context.tsx +8 -4
  62. package/src/types/auth_adapter.ts +29 -4
  63. package/src/types/backend.ts +44 -36
  64. package/src/types/backup.ts +26 -0
  65. package/src/types/builders.ts +2 -2
  66. package/src/types/collections.ts +101 -91
  67. package/src/types/component_overrides.ts +72 -5
  68. package/src/types/cron.ts +11 -2
  69. package/src/types/data_source.ts +24 -2
  70. package/src/types/database_adapter.ts +19 -4
  71. package/src/types/entities.ts +7 -7
  72. package/src/types/entity_actions.tsx +7 -7
  73. package/src/types/entity_callbacks.ts +42 -42
  74. package/src/types/entity_views.tsx +3 -3
  75. package/src/types/filter-operators.ts +96 -23
  76. package/src/types/index.ts +1 -0
  77. package/src/types/modify_collections.tsx +2 -2
  78. package/src/types/plugins.tsx +9 -9
  79. package/src/types/policy.ts +114 -9
  80. package/src/types/properties.ts +58 -9
  81. package/src/types/relations.ts +3 -3
  82. package/src/types/slots.tsx +14 -14
  83. package/src/types/translations.ts +5 -1
  84. package/src/types/user_management_delegate.ts +8 -2
  85. package/src/types/websockets.ts +43 -14
  86. package/src/users/user.ts +22 -9
  87. package/dist/index.umd.js +0 -458
  88. package/dist/index.umd.js.map +0 -1
@@ -1,3 +1,5 @@
1
+ import { ALL_WHERE_FILTER_OPS, WhereFilterOp } from "./filter-operators";
2
+
1
3
  /**
2
4
  * Describes the capabilities and features supported by a data source (driver).
3
5
  *
@@ -35,6 +37,17 @@ export interface DataSourceCapabilities {
35
37
  /** Does this source support real-time listeners? */
36
38
  supportsRealtime: boolean;
37
39
 
40
+ /**
41
+ * Canonical filter operators this engine can execute.
42
+ *
43
+ * The admin UI intersects this set with the property-type defaults and
44
+ * any per-property narrowing (`property.ui.filterOperators`) to decide
45
+ * which operators to offer in filter fields — so an engine that cannot
46
+ * run `ilike` (e.g. Firestore) never shows a "Contains" filter that
47
+ * would throw at query time.
48
+ */
49
+ filterOperators: readonly WhereFilterOp[];
50
+
38
51
  // ── Admin capability flags ───────────────────────────────────────
39
52
  /** Does this source support SQL admin operations (SQL editor, EXPLAIN, etc.)? */
40
53
  supportsSQLAdmin: boolean;
@@ -102,9 +115,11 @@ export interface DataSourceDefinition {
102
115
  engine: string;
103
116
 
104
117
  /**
105
- * How the frontend reaches this source. Defaults to `"server"`.
118
+ * How the frontend reaches this source. Optional when omitted it is
119
+ * inferred: `"direct"` if the definition carries a client-side driver,
120
+ * `"server"` otherwise.
106
121
  */
107
- transport: DataSourceTransport;
122
+ transport?: DataSourceTransport;
108
123
 
109
124
  /**
110
125
  * The physical database/schema/Firestore-database within the engine.
@@ -149,6 +164,7 @@ export const POSTGRES_CAPABILITIES: DataSourceCapabilities = {
149
164
  supportsReferences: false,
150
165
  supportsColumnTypes: true,
151
166
  supportsRealtime: true,
167
+ filterOperators: ALL_WHERE_FILTER_OPS,
152
168
  supportsSQLAdmin: true,
153
169
  supportsDocumentAdmin: false,
154
170
  supportsSchemaAdmin: true
@@ -164,6 +180,10 @@ export const FIREBASE_CAPABILITIES: DataSourceCapabilities = {
164
180
  supportsReferences: true,
165
181
  supportsColumnTypes: false,
166
182
  supportsRealtime: true,
183
+ // Firestore has no SQL pattern matching — the driver throws on the LIKE
184
+ // family, so the UI must never offer it.
185
+ filterOperators: ALL_WHERE_FILTER_OPS.filter(op =>
186
+ op !== "like" && op !== "ilike" && op !== "not-like" && op !== "not-ilike"),
167
187
  supportsSQLAdmin: false,
168
188
  supportsDocumentAdmin: false,
169
189
  supportsSchemaAdmin: false
@@ -179,6 +199,7 @@ export const MONGODB_CAPABILITIES: DataSourceCapabilities = {
179
199
  supportsReferences: true,
180
200
  supportsColumnTypes: false,
181
201
  supportsRealtime: false,
202
+ filterOperators: ALL_WHERE_FILTER_OPS,
182
203
  supportsSQLAdmin: false,
183
204
  supportsDocumentAdmin: true,
184
205
  supportsSchemaAdmin: true
@@ -198,6 +219,7 @@ export const DEFAULT_CAPABILITIES: DataSourceCapabilities = {
198
219
  supportsReferences: true,
199
220
  supportsColumnTypes: true,
200
221
  supportsRealtime: true,
222
+ filterOperators: ALL_WHERE_FILTER_OPS,
201
223
  supportsSQLAdmin: true,
202
224
  supportsDocumentAdmin: true,
203
225
  supportsSchemaAdmin: true
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * @example
11
11
  * ```ts
12
- * import { createPostgresAdapter } from "@rebasepro/server-postgresql";
12
+ * import { createPostgresAdapter } from "@rebasepro/server-postgres";
13
13
  *
14
14
  * initializeRebaseBackend({
15
15
  * database: createPostgresAdapter({ connection: db, schema }),
@@ -21,7 +21,7 @@
21
21
  */
22
22
 
23
23
  import type { DataDriver } from "../controllers/data_driver";
24
- import type { EntityCollection } from "./collections";
24
+ import type { CollectionConfig } from "./collections";
25
25
  import type {
26
26
  CollectionRegistryInterface,
27
27
  DatabaseAdmin,
@@ -29,6 +29,7 @@ import type {
29
29
  RealtimeProvider,
30
30
  BootstrappedAuth
31
31
  } from "./backend";
32
+ import type { HistoryConfig } from "../controllers/client";
32
33
 
33
34
  /**
34
35
  * A `DatabaseAdapter` provides data persistence for Rebase.
@@ -75,7 +76,7 @@ export interface DatabaseAdapter {
75
76
  * Return `undefined` if the database does not support history.
76
77
  */
77
78
  initializeHistory?(
78
- config: unknown,
79
+ config: HistoryConfig,
79
80
  driverResult: InitializedDriver,
80
81
  ): Promise<{ historyService: unknown } | undefined>;
81
82
 
@@ -114,7 +115,21 @@ export interface DatabaseAdapter {
114
115
  */
115
116
  export interface DatabaseAdapterInitConfig {
116
117
  /** Registered collection definitions. */
117
- collections: EntityCollection[];
118
+ collections: CollectionConfig[];
118
119
  /** The shared collection registry to register into. */
119
120
  collectionRegistry: CollectionRegistryInterface;
121
+ /**
122
+ * How the server is being run — see `RebaseBackendConfig.mode`.
123
+ *
124
+ * In `"baas"` mode `collections` is empty by design: a driver that can
125
+ * describe its own schema should introspect the database and report the
126
+ * collections it found back on `InitializedDriver.collections`. Drivers
127
+ * that cannot introspect may ignore this.
128
+ */
129
+ mode?: "cms" | "baas";
130
+ /**
131
+ * `baas`-mode options — see `RebaseBackendConfig.baas`. Drivers that
132
+ * introspect should honour `unprotectedTables`.
133
+ */
134
+ baas?: { unprotectedTables?: "exclude" | "serve" };
120
135
  }
@@ -5,7 +5,7 @@
5
5
  export type EntityStatus = "new" | "existing" | "copy";
6
6
 
7
7
  /**
8
- * Representation of an entity fetched from the driver
8
+ * Representation of a entity fetched from the driver
9
9
  * @group Models
10
10
  */
11
11
  export interface Entity<M extends Record<string, unknown> = Record<string, unknown>> {
@@ -47,7 +47,7 @@ export interface Entity<M extends Record<string, unknown> = Record<string, unkno
47
47
  export type EntityValues<M extends Record<string, unknown>> = M;
48
48
 
49
49
  /**
50
- * Props for creating an EntityReference
50
+ * Props for creating a EntityReference
51
51
  */
52
52
  export interface EntityReferenceProps {
53
53
  /** ID of the entity */
@@ -61,7 +61,7 @@ export interface EntityReferenceProps {
61
61
  }
62
62
 
63
63
  /**
64
- * Class used to create a reference to an entity in a different path.
64
+ * Class used to create a reference to a entity in a different path.
65
65
  *
66
66
  * @example
67
67
  * // Simple reference (most common case - single driver, single db)
@@ -99,7 +99,7 @@ export class EntityReference {
99
99
  readonly databaseId?: string;
100
100
 
101
101
  /**
102
- * Create a reference to an entity.
102
+ * Create a reference to a entity.
103
103
  *
104
104
  * @example
105
105
  * // Simple reference (most common case)
@@ -148,7 +148,7 @@ export class EntityReference {
148
148
  }
149
149
 
150
150
  /**
151
- * Class used to create a reference to an entity in a different path
151
+ * Class used to create a reference to a entity in a different path
152
152
  */
153
153
  export class EntityRelation {
154
154
 
@@ -167,9 +167,9 @@ export class EntityRelation {
167
167
  * Pre-fetched data payload to eliminate N+1 queries.
168
168
  * When present, clients can use this directly instead of fetching.
169
169
  */
170
- readonly data?: Entity;
170
+ readonly data?: Record<string, unknown>;
171
171
 
172
- constructor(id: string | number, path: string, data?: Entity) {
172
+ constructor(id: string | number, path: string, data?: Record<string, unknown>) {
173
173
  this.id = id;
174
174
  this.path = path;
175
175
  this.data = data;
@@ -1,13 +1,13 @@
1
1
  import React from "react";
2
2
  import type { Entity } from "./entities";
3
- import type { EntityCollection, SelectionController } from "./collections";
3
+ import type { CollectionConfig, SelectionController } from "./collections";
4
4
  import type { FormContext } from "./entity_views";
5
5
  import type { User } from "../users";
6
6
  import type { RebaseContext } from "../rebase_context";
7
- import type { SideEntityController } from "../controllers/side_entity_controller";
7
+ import type { SidePanelController } from "../controllers/side_panel_controller";
8
8
 
9
9
  /**
10
- * An entity action is a custom action that can be performed on an entity.
10
+ * A entity action is a custom action that can be performed on a entity.
11
11
  * They are displayed in the entity view and in the collection view.
12
12
  */
13
13
  export interface EntityAction<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
@@ -72,7 +72,7 @@ export type EntityActionClickProps<M extends Record<string, unknown>, USER exten
72
72
  context?: RebaseContext<USER>;
73
73
 
74
74
  path?: string;
75
- collection?: EntityCollection<M>;
75
+ collection?: CollectionConfig<M>;
76
76
 
77
77
  /**
78
78
  * Optional form context, present if the action is being called from a form.
@@ -83,7 +83,7 @@ export type EntityActionClickProps<M extends Record<string, unknown>, USER exten
83
83
  /**
84
84
  * Present if this actions is being called from a side dialog only
85
85
  */
86
- sideEntityController?: SideEntityController;
86
+ sidePanelController?: SidePanelController;
87
87
 
88
88
  /**
89
89
  * Is the action being called from the collection view or from the entity form view?
@@ -113,12 +113,12 @@ export type EntityActionClickProps<M extends Record<string, unknown>, USER exten
113
113
  unhighlightEntity?: (entity: Entity<Record<string, unknown>>) => void;
114
114
 
115
115
  /**
116
- * Optional function to navigate back (e.g. when deleting an entity or navigating from a form)
116
+ * Optional function to navigate back (e.g. when deleting a entity or navigating from a form)
117
117
  */
118
118
  navigateBack?: () => void;
119
119
 
120
120
  /**
121
- * Callback to be called when the collection changes, e.g. after an entity is deleted or created.
121
+ * Callback to be called when the collection changes, e.g. after a entity is deleted or created.
122
122
  */
123
123
  onCollectionChange?: () => void;
124
124
 
@@ -1,5 +1,5 @@
1
- import type { EntityCollection } from "./collections";
2
- import type { Entity, EntityStatus, EntityValues } from "./entities";
1
+ import type { CollectionConfig } from "./collections";
2
+ import type { EntityStatus, EntityValues } from "./entities";
3
3
  import type { User } from "../users";
4
4
  import type { RebaseCallContext } from "../rebase_context";
5
5
 
@@ -7,7 +7,7 @@ import type { RebaseCallContext } from "../rebase_context";
7
7
  * Lifecycle callbacks for entity CRUD operations.
8
8
  *
9
9
  * Register per-collection on the collection's `callbacks` field, or globally
10
- * via `initBackend({ callbacks })`. Fires on **every** data path — REST API,
10
+ * via `initializeRebaseBackend({ callbacks })`. Fires on **every** data path — REST API,
11
11
  * WebSocket / realtime subscriptions, and server-side `rebase.data`.
12
12
  *
13
13
  * When both global and per-collection callbacks are registered, execution
@@ -15,7 +15,7 @@ import type { RebaseCallContext } from "../rebase_context";
15
15
  *
16
16
  * @group Models
17
17
  */
18
- export type EntityCallbacks<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = {
18
+ export type CollectionCallbacks<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = {
19
19
 
20
20
  /**
21
21
  * Callback used after fetching data.
@@ -25,19 +25,19 @@ export type EntityCallbacks<M extends Record<string, unknown> = Record<string, u
25
25
  *
26
26
  * @param props
27
27
  */
28
- afterRead?(props: EntityAfterReadProps<M, USER>)
29
- : Promise<Entity<M>> | Entity<M>;
28
+ afterRead?(props: AfterReadProps<M, USER>)
29
+ : Promise<Record<string, unknown>> | Record<string, unknown>;
30
30
 
31
31
 
32
32
  /**
33
33
  * Callback used before saving, you need to return the values that will get
34
34
  * saved. If you throw an error in this method the process stops, and an
35
- * error snackbar gets displayed.
35
+ * HTTP error response is returned to the client.
36
36
  * This runs after schema validation.
37
37
  *
38
38
  * @param props
39
39
  */
40
- beforeSave?(props: EntityBeforeSaveProps<M, USER>)
40
+ beforeSave?(props: BeforeSaveProps<M, USER>)
41
41
  : Promise<Partial<EntityValues<M>>> | Partial<EntityValues<M>>;
42
42
 
43
43
  /**
@@ -45,44 +45,44 @@ export type EntityCallbacks<M extends Record<string, unknown> = Record<string, u
45
45
  *
46
46
  * @param props
47
47
  */
48
- afterSave?(props: EntityAfterSaveProps<M, USER>)
48
+ afterSave?(props: AfterSaveProps<M, USER>)
49
49
  : Promise<void> | void;
50
50
 
51
51
  /**
52
52
  * Callback used when saving fails
53
53
  * @param props
54
54
  */
55
- afterSaveError?(props: EntityAfterSaveErrorProps<M, USER>)
55
+ afterSaveError?(props: AfterSaveErrorProps<M, USER>)
56
56
  : Promise<void> | void;
57
57
 
58
58
  /**
59
59
  * Callback used before the entity is deleted.
60
60
  * If you throw an error in this method the process stops, and an
61
- * error snackbar gets displayed.
61
+ * HTTP error response is returned to the client.
62
62
  *
63
63
  * @param props
64
64
  */
65
- beforeDelete?(props: EntityBeforeDeleteProps<M, USER>): Promise<boolean | void> | boolean | void;
65
+ beforeDelete?(props: BeforeDeleteProps<M, USER>): Promise<boolean | void> | boolean | void;
66
66
 
67
67
  /**
68
68
  * Callback used after the entity is deleted.
69
69
  *
70
70
  * @param props
71
71
  */
72
- afterDelete?(props: EntityAfterDeleteProps<M, USER>): Promise<void> | void;
72
+ afterDelete?(props: AfterDeleteProps<M, USER>): Promise<void> | void;
73
73
 
74
74
  }
75
75
 
76
76
  /**
77
- * Parameters passed to hooks when an entity is fetched
77
+ * Parameters passed to hooks when a entity is fetched
78
78
  * @group Models
79
79
  */
80
- export interface EntityAfterReadProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
80
+ export interface AfterReadProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
81
81
 
82
82
  /**
83
83
  * Collection of the entity
84
84
  */
85
- collection: EntityCollection<M>;
85
+ collection: CollectionConfig<M>;
86
86
 
87
87
  /**
88
88
  * Full path of the CMS where this collection is being fetched.
@@ -91,9 +91,9 @@ export interface EntityAfterReadProps<M extends Record<string, unknown> = Record
91
91
  path: string;
92
92
 
93
93
  /**
94
- * Fetched entity
94
+ * Fetched row (flat — the table's columns)
95
95
  */
96
- entity: Entity<M>
96
+ row: Record<string, unknown>
97
97
 
98
98
  /**
99
99
  * Context of the app status
@@ -102,34 +102,34 @@ export interface EntityAfterReadProps<M extends Record<string, unknown> = Record
102
102
  }
103
103
 
104
104
  /**
105
- * Parameters passed to hooks before an entity is saved
105
+ * Parameters passed to hooks before a entity is saved
106
106
  * @group Models
107
107
  */
108
- export type EntityBeforeSaveProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> =
109
- Omit<EntityAfterSaveProps<M, USER>, "entityId">
108
+ export type BeforeSaveProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> =
109
+ Omit<AfterSaveProps<M, USER>, "id">
110
110
  & {
111
- entityId?: string | number;
111
+ id?: string | number;
112
112
  }
113
113
  /**
114
- * Parameters passed to hooks before an entity is saved
114
+ * Parameters passed to hooks before a entity is saved
115
115
  * @group Models
116
116
  */
117
- export type EntityAfterSaveErrorProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> =
118
- Omit<EntityAfterSaveProps<M, USER>, "entityId">
117
+ export type AfterSaveErrorProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> =
118
+ Omit<AfterSaveProps<M, USER>, "id">
119
119
  & {
120
- entityId?: string | number;
120
+ id?: string | number;
121
121
  }
122
122
 
123
123
  /**
124
- * Parameters passed to hooks when an entity is saved
124
+ * Parameters passed to hooks when a entity is saved
125
125
  * @group Models
126
126
  */
127
- export interface EntityAfterSaveProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
127
+ export interface AfterSaveProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
128
128
 
129
129
  /**
130
130
  * Resolved collection of the entity
131
131
  */
132
- collection: EntityCollection<M>;
132
+ collection: CollectionConfig<M>;
133
133
 
134
134
  /**
135
135
  * Full path of the CMS where this entity is being saved.
@@ -140,7 +140,7 @@ export interface EntityAfterSaveProps<M extends Record<string, unknown> = Record
140
140
  /**
141
141
  * ID of the entity
142
142
  */
143
- entityId: string | number;
143
+ id: string | number;
144
144
 
145
145
  /**
146
146
  * Values being saved
@@ -164,15 +164,15 @@ export interface EntityAfterSaveProps<M extends Record<string, unknown> = Record
164
164
  }
165
165
 
166
166
  /**
167
- * Parameters passed to hooks when an entity is deleted
167
+ * Parameters passed to hooks when a entity is deleted
168
168
  * @group Models
169
169
  */
170
- export interface EntityBeforeDeleteProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
170
+ export interface BeforeDeleteProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
171
171
 
172
172
  /**
173
173
  * collection of the entity being deleted
174
174
  */
175
- collection: EntityCollection<M>;
175
+ collection: CollectionConfig<M>;
176
176
 
177
177
  /**
178
178
  * Path of the parent collection
@@ -182,12 +182,12 @@ export interface EntityBeforeDeleteProps<M extends Record<string, unknown> = Rec
182
182
  /**
183
183
  * Deleted entity id
184
184
  */
185
- entityId: string | number;
185
+ id: string | number;
186
186
 
187
187
  /**
188
- * Deleted entity
188
+ * Deleted row (flat — the table's columns)
189
189
  */
190
- entity: Entity<M>;
190
+ row: Record<string, unknown>;
191
191
 
192
192
  /**
193
193
  * Context of the app status
@@ -196,15 +196,15 @@ export interface EntityBeforeDeleteProps<M extends Record<string, unknown> = Rec
196
196
  }
197
197
 
198
198
  /**
199
- * Parameters passed to hooks after an entity is deleted
199
+ * Parameters passed to hooks after a entity is deleted
200
200
  * @group Models
201
201
  */
202
- export interface EntityAfterDeleteProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
202
+ export interface AfterDeleteProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {
203
203
 
204
204
  /**
205
205
  * collection of the entity being deleted
206
206
  */
207
- collection: EntityCollection<M>;
207
+ collection: CollectionConfig<M>;
208
208
 
209
209
  /**
210
210
  * Path of the parent collection
@@ -214,12 +214,12 @@ export interface EntityAfterDeleteProps<M extends Record<string, unknown> = Reco
214
214
  /**
215
215
  * Deleted entity id
216
216
  */
217
- entityId: string | number;
217
+ id: string | number;
218
218
 
219
219
  /**
220
- * Deleted entity
220
+ * Deleted row (flat — the table's columns)
221
221
  */
222
- entity: Entity<M>;
222
+ row: Record<string, unknown>;
223
223
 
224
224
  /**
225
225
  * Context of the app status
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import type { Entity, EntityValues } from "./entities";
3
- import type { EntityCollection } from "./collections";
3
+ import type { CollectionConfig } from "./collections";
4
4
  import type { FormexController } from "./formex";
5
5
  import type { ComponentRef } from "./component_ref";
6
6
 
@@ -37,7 +37,7 @@ export interface FormContext<M extends Record<string, unknown> = Record<string,
37
37
  /**
38
38
  * Collection of the entity being modified
39
39
  */
40
- collection?: EntityCollection<M>;
40
+ collection?: CollectionConfig<M>;
41
41
 
42
42
  /**
43
43
  * Entity id, it can be undefined if it's a new entity
@@ -105,7 +105,7 @@ export type FormViewConfig<M extends Record<string, unknown> = Record<string, un
105
105
  };
106
106
 
107
107
  export interface EntityCustomViewParams<M extends Record<string, unknown> = Record<string, unknown>> {
108
- collection: EntityCollection<M>;
108
+ collection: CollectionConfig<M>;
109
109
  entity?: Entity<M>;
110
110
  modifiedValues?: EntityValues<M>;
111
111
  formContext: FormContext<M>;
@@ -8,24 +8,50 @@
8
8
  * HTTP wire boundary, handled by `serializeFilter` / `deserializeFilter`
9
9
  * in `@rebasepro/common`.
10
10
  *
11
- * ┌──────────────────┬───────────────┬──────────────────────────┐
12
- * │ Canonical │ REST short │ Meaning
13
- * ├──────────────────┼───────────────┼──────────────────────────┤
14
- * │ "==" │ "eq" │ Equal
15
- * │ "!=" │ "neq" │ Not equal
16
- * │ ">" │ "gt" │ Greater than
17
- * │ ">=" │ "gte" │ Greater than or equal
18
- * │ "<" │ "lt" │ Less than
19
- * │ "<=" │ "lte" │ Less than or equal
20
- * │ "in" │ "in" │ Value in list
21
- * │ "not-in" │ "nin" │ Value not in list
22
- * │ "array-contains" │ "cs" │ Array contains element
23
- * │ "array-contains-any" │ "csa" │ Array contains any of
24
- * └──────────────────┴───────────────┴──────────────────────────┘
11
+ * ┌──────────────────────┬───────────────┬──────────────────────────────┐
12
+ * │ Canonical │ REST short │ Meaning
13
+ * ├──────────────────────┼───────────────┼──────────────────────────────┤
14
+ * │ "==" │ "eq" │ Equal
15
+ * │ "!=" │ "neq" │ Not equal
16
+ * │ ">" │ "gt" │ Greater than
17
+ * │ ">=" │ "gte" │ Greater than or equal
18
+ * │ "<" │ "lt" │ Less than
19
+ * │ "<=" │ "lte" │ Less than or equal
20
+ * │ "in" │ "in" │ Value in list
21
+ * │ "not-in" │ "nin" │ Value not in list
22
+ * │ "array-contains" │ "cs" │ Array contains element
23
+ * │ "array-contains-any" │ "csa" │ Array contains any of
24
+ * │ "like" │ "like" │ SQL LIKE (case-sensitive) │
25
+ * │ "ilike" │ "ilike" │ SQL ILIKE (case-insensitive) │
26
+ * │ "not-like" │ "nlike" │ NOT LIKE (case-sensitive) │
27
+ * │ "not-ilike" │ "nilike" │ NOT ILIKE (case-insensitive) │
28
+ * │ "is-null" │ "isnull" │ Field IS NULL │
29
+ * │ "is-not-null" │ "notnull" │ Field IS NOT NULL │
30
+ * └──────────────────────┴───────────────┴──────────────────────────────┘
31
+ *
32
+ * Pattern matching (`like`/`ilike`) uses SQL wildcard syntax: `%` matches any
33
+ * sequence of characters, `_` matches a single character. On MongoDB these are
34
+ * translated to anchored regular expressions; Firestore has no native pattern
35
+ * matching and rejects these operators (use `searchString` instead).
25
36
  *
26
37
  * @module
27
38
  */
28
39
 
40
+ /**
41
+ * Canonical sort representation: `[fieldName, direction]`.
42
+ *
43
+ * Used in `FindParams.orderBy`, `collection.sort`, and `FilterPreset.sort`.
44
+ * The colon-string form (`"field:direction"`) exists only at the HTTP wire
45
+ * boundary, handled by `serializeOrderBy` / `deserializeOrderBy` in
46
+ * `@rebasepro/common`.
47
+ *
48
+ * Design note: the natural extension for multi-column sort is
49
+ * `OrderByTuple[]` — not implemented yet (server consumes only the first).
50
+ *
51
+ * @group Models
52
+ */
53
+ export type OrderByTuple<Key extends string = string> = [Key, "asc" | "desc"];
54
+
29
55
  /**
30
56
  * Canonical filter operators supported across all database backends.
31
57
  * Each DB driver translates these to its native query format.
@@ -42,7 +68,13 @@ export type WhereFilterOp =
42
68
  | "array-contains"
43
69
  | "in"
44
70
  | "not-in"
45
- | "array-contains-any";
71
+ | "array-contains-any"
72
+ | "like"
73
+ | "ilike"
74
+ | "not-like"
75
+ | "not-ilike"
76
+ | "is-null"
77
+ | "is-not-null";
46
78
 
47
79
  /**
48
80
  * Used to define filters applied in collections.
@@ -61,6 +93,14 @@ export type WhereFilterOp =
61
93
  * { role: ["in", ["admin", "editor"]] }
62
94
  * { tags: ["array-contains", "featured"] }
63
95
  *
96
+ * // Pattern matching (SQL wildcards: % and _)
97
+ * { name: ["ilike", "%john%"] }
98
+ * { slug: ["like", "post-%"] }
99
+ *
100
+ * // Null checks (the value is ignored; `null` is conventional)
101
+ * { deleted_at: ["is-null", null] }
102
+ * { published_at: ["is-not-null", null] }
103
+ *
64
104
  * @group Models
65
105
  */
66
106
  export type FilterValues<Key extends string> =
@@ -101,7 +141,7 @@ export interface FilterPreset<Key extends string = string> {
101
141
  /**
102
142
  * Optional sort override to apply alongside the filter values.
103
143
  */
104
- sort?: [Key, "asc" | "desc"];
144
+ sort?: OrderByTuple<Key>;
105
145
  }
106
146
 
107
147
  /**
@@ -114,7 +154,10 @@ export type RestFilterOp =
114
154
  | "gt" | "gte"
115
155
  | "lt" | "lte"
116
156
  | "in" | "nin"
117
- | "cs" | "csa";
157
+ | "cs" | "csa"
158
+ | "like" | "ilike"
159
+ | "nlike" | "nilike"
160
+ | "isnull" | "notnull";
118
161
 
119
162
  /** Maps canonical operators to their REST short-code equivalents. */
120
163
  export const CANONICAL_TO_REST: Readonly<Record<WhereFilterOp, RestFilterOp>> = {
@@ -127,7 +170,13 @@ export const CANONICAL_TO_REST: Readonly<Record<WhereFilterOp, RestFilterOp>> =
127
170
  "in": "in",
128
171
  "not-in": "nin",
129
172
  "array-contains": "cs",
130
- "array-contains-any": "csa"
173
+ "array-contains-any": "csa",
174
+ "like": "like",
175
+ "ilike": "ilike",
176
+ "not-like": "nlike",
177
+ "not-ilike": "nilike",
178
+ "is-null": "isnull",
179
+ "is-not-null": "notnull"
131
180
  };
132
181
 
133
182
  /** Maps REST short-code operators to their canonical equivalents. */
@@ -141,15 +190,39 @@ export const REST_TO_CANONICAL: Readonly<Record<RestFilterOp, WhereFilterOp>> =
141
190
  "in": "in",
142
191
  "nin": "not-in",
143
192
  "cs": "array-contains",
144
- "csa": "array-contains-any"
193
+ "csa": "array-contains-any",
194
+ "like": "like",
195
+ "ilike": "ilike",
196
+ "nlike": "not-like",
197
+ "nilike": "not-ilike",
198
+ "isnull": "is-null",
199
+ "notnull": "is-not-null"
145
200
  };
146
201
 
147
- /** All canonical operator strings for runtime validation. */
148
- const CANONICAL_OPS: ReadonlySet<string> = new Set<WhereFilterOp>([
202
+ /**
203
+ * Operators that test for null/not-null and therefore ignore their value.
204
+ * Codecs normalize the value of these conditions to `null`.
205
+ */
206
+ export const NULL_OPS: ReadonlySet<WhereFilterOp> = new Set<WhereFilterOp>([
207
+ "is-null", "is-not-null"
208
+ ]);
209
+
210
+ /**
211
+ * Every canonical operator, in a stable order. Useful for engine capability
212
+ * declarations ({@link DataSourceCapabilities.filterOperators}) and for
213
+ * building operator subsets.
214
+ * @group Models
215
+ */
216
+ export const ALL_WHERE_FILTER_OPS: readonly WhereFilterOp[] = [
149
217
  "<", "<=", "==", "!=", ">=", ">",
150
218
  "in", "not-in",
151
- "array-contains", "array-contains-any"
152
- ]);
219
+ "array-contains", "array-contains-any",
220
+ "like", "ilike", "not-like", "not-ilike",
221
+ "is-null", "is-not-null"
222
+ ];
223
+
224
+ /** All canonical operator strings for runtime validation. */
225
+ const CANONICAL_OPS: ReadonlySet<string> = new Set<WhereFilterOp>(ALL_WHERE_FILTER_OPS);
153
226
 
154
227
  /**
155
228
  * Resolve any operator string (canonical or REST short-code) to its