@electric-sql/pglite-sync
Version:
ElectricSQL Sync for PGlite
1 lines • 38.5 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/subscriptionState.ts","../src/apply.ts"],"sourcesContent":["import type { Row } from '@electric-sql/client'\nimport {\n ChangeMessage,\n isChangeMessage,\n isControlMessage,\n ShapeStreamOptions,\n} from '@electric-sql/client'\nimport { MultiShapeStream } from '@electric-sql/experimental'\nimport type { Extension, PGliteInterface } from '@electric-sql/pglite'\nimport {\n migrateSubscriptionMetadataTables,\n getSubscriptionState,\n updateSubscriptionState,\n deleteSubscriptionState,\n SubscriptionState,\n} from './subscriptionState'\nimport type {\n ElectricSyncOptions,\n SyncShapesToTablesOptions,\n SyncShapesToTablesResult,\n SyncShapeToTableOptions,\n SyncShapeToTableResult,\n InsertChangeMessage,\n Lsn,\n} from './types'\nimport {\n applyMessageToTable,\n applyMessagesToTableWithCopy,\n applyMessagesToTableWithJson,\n} from './apply'\n\nexport * from './types'\n\nasync function createPlugin(\n pg: PGliteInterface,\n options?: ElectricSyncOptions,\n) {\n const debug = options?.debug ?? false\n const metadataSchema = options?.metadataSchema ?? 'electric'\n const streams: Array<{\n stream: MultiShapeStream<Record<string, Row<unknown>>>\n aborter: AbortController\n }> = []\n\n // We keep an in-memory lock per table such that two\n // shapes are not synced into one table - this will be\n // resolved by using reference counting in shadow tables\n const shapePerTableLock = new Map<string, void>()\n\n let initMetadataTablesDone = false\n const initMetadataTables = async () => {\n if (initMetadataTablesDone) return\n initMetadataTablesDone = true\n await migrateSubscriptionMetadataTables({\n pg,\n metadataSchema,\n })\n }\n\n const syncShapesToTables = async ({\n key,\n shapes,\n useCopy = false, // DEPRECATED: use initialInsertMethod instead\n initialInsertMethod = 'insert',\n onInitialSync,\n }: SyncShapesToTablesOptions): Promise<SyncShapesToTablesResult> => {\n let unsubscribed = false\n await initMetadataTables()\n\n Object.values(shapes)\n .filter((shape) => !shape.onMustRefetch) // Shapes with onMustRefetch bypass the lock\n .forEach((shape) => {\n if (shapePerTableLock.has(shape.table)) {\n throw new Error('Already syncing shape for table ' + shape.table)\n }\n shapePerTableLock.set(shape.table)\n })\n\n let subState: SubscriptionState | null = null\n\n // if key is not null, ensure persistence of subscription state\n // is possible and check if it is already persisted\n if (key !== null) {\n subState = await getSubscriptionState({\n pg,\n metadataSchema,\n subscriptionKey: key,\n })\n if (debug && subState) {\n console.log('resuming from subscription state', subState)\n }\n }\n\n // If it's a new subscription there is no state to resume from\n const isNewSubscription = subState === null\n\n // We need to handle the old useCopy option\n // We check if it's set to true and initialInsertMethod is it's default value\n if (useCopy && initialInsertMethod === 'insert') {\n initialInsertMethod = 'csv'\n console.warn(\n 'The useCopy option is deprecated and will be removed in a future version. Use initialInsertMethod instead.',\n )\n }\n\n // If it's a new subscription we can do a `COPY FROM` to insert the initial data\n // TODO: in future when we can have multiple shapes on the same table we will need\n // to make sure we only do a `COPY FROM` on the first shape on the table as they\n // may overlap and so the insert logic will be wrong.\n let useInsert = !isNewSubscription || initialInsertMethod === 'insert'\n\n // Track if onInitialSync has been called\n let onInitialSyncCalled = false\n\n // Map of shape name to lsn to changes\n // We accumulate changes for each lsn and then apply them all at once\n const changes = new Map<string, Map<Lsn, ChangeMessage<Row<unknown>>[]>>(\n Object.keys(shapes).map((key) => [key, new Map()]),\n )\n\n // We track the highest completely buffered lsn for each shape\n const completeLsns = new Map<string, Lsn>(\n Object.keys(shapes).map((key) => [key, BigInt(-1)]),\n )\n\n // We track which shapes need a truncate\n // These are truncated at the start of the next commit\n const truncateNeeded = new Set<string>()\n\n // We also have to track the last lsn that we have committed\n // This is across all shapes\n const lastCommittedLsn: Lsn = subState?.last_lsn ?? BigInt(-1)\n\n // We need our own aborter to be able to abort the streams but still accept the\n // signals from the user for each shape, and so we monitor the user provided signal\n // for each shape and abort our own aborter when the user signal is aborted.\n const aborter = new AbortController()\n Object.values(shapes)\n .filter((shapeOptions) => !!shapeOptions.shape.signal)\n .forEach((shapeOptions) => {\n shapeOptions.shape.signal!.addEventListener(\n 'abort',\n () => aborter.abort(),\n {\n once: true,\n },\n )\n })\n\n const multiShapeStream = new MultiShapeStream<Record<string, Row<unknown>>>(\n {\n shapes: Object.fromEntries(\n Object.entries(shapes).map(([key, shapeOptions]) => {\n const shapeMetadata = subState?.shape_metadata[key]\n return [\n key,\n {\n ...shapeOptions.shape,\n ...(shapeMetadata\n ? {\n offset: shapeMetadata.offset,\n handle: shapeMetadata.handle,\n }\n : {}),\n signal: aborter.signal,\n } satisfies ShapeStreamOptions,\n ]\n }),\n ),\n },\n )\n\n const commitUpToLsn = async (targetLsn: Lsn) => {\n // We need to collect all the messages for each shape that we need to commit\n const messagesToCommit = new Map<string, ChangeMessage<Row<unknown>>[]>(\n Object.keys(shapes).map((shapeName) => [shapeName, []]),\n )\n for (const [shapeName, shapeChanges] of changes.entries()) {\n const messagesForShape = messagesToCommit.get(shapeName)!\n for (const lsn of shapeChanges.keys()) {\n if (lsn <= targetLsn) {\n for (const message of shapeChanges.get(lsn)!) {\n messagesForShape.push(message)\n }\n shapeChanges.delete(lsn)\n }\n }\n }\n\n await pg.transaction(async (tx) => {\n if (debug) {\n console.time('commit')\n }\n\n // Set the syncing flag to true during this transaction so that\n // user defined triggers on the table are able to chose how to run\n // during a sync\n await tx.exec(`SET LOCAL ${metadataSchema}.syncing = true;`)\n\n for (const [shapeName, initialMessages] of messagesToCommit.entries()) {\n const shape = shapes[shapeName]\n let messages = initialMessages\n\n // If we need to truncate the table, do so\n if (truncateNeeded.has(shapeName)) {\n if (debug) {\n console.log('truncating table', shape.table)\n }\n if (shape.onMustRefetch) {\n await shape.onMustRefetch(tx)\n } else {\n await tx.exec(`DELETE FROM ${shape.table};`)\n }\n truncateNeeded.delete(shapeName)\n }\n\n // Apply the changes to the table\n if (!useInsert) {\n // We can do a `COPY FROM`/json_to_recordset to insert the initial data\n // Split messageAggregator into initial inserts and remaining messages\n const initialInserts: InsertChangeMessage[] = []\n const remainingMessages: ChangeMessage<any>[] = []\n let foundNonInsert = false\n for (const message of messages) {\n if (!foundNonInsert && message.headers.operation === 'insert') {\n initialInserts.push(message as InsertChangeMessage)\n } else {\n foundNonInsert = true\n remainingMessages.push(message)\n }\n }\n if (initialInserts.length > 0 && initialInsertMethod === 'csv') {\n // As `COPY FROM` doesn't trigger a NOTIFY, we pop\n // the last insert message and and add it to the be beginning\n // of the remaining messages to be applied after the `COPY FROM`\n remainingMessages.unshift(initialInserts.pop()!)\n }\n messages = remainingMessages\n\n // Do the `COPY FROM`/json_to_recordset with initial inserts\n if (initialInserts.length > 0) {\n const method =\n initialInsertMethod === 'json'\n ? applyMessagesToTableWithJson\n : applyMessagesToTableWithCopy\n await method({\n pg: tx,\n table: shape.table,\n schema: shape.schema,\n messages: initialInserts as InsertChangeMessage[],\n mapColumns: shape.mapColumns,\n primaryKey: shape.primaryKey,\n debug,\n })\n // We don't want to do a `COPY FROM`/json_to_recordset again after that\n useInsert = true\n }\n }\n\n for (const changeMessage of messages) {\n await applyMessageToTable({\n pg: tx,\n table: shape.table,\n schema: shape.schema,\n message: changeMessage,\n mapColumns: shape.mapColumns,\n primaryKey: shape.primaryKey,\n debug,\n })\n }\n }\n\n if (key) {\n await updateSubscriptionState({\n pg: tx,\n metadataSchema,\n subscriptionKey: key,\n shapeMetadata: Object.fromEntries(\n Object.keys(shapes).map((shapeName) => [\n shapeName,\n {\n handle: multiShapeStream.shapes[shapeName].shapeHandle!,\n offset: multiShapeStream.shapes[shapeName].lastOffset,\n },\n ]),\n ),\n lastLsn: targetLsn,\n debug,\n })\n }\n if (unsubscribed) {\n await tx.rollback()\n }\n })\n if (debug) console.timeEnd('commit')\n if (\n onInitialSync &&\n !onInitialSyncCalled &&\n multiShapeStream.isUpToDate\n ) {\n onInitialSync()\n onInitialSyncCalled = true\n }\n }\n\n multiShapeStream.subscribe(async (messages) => {\n if (unsubscribed) {\n return\n }\n if (debug) {\n console.log('received messages', messages.length)\n }\n messages.forEach((message) => {\n const lastCommittedLsnForShape =\n completeLsns.get(message.shape) ?? BigInt(-1) // we default to -1 if there are no previous changes\n if (isChangeMessage(message)) {\n const shapeChanges = changes.get(message.shape)!\n const lsn =\n typeof message.headers.lsn === 'string'\n ? BigInt(message.headers.lsn)\n : BigInt(0) // we default to 0 if there no lsn on the message\n if (lsn <= lastCommittedLsnForShape) {\n // We are replaying changes / have already seen this lsn\n // skip and move on to the next message\n return\n }\n const isLastOfLsn =\n (message.headers.last as boolean | undefined) ?? false\n if (!shapeChanges.has(lsn)) {\n shapeChanges.set(lsn, [])\n }\n shapeChanges.get(lsn)!.push(message)\n if (isLastOfLsn) {\n completeLsns.set(message.shape, lsn)\n }\n } else if (isControlMessage(message)) {\n switch (message.headers.control) {\n case 'up-to-date': {\n // Update the complete lsn for this shape\n if (debug) {\n console.log('received up-to-date', message)\n }\n if (typeof message.headers.global_last_seen_lsn !== `string`) {\n throw new Error(`global_last_seen_lsn is not a string`)\n }\n const globalLastSeenLsn = BigInt(\n message.headers.global_last_seen_lsn,\n )\n if (globalLastSeenLsn <= lastCommittedLsnForShape) {\n // We are replaying changes / have already seen this lsn\n // skip and move on to the next message\n return\n }\n completeLsns.set(message.shape, globalLastSeenLsn)\n break\n }\n case 'must-refetch': {\n // Reset the changes for this shape\n if (debug) {\n console.log('received must-refetch', message)\n }\n const shapeChanges = changes.get(message.shape)!\n shapeChanges.clear()\n completeLsns.set(message.shape, BigInt(-1))\n // Track that we need to truncate the table for this shape\n truncateNeeded.add(message.shape)\n break\n }\n }\n }\n })\n const lowestCommittedLsn = Array.from(completeLsns.values()).reduce(\n (m, e) => (e < m ? e : m), // Min of all complete lsn\n )\n\n // Normal commit needed\n const isCommitNeeded = lowestCommittedLsn > lastCommittedLsn\n // We've had a must-refetch and are catching up on one of the shape\n const isMustRefetchAndCatchingUp =\n lowestCommittedLsn >= lastCommittedLsn && truncateNeeded.size > 0\n\n if (isCommitNeeded || isMustRefetchAndCatchingUp) {\n // We have new changes to commit\n commitUpToLsn(lowestCommittedLsn)\n // Await a timeout to start a new task and allow other connections to do work\n await new Promise((resolve) => setTimeout(resolve))\n }\n })\n\n streams.push({\n stream: multiShapeStream,\n aborter,\n })\n const unsubscribe = () => {\n if (debug) {\n console.log('unsubscribing')\n }\n unsubscribed = true\n multiShapeStream.unsubscribeAll()\n aborter.abort()\n for (const shape of Object.values(shapes)) {\n shapePerTableLock.delete(shape.table)\n }\n }\n return {\n unsubscribe,\n get isUpToDate() {\n return multiShapeStream.isUpToDate\n },\n streams: Object.fromEntries(\n Object.keys(shapes).map((shapeName) => [\n shapeName,\n multiShapeStream.shapes[shapeName],\n ]),\n ),\n }\n }\n\n const syncShapeToTable = async (\n options: SyncShapeToTableOptions,\n ): Promise<SyncShapeToTableResult> => {\n const multiShapeSub = await syncShapesToTables({\n shapes: {\n shape: {\n shape: options.shape,\n table: options.table,\n schema: options.schema,\n mapColumns: options.mapColumns,\n primaryKey: options.primaryKey,\n onMustRefetch: options.onMustRefetch,\n },\n },\n key: options.shapeKey,\n useCopy: options.useCopy, // DEPRECATED: use initialInsertMethod instead\n initialInsertMethod: options.initialInsertMethod,\n onInitialSync: options.onInitialSync,\n })\n return {\n unsubscribe: multiShapeSub.unsubscribe,\n get isUpToDate() {\n return multiShapeSub.isUpToDate\n },\n stream: multiShapeSub.streams.shape,\n }\n }\n const deleteSubscription = async (key: string) => {\n await deleteSubscriptionState({\n pg,\n metadataSchema,\n subscriptionKey: key,\n })\n }\n\n const namespaceObj = {\n initMetadataTables,\n syncShapesToTables,\n syncShapeToTable,\n deleteSubscription,\n }\n\n const close = async () => {\n for (const { stream, aborter } of streams) {\n stream.unsubscribeAll()\n aborter.abort()\n }\n }\n\n return {\n namespaceObj,\n close,\n }\n}\n\nexport type SyncNamespaceObj = Awaited<\n ReturnType<typeof createPlugin>\n>['namespaceObj']\n\nexport type PGliteWithSync = PGliteInterface & {\n sync: SyncNamespaceObj\n}\n\nexport function electricSync(options?: ElectricSyncOptions) {\n return {\n name: 'ElectricSQL Sync',\n setup: async (pg: PGliteInterface) => {\n const { namespaceObj, close } = await createPlugin(pg, options)\n return {\n namespaceObj,\n close,\n }\n },\n } satisfies Extension\n}\n","import type { PGliteInterface, Transaction } from '@electric-sql/pglite'\nimport type { Offset } from '@electric-sql/client'\nimport { SubscriptionKey, Lsn } from './types'\n\nconst subscriptionTableName = `subscriptions_metadata`\n\nexport interface SubscriptionState {\n key: SubscriptionKey\n shape_metadata: Record<string, ShapeSubscriptionState>\n last_lsn: Lsn\n}\n\nexport interface ShapeSubscriptionState {\n handle: string\n offset: Offset\n}\n\nexport interface GetSubscriptionStateOptions {\n readonly pg: PGliteInterface | Transaction\n readonly metadataSchema: string\n readonly subscriptionKey: SubscriptionKey\n}\n\n/**\n * Get the subscription state for a given key.\n * @param options - The options for the subscription state.\n * @returns The subscription state or null if it does not exist.\n */\nexport async function getSubscriptionState({\n pg,\n metadataSchema,\n subscriptionKey,\n}: GetSubscriptionStateOptions): Promise<SubscriptionState | null> {\n const result = await pg.query<SubscriptionState>(\n `\n SELECT key, shape_metadata, last_lsn\n FROM ${subscriptionMetadataTableName(metadataSchema)}\n WHERE key = $1\n `,\n [subscriptionKey],\n )\n\n if (result.rows.length === 0) {\n return null\n } else if (result.rows.length > 1) {\n throw new Error(`Multiple subscriptions found for key: ${subscriptionKey}`)\n }\n\n const res = result.rows[0]\n\n if (typeof res.last_lsn === 'string') {\n return {\n ...res,\n last_lsn: BigInt(res.last_lsn),\n }\n } else {\n throw new Error(`Invalid last_lsn type: ${typeof res.last_lsn}`)\n }\n}\n\nexport interface UpdateSubscriptionStateOptions {\n pg: PGliteInterface | Transaction\n metadataSchema: string\n subscriptionKey: SubscriptionKey\n shapeMetadata: Record<string, ShapeSubscriptionState>\n lastLsn: Lsn\n debug?: boolean\n}\n\n/**\n * Update the subscription state for a given key.\n * @param options - The options for the subscription state.\n */\nexport async function updateSubscriptionState({\n pg,\n metadataSchema,\n subscriptionKey,\n shapeMetadata,\n lastLsn,\n debug,\n}: UpdateSubscriptionStateOptions) {\n if (debug) {\n console.log(\n 'updating subscription state',\n subscriptionKey,\n shapeMetadata,\n lastLsn,\n )\n }\n await pg.query(\n `\n INSERT INTO ${subscriptionMetadataTableName(metadataSchema)}\n (key, shape_metadata, last_lsn)\n VALUES\n ($1, $2, $3)\n ON CONFLICT(key)\n DO UPDATE SET\n shape_metadata = EXCLUDED.shape_metadata,\n last_lsn = EXCLUDED.last_lsn;\n `,\n [subscriptionKey, shapeMetadata, lastLsn.toString()],\n )\n}\n\nexport interface DeleteSubscriptionStateOptions {\n pg: PGliteInterface | Transaction\n metadataSchema: string\n subscriptionKey: SubscriptionKey\n}\n\n/**\n * Delete the subscription state for a given key.\n * @param options - The options for the subscription state.\n */\nexport async function deleteSubscriptionState({\n pg,\n metadataSchema,\n subscriptionKey,\n}: DeleteSubscriptionStateOptions) {\n await pg.query(\n `DELETE FROM ${subscriptionMetadataTableName(metadataSchema)} WHERE key = $1`,\n [subscriptionKey],\n )\n}\n\nexport interface MigrateSubscriptionMetadataTablesOptions {\n pg: PGliteInterface | Transaction\n metadataSchema: string\n}\n\n/**\n * Migrate the subscription metadata tables.\n * @param options - The options for the subscription metadata tables.\n */\nexport async function migrateSubscriptionMetadataTables({\n pg,\n metadataSchema,\n}: MigrateSubscriptionMetadataTablesOptions) {\n await pg.exec(\n `\n SET ${metadataSchema}.syncing = false;\n CREATE SCHEMA IF NOT EXISTS \"${metadataSchema}\";\n CREATE TABLE IF NOT EXISTS ${subscriptionMetadataTableName(metadataSchema)} (\n key TEXT PRIMARY KEY,\n shape_metadata JSONB NOT NULL,\n last_lsn TEXT NOT NULL\n );\n `,\n )\n}\n\nfunction subscriptionMetadataTableName(metadataSchema: string) {\n return `\"${metadataSchema}\".\"${subscriptionTableName}\"`\n}\n","import { ChangeMessage } from '@electric-sql/client'\nimport type { PGliteInterface, Transaction } from '@electric-sql/pglite'\nimport type { MapColumns, InsertChangeMessage } from './types'\n\nexport interface ApplyMessageToTableOptions {\n pg: PGliteInterface | Transaction\n table: string\n schema?: string\n message: ChangeMessage<any>\n mapColumns?: MapColumns\n primaryKey: string[]\n debug: boolean\n}\n\nexport async function applyMessageToTable({\n pg,\n table,\n schema = 'public',\n message,\n mapColumns,\n primaryKey,\n debug,\n}: ApplyMessageToTableOptions) {\n const data = mapColumns ? doMapColumns(mapColumns, message) : message.value\n\n switch (message.headers.operation) {\n case 'insert': {\n if (debug) console.log('inserting', data)\n const columns = Object.keys(data)\n return await pg.query(\n `\n INSERT INTO \"${schema}\".\"${table}\"\n (${columns.map((s) => '\"' + s + '\"').join(', ')})\n VALUES\n (${columns.map((_v, i) => '$' + (i + 1)).join(', ')})\n `,\n columns.map((column) => data[column]),\n )\n }\n\n case 'update': {\n if (debug) console.log('updating', data)\n const columns = Object.keys(data).filter(\n // we don't update the primary key, they are used to identify the row\n (column) => !primaryKey.includes(column),\n )\n if (columns.length === 0) return // nothing to update\n return await pg.query(\n `\n UPDATE \"${schema}\".\"${table}\"\n SET ${columns\n .map((column, i) => '\"' + column + '\" = $' + (i + 1))\n .join(', ')}\n WHERE ${primaryKey\n .map(\n (column, i) =>\n '\"' + column + '\" = $' + (columns.length + i + 1),\n )\n .join(' AND ')}\n `,\n [\n ...columns.map((column) => data[column]),\n ...primaryKey.map((column) => data[column]),\n ],\n )\n }\n\n case 'delete': {\n if (debug) console.log('deleting', data)\n return await pg.query(\n `\n DELETE FROM \"${schema}\".\"${table}\"\n WHERE ${primaryKey\n .map((column, i) => '\"' + column + '\" = $' + (i + 1))\n .join(' AND ')}\n `,\n [...primaryKey.map((column) => data[column])],\n )\n }\n }\n}\n\nexport interface BulkApplyMessagesToTableOptions {\n pg: PGliteInterface | Transaction\n table: string\n schema?: string\n messages: InsertChangeMessage[]\n mapColumns?: MapColumns\n primaryKey: string[]\n debug: boolean\n}\n\nexport async function applyMessagesToTableWithJson({\n pg,\n table,\n schema = 'public',\n messages,\n mapColumns,\n debug,\n}: BulkApplyMessagesToTableOptions) {\n if (debug) console.log('applying messages with json_to_recordset')\n\n // Map the messages to the data to be inserted\n const data: Record<string, object>[] = messages.map((message) =>\n mapColumns ? doMapColumns(mapColumns, message) : message.value,\n )\n const columns = (\n await pg.query<{\n column_name: string\n udt_name: string\n data_type: string\n }>(\n `\n SELECT column_name, udt_name, data_type\n FROM information_schema.columns\n WHERE table_name = $1 AND table_schema = $2\n `,\n [table, schema],\n )\n ).rows.filter((x) =>\n Object.prototype.hasOwnProperty.call(data[0], x.column_name),\n )\n\n const MAX = 10_000\n for (let i = 0; i < data.length; i += MAX) {\n const maxdata = data.slice(i, i + MAX)\n await pg.query(\n `\n INSERT INTO \"${schema}\".\"${table}\"\n SELECT x.* from json_to_recordset($1) as x(${columns\n .map(\n (x) =>\n `${x.column_name} ${x.udt_name.replace(/^_/, '')}` +\n (x.data_type === 'ARRAY' ? `[]` : ''),\n )\n .join(', ')})\n `,\n [maxdata],\n )\n }\n\n if (debug)\n console.log(`Inserted ${messages.length} rows using json_to_recordset`)\n}\n\nexport async function applyMessagesToTableWithCopy({\n pg,\n table,\n schema = 'public',\n messages,\n mapColumns,\n debug,\n}: BulkApplyMessagesToTableOptions) {\n if (debug) console.log('applying messages with COPY')\n\n // Map the messages to the data to be inserted\n const data: Record<string, any>[] = messages.map((message) =>\n mapColumns ? doMapColumns(mapColumns, message) : message.value,\n )\n\n // Get column names from the first message\n const columns = Object.keys(data[0])\n\n // Create CSV data\n const csvData = data\n .map((message) => {\n return columns\n .map((column) => {\n const value = message[column]\n // Escape double quotes and wrap in quotes if necessary\n if (\n typeof value === 'string' &&\n (value.includes(',') || value.includes('\"') || value.includes('\\n'))\n ) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`\n }\n return value === null ? '\\\\N' : value\n })\n .join(',')\n })\n .join('\\n')\n const csvBlob = new Blob([csvData], { type: 'text/csv' })\n\n // Perform COPY FROM\n await pg.query(\n `\n COPY \"${schema}\".\"${table}\" (${columns.map((c) => `\"${c}\"`).join(', ')})\n FROM '/dev/blob'\n WITH (FORMAT csv, NULL '\\\\N')\n `,\n [],\n {\n blob: csvBlob,\n },\n )\n\n if (debug) console.log(`Inserted ${messages.length} rows using COPY`)\n}\n\nfunction doMapColumns(\n mapColumns: MapColumns,\n message: ChangeMessage<any>,\n): Record<string, any> {\n if (typeof mapColumns === 'function') {\n return mapColumns(message)\n }\n const mappedColumns: Record<string, any> = {}\n for (const [key, value] of Object.entries(mapColumns)) {\n mappedColumns[key] = message.value[value]\n }\n return mappedColumns\n}\n"],"mappings":"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","names":["src_exports","__export","electricSync","__toCommonJS","import_client","import_experimental","subscriptionTableName","getSubscriptionState","pg","metadataSchema","subscriptionKey","result","subscriptionMetadataTableName","res","updateSubscriptionState","shapeMetadata","lastLsn","debug","deleteSubscriptionState","migrateSubscriptionMetadataTables","applyMessageToTable","pg","table","schema","message","mapColumns","primaryKey","debug","data","doMapColumns","columns","s","_v","i","column","applyMessagesToTableWithJson","messages","x","MAX","maxdata","applyMessagesToTableWithCopy","csvData","value","csvBlob","c","mappedColumns","key","createPlugin","pg","options","debug","metadataSchema","streams","shapePerTableLock","initMetadataTablesDone","initMetadataTables","migrateSubscriptionMetadataTables","syncShapesToTables","key","shapes","useCopy","initialInsertMethod","onInitialSync","unsubscribed","shape","subState","getSubscriptionState","isNewSubscription","useInsert","onInitialSyncCalled","changes","completeLsns","truncateNeeded","lastCommittedLsn","aborter","shapeOptions","multiShapeStream","shapeMetadata","commitUpToLsn","targetLsn","messagesToCommit","shapeName","shapeChanges","messagesForShape","lsn","message","tx","initialMessages","messages","initialInserts","remainingMessages","foundNonInsert","applyMessagesToTableWithJson","applyMessagesToTableWithCopy","changeMessage","applyMessageToTable","updateSubscriptionState","lastCommittedLsnForShape","isLastOfLsn","globalLastSeenLsn","lowestCommittedLsn","m","e","isCommitNeeded","isMustRefetchAndCatchingUp","resolve","multiShapeSub","deleteSubscriptionState","stream","electricSync","namespaceObj","close"]}