@@ -4,6 +4,16 @@ import { StaticTables } from "../constants/constants";
44import DBServiceHelper from "../helpers/helperDbServices" ;
55import { FormTypes } from "../constants/constants" ;
66
7+ interface TableFilter {
8+ column : string ;
9+ condition : "=" | "IN" | "LIKE" ;
10+ values : string | string [ ] ;
11+ }
12+
13+ interface UpdateFilter {
14+ conditions : Record < string , any > ; // Object with search conditions
15+ updates : Record < string , any > ; // Object with updates to make
16+ }
717
818class OfflineFetchService {
919
@@ -12,29 +22,207 @@ class OfflineFetchService {
1222 * Ensures that the table is within the predefined static tables list.
1323 *
1424 * @param tableName - Name of the table to fetch data from.
25+ * @param filter - Optional filter object for filtering results
26+ * @param filter.column - The column name to filter on
27+ * @param filter.condition - The condition to apply ("=" | "IN" | "LIKE")
28+ * @param filter.values - The value(s) to filter by. String for "=" and "LIKE", string[] for "IN"
1529 * @returns A promise that resolves to an array of records from the table.
1630 * @throws Error if IndexedDB is unavailable, the table is inaccessible, or data retrieval fails.
1731 */
18- public static async fetchStaticDataFromTable ( tableName : string ) : Promise < any [ ] > {
32+ public static async fetchStaticDataFromTable (
33+ tableName : string ,
34+ filter ?: TableFilter
35+ ) : Promise < any [ ] > {
1936 try {
2037 if ( ! rsbcDb ) throw new Error ( "IndexedDB is not available." ) ;
21- if ( ! StaticTables . includes ( tableName ) ) throw new Error ( `Table ${ tableName } is not accessible.` ) ;
22-
38+ if ( ! StaticTables . includes ( tableName ) )
39+ throw new Error ( `Table ${ tableName } is not accessible.` ) ;
40+
2341 await rsbcDb . open ( ) ; // Ensure the database is open
24-
42+
2543 const table = rsbcDb [ tableName ] ;
26- if ( ! table ) throw new Error ( `Table ${ tableName } not found in IndexedDB.` ) ;
27-
28- const data = await table . toArray ( ) ;
29- if ( ! data . length ) console . warn ( `No data found in table ${ tableName } .` ) ;
30-
44+ if ( ! table ) {
45+ throw new Error ( `Table ${ tableName } not found in IndexedDB.` ) ;
46+ }
47+
48+ // Validate filter if provided
49+ if ( filter ) {
50+ if ( ! filter . column || ! filter . condition ) {
51+ throw new Error ( "Invalid filter: missing required properties" ) ;
52+ }
53+
54+ if ( filter . condition === "IN" && ! Array . isArray ( filter . values ) ) {
55+ throw new Error ( "Values must be an array for IN condition" ) ;
56+ }
57+ }
58+
59+ let data : any [ ] = [ ] ;
60+ if ( filter ) {
61+ const { column, condition, values } = filter ;
62+
63+ switch ( condition ) {
64+ case "=" :
65+ data = await table . where ( column ) . equals ( values ) . toArray ( ) ;
66+ break ;
67+
68+ case "IN" :
69+ data = await table
70+ . where ( column )
71+ . anyOf ( values as string [ ] )
72+ . toArray ( ) ;
73+ break ;
74+
75+ case "LIKE" :
76+ if ( typeof values !== "string" ) {
77+ throw new Error ( "Values must be a string for LIKE condition" ) ;
78+ }
79+ const allData = await table . toArray ( ) ;
80+ data = allData . filter ( ( item ) => {
81+ const itemValue = String ( item [ column ] || "" ) . toLowerCase ( ) ;
82+ const searchValue = String ( values || "" ) . toLowerCase ( ) ;
83+ return itemValue . includes ( searchValue ) ;
84+ } ) ;
85+ break ;
86+
87+ default :
88+ throw new Error ( `Unsupported condition: ${ condition } ` ) ;
89+ }
90+ } else {
91+ data = await table . toArray ( ) ;
92+ }
93+
94+ if ( ! data . length ) {
95+ console . warn ( `No data found in table ${ tableName } .` ) ;
96+ }
97+
3198 return data ;
3299 } catch ( error ) {
33100 console . error ( `Error fetching data from table ${ tableName } :` , error ) ;
34101 throw error ;
35102 }
36103 }
37104
105+ /**
106+ * Updates data in a static table in IndexedDB.
107+ * Ensures that the table is within the predefined static tables list.
108+ *
109+ * @param tableName - Name of the table to update data in
110+ * @param filter - Filter object for updating records
111+ * @param filter.conditions - Object with conditions to match records (e.g., {id: 3} or {date: "1990-12-12", status: "new"})
112+ * @param filter.updates - Object with updates to make (e.g., {status: "completed"})
113+ * @returns A promise that resolves to the number of updated records
114+ * @throws Error if IndexedDB is unavailable, the table is inaccessible, or update fails.
115+ */
116+ public static async updateStaticDataTable (
117+ tableName : string ,
118+ filter : UpdateFilter
119+ ) : Promise < number > {
120+ try {
121+ if ( ! rsbcDb ) {
122+ throw new Error ( "IndexedDB is not available." ) ;
123+ }
124+ if ( ! StaticTables . includes ( tableName ) ) {
125+ throw new Error ( `Table ${ tableName } is not accessible.` ) ;
126+ }
127+
128+ await rsbcDb . open ( ) ; // Ensure the database is open
129+
130+ // Get table using Dexie's table() method
131+ const table = rsbcDb . table ( tableName ) ;
132+ if ( ! table ) {
133+ throw new Error ( `Table ${ tableName } not found in IndexedDB.` ) ;
134+ }
135+
136+ // Validate filter
137+ if (
138+ ! filter ?. conditions ||
139+ ! filter ?. updates ||
140+ Object . keys ( filter . conditions ) . length === 0 ||
141+ Object . keys ( filter . updates ) . length === 0
142+ ) {
143+ throw new Error (
144+ "Invalid filter: conditions and updates are required and must not be empty"
145+ ) ;
146+ }
147+
148+ // Get all records first
149+ const allRecords = await table . toArray ( ) ;
150+
151+ // Filter records that match ALL conditions
152+ const recordsToUpdate = allRecords . filter ( ( record ) => {
153+ return Object . entries ( filter . conditions ) . every (
154+ ( [ key , value ] ) => record [ key ] === value
155+ ) ;
156+ } ) ;
157+
158+ // Update each record with all specified updates
159+ const updatePromises = recordsToUpdate . map ( async ( record ) => {
160+ // Apply all updates to the record
161+ Object . entries ( filter . updates ) . forEach ( ( [ key , value ] ) => {
162+ record [ key ] = value ;
163+ } ) ;
164+ return await table . put ( record ) ;
165+ } ) ;
166+
167+ await Promise . all ( updatePromises ) ;
168+ const updateCount = recordsToUpdate . length ;
169+
170+ if ( updateCount === 0 ) {
171+ console . warn ( `No records updated in table ${ tableName } .` ) ;
172+ }
173+
174+ return updateCount ;
175+ } catch ( error ) {
176+ console . error ( `Error updating data in table ${ tableName } :` , error ) ;
177+ throw error ;
178+ }
179+ }
180+
181+ /**
182+ * Creates a new record in a static table in IndexedDB.
183+ * Ensures that the table is within the predefined static tables list.
184+ *
185+ * @param tableName - Name of the table to create data in
186+ * @param data - The data object to insert into the table
187+ * @returns A promise that resolves to the id of the created record
188+ * @throws Error if IndexedDB is unavailable, the table is inaccessible, or creation fails.
189+ */
190+ public static async insertStaticDataTable (
191+ tableName : string ,
192+ data : any
193+ ) : Promise < any > {
194+ try {
195+ if ( ! rsbcDb ) {
196+ throw new Error ( "IndexedDB is not available." ) ;
197+ }
198+ if ( ! StaticTables . includes ( tableName ) ) {
199+ throw new Error ( `Table ${ tableName } is not accessible.` ) ;
200+ }
201+
202+ await rsbcDb . open ( ) ; // Ensure the database is open
203+
204+ const table = rsbcDb . table ( tableName ) ;
205+ if ( ! table ) {
206+ throw new Error ( `Table ${ tableName } not found in IndexedDB.` ) ;
207+ }
208+
209+ // Validate data
210+ if ( ! data || Object . keys ( data ) . length === 0 ) {
211+ throw new Error (
212+ "Invalid data: data object is required and must not be empty"
213+ ) ;
214+ }
215+
216+ // Add the record to the table
217+ const id = await table . add ( data ) ;
218+
219+ return id ;
220+ } catch ( error ) {
221+ console . error ( `Error creating data in table ${ tableName } :` , error ) ;
222+ throw error ;
223+ }
224+ }
225+
38226 /**
39227 * Fetches a specific offline form by its ID from the formDefinition table.
40228 *
0 commit comments