Skip to content

Commit 0726714

Browse files
committed
Enhance entity handling with typed sorting and import results
- Introduced `SortField` type for improved sorting parameter handling in list and filter methods. - Updated `importEntities` method to return a structured `ImportResult` type, providing detailed import status and output. - Modified list and filter methods to support generic field selection, enhancing type safety and flexibility.
1 parent 4b25c61 commit 0726714

File tree

2 files changed

+64
-22
lines changed

2 files changed

+64
-22
lines changed

src/modules/entities.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import {
44
DeleteResult,
55
EntitiesModule,
66
EntityHandler,
7+
ImportResult,
78
RealtimeCallback,
89
RealtimeEvent,
910
RealtimeEventType,
11+
SortField,
1012
} from "./entities.types";
1113
import { RoomsSocket } from "../utils/socket-utils.js";
1214

@@ -91,12 +93,12 @@ function createEntityHandler<T = any>(
9193

9294
return {
9395
// List entities with optional pagination and sorting
94-
async list(
95-
sort?: string,
96+
async list<K extends keyof T = keyof T>(
97+
sort?: SortField<T>,
9698
limit?: number,
9799
skip?: number,
98-
fields?: string[]
99-
): Promise<T[]> {
100+
fields?: K[]
101+
): Promise<Pick<T, K>[]> {
100102
const params: Record<string, string | number> = {};
101103
if (sort) params.sort = sort;
102104
if (limit) params.limit = limit;
@@ -108,13 +110,13 @@ function createEntityHandler<T = any>(
108110
},
109111

110112
// Filter entities based on query
111-
async filter(
113+
async filter<K extends keyof T = keyof T>(
112114
query: Partial<T>,
113-
sort?: string,
115+
sort?: SortField<T>,
114116
limit?: number,
115117
skip?: number,
116-
fields?: string[]
117-
): Promise<T[]> {
118+
fields?: K[]
119+
): Promise<Pick<T, K>[]> {
118120
const params: Record<string, string | number> = {
119121
q: JSON.stringify(query),
120122
};
@@ -159,7 +161,7 @@ function createEntityHandler<T = any>(
159161
},
160162

161163
// Import entities from a file
162-
async importEntities(file: File): Promise<any> {
164+
async importEntities(file: File): Promise<ImportResult<T>> {
163165
const formData = new FormData();
164166
formData.append("file", file, file.name);
165167

src/modules/entities.types.ts

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,42 @@ export interface DeleteManyResult {
4444
deleted: number;
4545
}
4646

47+
/**
48+
* Result returned when importing entities from a file.
49+
*
50+
* @typeParam T - The entity type for imported records. Defaults to `any`.
51+
*/
52+
export interface ImportResult<T = any> {
53+
/** Status of the import operation */
54+
status: "success" | "error";
55+
/** Details message, e.g., "Successfully imported 3 entities with RLS enforcement" */
56+
details: string | null;
57+
/** Array of created entity objects when successful, or null on error */
58+
output: T[] | null;
59+
}
60+
61+
/**
62+
* Sort field type for entity queries.
63+
*
64+
* Supports ascending (no prefix or `'+'`) and descending (`'-'`) sorting.
65+
*
66+
* @typeParam T - The entity type to derive sortable fields from.
67+
*
68+
* @example
69+
* ```typescript
70+
* // Ascending sort (default)
71+
* 'created_date'
72+
* '+created_date'
73+
*
74+
* // Descending sort
75+
* '-created_date'
76+
* ```
77+
*/
78+
export type SortField<T> =
79+
| (keyof T & string)
80+
| `+${keyof T & string}`
81+
| `-${keyof T & string}`;
82+
4783
/**
4884
* Entity handler providing CRUD operations for a specific entity type.
4985
*
@@ -60,11 +96,12 @@ export interface EntityHandler<T = any> {
6096
*
6197
* **Note:** The maximum limit is 5,000 items per request.
6298
*
99+
* @typeParam K - The fields to include in the response. Defaults to all fields.
63100
* @param sort - Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`.
64101
* @param limit - Maximum number of results to return. Defaults to `50`.
65102
* @param skip - Number of results to skip for pagination. Defaults to `0`.
66103
* @param fields - Array of field names to include in the response. Defaults to all fields.
67-
* @returns Promise resolving to an array of records.
104+
* @returns Promise resolving to an array of records with selected fields.
68105
*
69106
* @example
70107
* ```typescript
@@ -91,12 +128,12 @@ export interface EntityHandler<T = any> {
91128
* const fields = await base44.entities.MyEntity.list('-created_date', 10, 0, ['name', 'status']);
92129
* ```
93130
*/
94-
list(
95-
sort?: string,
131+
list<K extends keyof T = keyof T>(
132+
sort?: SortField<T>,
96133
limit?: number,
97134
skip?: number,
98-
fields?: string[]
99-
): Promise<T[]>;
135+
fields?: K[]
136+
): Promise<Pick<T, K>[]>;
100137

101138
/**
102139
* Filters records based on a query.
@@ -106,14 +143,15 @@ export interface EntityHandler<T = any> {
106143
*
107144
* **Note:** The maximum limit is 5,000 items per request.
108145
*
146+
* @typeParam K - The fields to include in the response. Defaults to all fields.
109147
* @param query - Query object with field-value pairs. Each key should be a field name
110148
* from your entity schema, and each value is the criteria to match. Records matching all
111149
* specified criteria are returned. Field names are case-sensitive.
112150
* @param sort - Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`.
113151
* @param limit - Maximum number of results to return. Defaults to `50`.
114152
* @param skip - Number of results to skip for pagination. Defaults to `0`.
115153
* @param fields - Array of field names to include in the response. Defaults to all fields.
116-
* @returns Promise resolving to an array of filtered records.
154+
* @returns Promise resolving to an array of filtered records with selected fields.
117155
*
118156
* @example
119157
* ```typescript
@@ -155,13 +193,13 @@ export interface EntityHandler<T = any> {
155193
* );
156194
* ```
157195
*/
158-
filter(
196+
filter<K extends keyof T = keyof T>(
159197
query: Partial<T>,
160-
sort?: string,
198+
sort?: SortField<T>,
161199
limit?: number,
162200
skip?: number,
163-
fields?: string[]
164-
): Promise<T[]>;
201+
fields?: K[]
202+
): Promise<Pick<T, K>[]>;
165203

166204
/**
167205
* Gets a single record by ID.
@@ -298,7 +336,7 @@ export interface EntityHandler<T = any> {
298336
* The file format should match your entity structure. Requires a browser environment and can't be used in the backend.
299337
*
300338
* @param file - File object to import.
301-
* @returns Promise resolving to the import result.
339+
* @returns Promise resolving to the import result containing status, details, and created records.
302340
*
303341
* @example
304342
* ```typescript
@@ -307,12 +345,14 @@ export interface EntityHandler<T = any> {
307345
* const file = event.target.files?.[0];
308346
* if (file) {
309347
* const result = await base44.entities.MyEntity.importEntities(file);
310-
* console.log(`Imported ${result.count} records`);
348+
* if (result.status === 'success' && result.output) {
349+
* console.log(`Imported ${result.output.length} records`);
350+
* }
311351
* }
312352
* };
313353
* ```
314354
*/
315-
importEntities(file: File): Promise<any>;
355+
importEntities(file: File): Promise<ImportResult<T>>;
316356

317357
/**
318358
* Subscribes to realtime updates for all records of this entity type.

0 commit comments

Comments
 (0)