UNPKG

@dataql/react-native

Version:

DataQL React Native SDK with offline-first capabilities and clean API

253 lines (252 loc) 9.27 kB
import { BaseDataQLClient, } from "@dataql/core"; import { DatabaseClient } from "./db/client"; import { OfflineCacheManager } from "./cache/OfflineCacheManager"; import { SyncManager } from "./sync/SyncManager"; import { setGlobalInstances } from "./hooks/useDataQL"; export class DataQLClient extends BaseDataQLClient { constructor(config) { // Transform React Native config to base config const baseConfig = { appToken: config.appToken, workerUrl: config.syncConfig?.serverUrl || "https://your-dataql-server.com/api", schemas: config.schemas, debug: config.debug, env: config.env, devPrefix: config.devPrefix, }; const syncConfig = { serverUrl: config.syncConfig?.serverUrl, autoSync: config.syncConfig?.autoSync, syncInterval: config.syncConfig?.syncInterval, customConnection: config.syncConfig?.customConnection, workerBinding: config.syncConfig?.workerBinding, }; super(baseConfig, syncConfig); this.reactNativeConfig = config; // Initialize React Native specific components this.dbClient = new DatabaseClient(config); this.cacheManager = new OfflineCacheManager(this.dbClient); // Handle potentially undefined syncConfig const reactNativeSyncConfig = { serverUrl: config.syncConfig?.serverUrl, workerUrl: config.syncConfig?.workerUrl, syncInterval: config.syncConfig?.syncInterval || 30000, retryCount: config.syncConfig?.retryCount || 3, batchSize: config.syncConfig?.batchSize || 10, autoSync: config.syncConfig?.autoSync ?? true, customConnection: config.syncConfig?.customConnection, workerBinding: config.syncConfig?.workerBinding, }; this.syncManager = new SyncManager(this.cacheManager, reactNativeSyncConfig); // Set global instances for hooks setGlobalInstances(this.cacheManager, this.syncManager, this.dbClient); } // Implement abstract methods from BaseDataQLClient async initializeStorage() { try { const dbInitialized = await this.dbClient.initializeDatabase(); if (!dbInitialized) { return false; } // Start auto sync if enabled if (this.syncConfig?.autoSync) { this.syncManager.startAutoSync(); } return true; } catch (error) { console.error("[DataQL React Native] Failed to initialize storage:", error); return false; } } async storeDataLocally(tableName, data) { try { await this.cacheManager.createOffline(tableName, data); // Simple conversion for now - this can be refined later return { success: true, data: data, // Return the original data since it was successfully stored insertedId: data.id, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Failed to store data locally", }; } } async retrieveDataLocally(tableName, filter) { try { const result = await this.cacheManager.queryOffline(tableName, filter); // Handle both QueryResult format and direct array format return Array.isArray(result) ? result : result?.data || []; } catch (error) { console.error(`[DataQL React Native] Failed to retrieve data from ${tableName}:`, error); return []; } } async updateDataLocally(tableName, id, data) { try { await this.cacheManager.updateOffline(tableName, id, data); // Simple conversion for now return { success: true, data: data, // Return the updated data modifiedCount: 1, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Failed to update data locally", }; } } async deleteDataLocally(tableName, id) { try { await this.cacheManager.deleteOffline(tableName, id); return { success: true, deletedCount: 1, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Failed to delete data locally", }; } } async syncWithServer() { try { return await this.syncManager.syncNow(); } catch (error) { console.error("[DataQL React Native] Sync failed:", error); return false; } } async getStoredSyncStatus() { try { const status = await this.cacheManager.getSyncStatus(); // Convert React Native SyncStatus to Core SyncStatus return { lastSyncTime: status.lastSyncTime || undefined, pendingOperations: status.pendingOperations, failedOperations: status.failedOperations || 0, isOnline: status.isOnline, }; } catch (error) { console.error("[DataQL React Native] Failed to get sync status:", error); return { pendingOperations: 0, failedOperations: 0, isOnline: false, }; } } // React Native specific methods (keeping backward compatibility) getDatabase() { return this.dbClient.getDatabase(); } // Deprecated methods - keeping for backward compatibility but delegating to base class /** @deprecated Use create() instead */ async createOffline(tableName, data) { return this.create(tableName, data); } /** @deprecated Use update() instead */ async updateOffline(tableName, id, data) { return this.update(tableName, id, data); } /** @deprecated Use delete() instead */ async deleteOffline(tableName, id) { return this.delete(tableName, id); } /** @deprecated Use query() instead */ async queryOffline(tableName, filter) { return this.query(tableName, filter); } // React Native specific sync methods startAutoSync() { this.syncManager.startAutoSync(); } stopAutoSync() { this.syncManager.stopAutoSync(); } // Advanced: Access to React Native specific managers getSyncManager() { return this.syncManager; } getCacheManager() { return this.cacheManager; } // Check online status isOnline() { return this.syncManager.getOnlineStatus(); } // Configuration updates updateSyncConfig(newConfig) { // Update base config if (this.syncConfig) { Object.assign(this.syncConfig, newConfig); } // Update React Native config this.reactNativeConfig.syncConfig = { ...this.reactNativeConfig.syncConfig, ...newConfig, }; // Update sync manager this.syncManager.updateConfig(newConfig); } // Override custom connection methods to also update React Native config setCustomConnection(customConnection) { super.setCustomConnection(customConnection); this.reactNativeConfig.syncConfig = this.reactNativeConfig.syncConfig || {}; this.reactNativeConfig.syncConfig.customConnection = customConnection; this.syncManager.updateConfig({ customConnection }); } setWorkerBinding(workerBinding) { super.setWorkerBinding(workerBinding); this.reactNativeConfig.syncConfig = this.reactNativeConfig.syncConfig || {}; this.reactNativeConfig.syncConfig.workerBinding = workerBinding; this.syncManager.updateConfig({ workerBinding }); } clearCustomConnection() { super.clearCustomConnection(); if (this.reactNativeConfig.syncConfig) { this.reactNativeConfig.syncConfig.customConnection = undefined; this.reactNativeConfig.syncConfig.workerBinding = undefined; } this.syncManager.updateConfig({ customConnection: undefined, workerBinding: undefined, }); } // Override destroy to clean up React Native specific resources async destroy() { try { this.syncManager.destroy(); await this.dbClient.close(); await super.destroy(); if (this.config.debug) { console.log("[DataQL React Native] Client destroyed"); } } catch (error) { console.error("[DataQL React Native] Error destroying client:", error); } } // React Native specific getters getReactNativeConfig() { return { ...this.reactNativeConfig }; } }