UNPKG

zeno-db

Version:

A lightweight, offline-first client-side database with automatic sync capabilities

172 lines (171 loc) 6.57 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PostgresSync = void 0; const pg_1 = require("pg"); class PostgresSync { constructor(config) { this.pool = null; this.lastTimestamp = 0; this.receiveCallback = null; this.pollTimer = null; this.isConnected = false; this.pool = new pg_1.Pool({ host: config.host, port: config.port, database: config.database, user: config.user, password: config.password, ssl: config.ssl, connectionTimeoutMillis: 10000, idleTimeoutMillis: 30000, max: 10 }); this.tableName = config.tableName || 'zenodb_changes'; this.pollInterval = config.pollInterval || 1000; this.clientId = config.clientId; } connect() { return __awaiter(this, void 0, void 0, function* () { if (!this.pool) { throw new Error('PostgreSQL pool not initialized'); } try { yield this.pool.query('SELECT NOW()'); yield this.pool.query(` CREATE TABLE IF NOT EXISTS ${this.tableName} ( id SERIAL PRIMARY KEY, key TEXT NOT NULL, value JSONB, timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, client_id TEXT NOT NULL, operation TEXT NOT NULL ) `); this.isConnected = true; this.startPolling(); if (this.onConnectedCallback) { this.onConnectedCallback(); } } catch (error) { console.error('Error connecting to PostgreSQL:', error); this.isConnected = false; throw error; } }); } onDisconnected(callback) { this.onDisconnectedCallback = callback; } startPolling() { return __awaiter(this, void 0, void 0, function* () { if (!this.pool) { throw new Error('PostgreSQL pool not initialized'); } if (this.pollTimer) { clearInterval(this.pollTimer); } const poll = () => __awaiter(this, void 0, void 0, function* () { if (!this.isConnected || !this.pool) return; console.log('Polling PostgreSQL for changes, last timestamp:', this.lastTimestamp); try { const result = yield this.pool.query(` SELECT * FROM ${this.tableName} WHERE timestamp > to_timestamp($1) AND client_id != $2 ORDER BY timestamp ASC `, [this.lastTimestamp / 1000, this.clientId]); for (const row of result.rows) { this.lastTimestamp = new Date(row.timestamp).getTime(); if (this.onReceiveCallback) { this.onReceiveCallback({ key: row.key, value: row.value, operation: row.operation, timestamp: this.lastTimestamp, clientId: row.client_id }); } } } catch (error) { console.error('Error polling PostgreSQL:', error); this.isConnected = false; if (this.onDisconnectedCallback) { this.onDisconnectedCallback(); } } }); this.pollTimer = setInterval(poll, this.pollInterval); yield poll(); // Initial poll }); } send(change) { return __awaiter(this, void 0, void 0, function* () { if (!this.pool) { throw new Error('PostgreSQL pool not initialized'); } console.log('Sending change to PostgreSQL:', change); try { yield this.pool.query(` INSERT INTO ${this.tableName} (key, value, timestamp, client_id, operation) VALUES ($1, $2, CURRENT_TIMESTAMP, $3, $4) `, [change.key, change.value, this.clientId, change.operation]); console.log('Change sent successfully'); return true; } catch (error) { console.error('Error sending change to PostgreSQL:', error); return false; } }); } onReceive(callback) { this.onReceiveCallback = callback; } onConnected(callback) { this.onConnectedCallback = callback; } close() { return __awaiter(this, void 0, void 0, function* () { if (this.pollTimer) { clearInterval(this.pollTimer); this.pollTimer = null; } this.isConnected = false; if (this.onDisconnectedCallback) { this.onDisconnectedCallback(); } if (this.pool) { yield this.pool.end(); } }); } disconnect() { return __awaiter(this, void 0, void 0, function* () { if (this.pool) { yield this.pool.end(); this.pool = null; } }); } sendChange(change) { return __awaiter(this, void 0, void 0, function* () { if (!this.pool) { throw new Error('PostgreSQL client not connected'); } yield this.pool.query('INSERT INTO changes (key, value, timestamp, client_id) VALUES ($1, $2, $3, $4)', [change.key, change.value, change.timestamp, change.clientId]); }); } } exports.PostgresSync = PostgresSync;