@tanstack/electric-db-collection 0.2.43 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/electric.cjs +62 -4
- package/dist/cjs/electric.cjs.map +1 -1
- package/dist/cjs/tag-index.cjs +31 -4
- package/dist/cjs/tag-index.cjs.map +1 -1
- package/dist/cjs/tag-index.d.cts +39 -10
- package/dist/esm/electric.js +68 -10
- package/dist/esm/electric.js.map +1 -1
- package/dist/esm/tag-index.d.ts +39 -10
- package/dist/esm/tag-index.js +31 -4
- package/dist/esm/tag-index.js.map +1 -1
- package/package.json +3 -3
- package/src/electric.ts +107 -11
- package/src/tag-index.ts +76 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag-index.cjs","sources":["../../src/tag-index.ts"],"sourcesContent":["// Import Row and Message types for the isEventMessage function\nimport type { Message, Row } from '@electric-sql/client'\n\nexport type RowId = string | number\nexport type MoveTag = string\nexport type ParsedMoveTag = Array<string>\nexport type Position = number\nexport type Value = string\nexport type
|
|
1
|
+
{"version":3,"file":"tag-index.cjs","sources":["../../src/tag-index.ts"],"sourcesContent":["// Import Row and Message types for the isEventMessage function\nimport type { Message, Row } from '@electric-sql/client'\n\nexport type RowId = string | number\nexport type MoveTag = string\nexport type ParsedMoveTag = Array<string | NonParticipating>\nexport type Position = number\nexport type Value = string\nexport type MovePattern = {\n pos: Position\n value: Value\n}\n\n/**\n * Sentinel value for tag positions where the disjunct does not participate\n * in that condition. These positions are not indexed and won't match any\n * move pattern.\n */\nexport const NON_PARTICIPATING = null\nexport type NonParticipating = typeof NON_PARTICIPATING\n\nexport type ActiveConditions = Array<boolean>\nexport type DisjunctPositions = Array<Array<number>>\n\n/**\n * Event message type for move-out and move-in events\n */\nexport interface EventMessage {\n headers: {\n event: `move-out` | `move-in`\n patterns: Array<MovePattern>\n }\n}\n\n/**\n * Tag index structure: array indexed by position, maps value to set of row IDs.\n * For example:\n * ```example\n * const tag1 = [a, b, c]\n * const tag2 = [a, b, d]\n * const tag3 = [a, d, e]\n *\n * // Index is:\n * [\n * new Map([a -> <rows with a on index 0>])\n * new Map([b -> <rows with b on index 1>, d -> <rows with d on index 1>])\n * new Map([c -> <rows with c on index 2>, d -> <rows with d on index 2>, e -> <rows with e on index 2>])\n * ]\n * ```\n */\nexport type TagIndex = Array<Map<Value, Set<RowId>>>\n\n/**\n * Parse a tag string into a ParsedMoveTag.\n * Splits on `/` delimiter and maps empty strings to {@link NON_PARTICIPATING}.\n */\nexport function parseTag(tag: MoveTag): ParsedMoveTag {\n return tag.split(`/`).map((s) => (s === `` ? NON_PARTICIPATING : s))\n}\n\n/**\n * Abstraction to get the value at a specific position in a tag\n */\nexport function getValue(\n tag: ParsedMoveTag,\n position: Position,\n): string | NonParticipating {\n if (position >= tag.length) {\n throw new Error(`Position out of bounds`)\n }\n return tag[position]!\n}\n\n/**\n * Abstraction to extract position and value from a pattern.\n */\nfunction getPositionalValue(pattern: MovePattern): {\n pos: number\n value: string\n} {\n return pattern\n}\n\n/**\n * Abstraction to get the length of a tag\n */\nexport function getTagLength(tag: ParsedMoveTag): number {\n return tag.length\n}\n\n/**\n * Check if a tag matches a pattern.\n * A tag matches if the value at the pattern's position equals the pattern's value.\n * {@link NON_PARTICIPATING} positions naturally don't match any string value.\n */\nexport function tagMatchesPattern(\n tag: ParsedMoveTag,\n pattern: MovePattern,\n): boolean {\n const { pos, value } = getPositionalValue(pattern)\n const tagValue = getValue(tag, pos)\n return tagValue === value\n}\n\n/**\n * Add a tag to the index for efficient pattern matching\n */\nexport function addTagToIndex(\n tag: ParsedMoveTag,\n rowId: RowId,\n index: TagIndex,\n tagLength: number,\n): void {\n for (let i = 0; i < tagLength; i++) {\n const value = getValue(tag, i)\n\n if (value !== NON_PARTICIPATING) {\n const positionIndex = index[i]!\n if (!positionIndex.has(value)) {\n positionIndex.set(value, new Set())\n }\n\n const tags = positionIndex.get(value)!\n tags.add(rowId)\n }\n }\n}\n\n/**\n * Remove a tag from the index\n */\nexport function removeTagFromIndex(\n tag: ParsedMoveTag,\n rowId: RowId,\n index: TagIndex,\n tagLength: number,\n): void {\n for (let i = 0; i < tagLength; i++) {\n const value = getValue(tag, i)\n\n if (value !== NON_PARTICIPATING) {\n const positionIndex = index[i]\n if (positionIndex) {\n const rowSet = positionIndex.get(value)\n if (rowSet) {\n rowSet.delete(rowId)\n\n // Clean up empty sets\n if (rowSet.size === 0) {\n positionIndex.delete(value)\n }\n }\n }\n }\n }\n}\n\n/**\n * Find all rows that match a given pattern\n */\nexport function findRowsMatchingPattern(\n pattern: MovePattern,\n index: TagIndex,\n): Set<RowId> {\n const { pos, value } = getPositionalValue(pattern)\n const positionIndex = index[pos]\n const rowSet = positionIndex?.get(value)\n return rowSet ?? new Set()\n}\n\n/**\n * Derive disjunct positions from parsed tags.\n * For each tag (= disjunct), collect the indices of participating positions.\n * E.g., [\"hash_a\", NON_PARTICIPATING, \"hash_b\"] → [0, 2]\n */\nexport function deriveDisjunctPositions(\n tags: Array<ParsedMoveTag>,\n): DisjunctPositions {\n return tags.map((tag) => {\n const positions: Array<number> = []\n for (let i = 0; i < tag.length; i++) {\n if (tag[i] !== NON_PARTICIPATING) {\n positions.push(i)\n }\n }\n return positions\n })\n}\n\n/**\n * Evaluate whether a row is visible given active conditions and disjunct positions.\n * Returns true if ANY disjunct has ALL its positions as true in activeConditions.\n */\nexport function rowVisible(\n activeConditions: ActiveConditions,\n disjunctPositions: DisjunctPositions,\n): boolean {\n return disjunctPositions.some((positions) =>\n positions.every((pos) => activeConditions[pos]),\n )\n}\n\n/**\n * Check if a message is an event message with move-out event\n */\nexport function isMoveOutMessage<T extends Row<unknown>>(\n message: Message<T>,\n): message is Message<T> & EventMessage {\n return message.headers.event === `move-out`\n}\n\n/**\n * Check if a message is an event message with move-in event\n */\nexport function isMoveInMessage<T extends Row<unknown>>(\n message: Message<T>,\n): message is Message<T> & EventMessage {\n return message.headers.event === `move-in`\n}\n"],"names":[],"mappings":";;AAkBO,MAAM,oBAAoB;AAsC1B,SAAS,SAAS,KAA6B;AACpD,SAAO,IAAI,MAAM,GAAG,EAAE,IAAI,CAAC,MAAO,MAAM,KAAK,oBAAoB,CAAE;AACrE;AAKO,SAAS,SACd,KACA,UAC2B;AAC3B,MAAI,YAAY,IAAI,QAAQ;AAC1B,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AACA,SAAO,IAAI,QAAQ;AACrB;AAKA,SAAS,mBAAmB,SAG1B;AACA,SAAO;AACT;AAKO,SAAS,aAAa,KAA4B;AACvD,SAAO,IAAI;AACb;AAOO,SAAS,kBACd,KACA,SACS;AACT,QAAM,EAAE,KAAK,UAAU,mBAAmB,OAAO;AACjD,QAAM,WAAW,SAAS,KAAK,GAAG;AAClC,SAAO,aAAa;AACtB;AAKO,SAAS,cACd,KACA,OACA,OACA,WACM;AACN,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,UAAM,QAAQ,SAAS,KAAK,CAAC;AAE7B,QAAI,UAAU,mBAAmB;AAC/B,YAAM,gBAAgB,MAAM,CAAC;AAC7B,UAAI,CAAC,cAAc,IAAI,KAAK,GAAG;AAC7B,sBAAc,IAAI,OAAO,oBAAI,IAAA,CAAK;AAAA,MACpC;AAEA,YAAM,OAAO,cAAc,IAAI,KAAK;AACpC,WAAK,IAAI,KAAK;AAAA,IAChB;AAAA,EACF;AACF;AAKO,SAAS,mBACd,KACA,OACA,OACA,WACM;AACN,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,UAAM,QAAQ,SAAS,KAAK,CAAC;AAE7B,QAAI,UAAU,mBAAmB;AAC/B,YAAM,gBAAgB,MAAM,CAAC;AAC7B,UAAI,eAAe;AACjB,cAAM,SAAS,cAAc,IAAI,KAAK;AACtC,YAAI,QAAQ;AACV,iBAAO,OAAO,KAAK;AAGnB,cAAI,OAAO,SAAS,GAAG;AACrB,0BAAc,OAAO,KAAK;AAAA,UAC5B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,wBACd,SACA,OACY;AACZ,QAAM,EAAE,KAAK,UAAU,mBAAmB,OAAO;AACjD,QAAM,gBAAgB,MAAM,GAAG;AAC/B,QAAM,SAAS,eAAe,IAAI,KAAK;AACvC,SAAO,8BAAc,IAAA;AACvB;AAOO,SAAS,wBACd,MACmB;AACnB,SAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,UAAM,YAA2B,CAAA;AACjC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,IAAI,CAAC,MAAM,mBAAmB;AAChC,kBAAU,KAAK,CAAC;AAAA,MAClB;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAMO,SAAS,WACd,kBACA,mBACS;AACT,SAAO,kBAAkB;AAAA,IAAK,CAAC,cAC7B,UAAU,MAAM,CAAC,QAAQ,iBAAiB,GAAG,CAAC;AAAA,EAAA;AAElD;AAKO,SAAS,iBACd,SACsC;AACtC,SAAO,QAAQ,QAAQ,UAAU;AACnC;AAKO,SAAS,gBACd,SACsC;AACtC,SAAO,QAAQ,QAAQ,UAAU;AACnC;;;;;;;;;;;;;"}
|
package/dist/cjs/tag-index.d.cts
CHANGED
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
import { Message, Row } from '@electric-sql/client';
|
|
2
2
|
export type RowId = string | number;
|
|
3
3
|
export type MoveTag = string;
|
|
4
|
-
export type ParsedMoveTag = Array<string>;
|
|
4
|
+
export type ParsedMoveTag = Array<string | NonParticipating>;
|
|
5
5
|
export type Position = number;
|
|
6
6
|
export type Value = string;
|
|
7
|
-
export type
|
|
7
|
+
export type MovePattern = {
|
|
8
8
|
pos: Position;
|
|
9
9
|
value: Value;
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Sentinel value for tag positions where the disjunct does not participate
|
|
13
|
+
* in that condition. These positions are not indexed and won't match any
|
|
14
|
+
* move pattern.
|
|
15
|
+
*/
|
|
16
|
+
export declare const NON_PARTICIPATING: null;
|
|
17
|
+
export type NonParticipating = typeof NON_PARTICIPATING;
|
|
18
|
+
export type ActiveConditions = Array<boolean>;
|
|
19
|
+
export type DisjunctPositions = Array<Array<number>>;
|
|
20
|
+
/**
|
|
21
|
+
* Event message type for move-out and move-in events
|
|
13
22
|
*/
|
|
14
23
|
export interface EventMessage {
|
|
15
24
|
headers: {
|
|
16
|
-
event: `move-out`;
|
|
17
|
-
patterns: Array<
|
|
25
|
+
event: `move-out` | `move-in`;
|
|
26
|
+
patterns: Array<MovePattern>;
|
|
18
27
|
};
|
|
19
28
|
}
|
|
20
29
|
/**
|
|
@@ -34,20 +43,25 @@ export interface EventMessage {
|
|
|
34
43
|
* ```
|
|
35
44
|
*/
|
|
36
45
|
export type TagIndex = Array<Map<Value, Set<RowId>>>;
|
|
46
|
+
/**
|
|
47
|
+
* Parse a tag string into a ParsedMoveTag.
|
|
48
|
+
* Splits on `/` delimiter and maps empty strings to {@link NON_PARTICIPATING}.
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseTag(tag: MoveTag): ParsedMoveTag;
|
|
37
51
|
/**
|
|
38
52
|
* Abstraction to get the value at a specific position in a tag
|
|
39
53
|
*/
|
|
40
|
-
export declare function getValue(tag: ParsedMoveTag, position: Position):
|
|
54
|
+
export declare function getValue(tag: ParsedMoveTag, position: Position): string | NonParticipating;
|
|
41
55
|
/**
|
|
42
56
|
* Abstraction to get the length of a tag
|
|
43
57
|
*/
|
|
44
58
|
export declare function getTagLength(tag: ParsedMoveTag): number;
|
|
45
59
|
/**
|
|
46
60
|
* Check if a tag matches a pattern.
|
|
47
|
-
* A tag matches if the value at the pattern's position equals the pattern's value
|
|
48
|
-
*
|
|
61
|
+
* A tag matches if the value at the pattern's position equals the pattern's value.
|
|
62
|
+
* {@link NON_PARTICIPATING} positions naturally don't match any string value.
|
|
49
63
|
*/
|
|
50
|
-
export declare function tagMatchesPattern(tag: ParsedMoveTag, pattern:
|
|
64
|
+
export declare function tagMatchesPattern(tag: ParsedMoveTag, pattern: MovePattern): boolean;
|
|
51
65
|
/**
|
|
52
66
|
* Add a tag to the index for efficient pattern matching
|
|
53
67
|
*/
|
|
@@ -59,8 +73,23 @@ export declare function removeTagFromIndex(tag: ParsedMoveTag, rowId: RowId, ind
|
|
|
59
73
|
/**
|
|
60
74
|
* Find all rows that match a given pattern
|
|
61
75
|
*/
|
|
62
|
-
export declare function findRowsMatchingPattern(pattern:
|
|
76
|
+
export declare function findRowsMatchingPattern(pattern: MovePattern, index: TagIndex): Set<RowId>;
|
|
77
|
+
/**
|
|
78
|
+
* Derive disjunct positions from parsed tags.
|
|
79
|
+
* For each tag (= disjunct), collect the indices of participating positions.
|
|
80
|
+
* E.g., ["hash_a", NON_PARTICIPATING, "hash_b"] → [0, 2]
|
|
81
|
+
*/
|
|
82
|
+
export declare function deriveDisjunctPositions(tags: Array<ParsedMoveTag>): DisjunctPositions;
|
|
83
|
+
/**
|
|
84
|
+
* Evaluate whether a row is visible given active conditions and disjunct positions.
|
|
85
|
+
* Returns true if ANY disjunct has ALL its positions as true in activeConditions.
|
|
86
|
+
*/
|
|
87
|
+
export declare function rowVisible(activeConditions: ActiveConditions, disjunctPositions: DisjunctPositions): boolean;
|
|
63
88
|
/**
|
|
64
89
|
* Check if a message is an event message with move-out event
|
|
65
90
|
*/
|
|
66
91
|
export declare function isMoveOutMessage<T extends Row<unknown>>(message: Message<T>): message is Message<T> & EventMessage;
|
|
92
|
+
/**
|
|
93
|
+
* Check if a message is an event message with move-in event
|
|
94
|
+
*/
|
|
95
|
+
export declare function isMoveInMessage<T extends Row<unknown>>(message: Message<T>): message is Message<T> & EventMessage;
|
package/dist/esm/electric.js
CHANGED
|
@@ -5,7 +5,7 @@ import DebugModule from "debug";
|
|
|
5
5
|
import { DeduplicatedLoadSubset, and } from "@tanstack/db";
|
|
6
6
|
import { StreamAbortedError, ExpectedNumberInAwaitTxIdError, TimeoutWaitingForTxIdError, TimeoutWaitingForMatchError } from "./errors.js";
|
|
7
7
|
import { compileSQL } from "./sql-compiler.js";
|
|
8
|
-
import { isMoveOutMessage, getTagLength, addTagToIndex, removeTagFromIndex, findRowsMatchingPattern, tagMatchesPattern } from "./tag-index.js";
|
|
8
|
+
import { isMoveOutMessage, isMoveInMessage, deriveDisjunctPositions, getTagLength, addTagToIndex, parseTag, removeTagFromIndex, findRowsMatchingPattern, rowVisible, tagMatchesPattern } from "./tag-index.js";
|
|
9
9
|
const debug = DebugModule.debug(`ts/db:electric`);
|
|
10
10
|
const ELECTRIC_TEST_HOOKS = /* @__PURE__ */ Symbol(`electricTestHooks`);
|
|
11
11
|
function isUpToDateMessage(message) {
|
|
@@ -399,18 +399,20 @@ function createElectricSync(shapeOptions, options) {
|
|
|
399
399
|
const MAX_BATCH_MESSAGES = 1e3;
|
|
400
400
|
const relationSchema = new Store(void 0);
|
|
401
401
|
const tagCache = /* @__PURE__ */ new Map();
|
|
402
|
-
const parseTag = (tag) => {
|
|
402
|
+
const parseTag$1 = (tag) => {
|
|
403
403
|
const cachedTag = tagCache.get(tag);
|
|
404
404
|
if (cachedTag) {
|
|
405
405
|
return cachedTag;
|
|
406
406
|
}
|
|
407
|
-
const parsedTag = tag
|
|
407
|
+
const parsedTag = parseTag(tag);
|
|
408
408
|
tagCache.set(tag, parsedTag);
|
|
409
409
|
return parsedTag;
|
|
410
410
|
};
|
|
411
411
|
const rowTagSets = /* @__PURE__ */ new Map();
|
|
412
412
|
const tagIndex = [];
|
|
413
413
|
let tagLength = void 0;
|
|
414
|
+
const rowActiveConditions = /* @__PURE__ */ new Map();
|
|
415
|
+
let disjunctPositions = void 0;
|
|
414
416
|
const initializeTagIndex = (length) => {
|
|
415
417
|
if (tagIndex.length < length) {
|
|
416
418
|
for (let i = tagIndex.length; i < length; i++) {
|
|
@@ -420,7 +422,7 @@ function createElectricSync(shapeOptions, options) {
|
|
|
420
422
|
};
|
|
421
423
|
const addTagsToRow = (tags, rowId, rowTagSet) => {
|
|
422
424
|
for (const tag of tags) {
|
|
423
|
-
const parsedTag = parseTag(tag);
|
|
425
|
+
const parsedTag = parseTag$1(tag);
|
|
424
426
|
if (tagLength === void 0) {
|
|
425
427
|
tagLength = getTagLength(parsedTag);
|
|
426
428
|
initializeTagIndex(tagLength);
|
|
@@ -441,29 +443,38 @@ function createElectricSync(shapeOptions, options) {
|
|
|
441
443
|
return;
|
|
442
444
|
}
|
|
443
445
|
for (const tag of removedTags) {
|
|
444
|
-
const parsedTag = parseTag(tag);
|
|
446
|
+
const parsedTag = parseTag$1(tag);
|
|
445
447
|
rowTagSet.delete(tag);
|
|
446
448
|
removeTagFromIndex(parsedTag, rowId, tagIndex, tagLength);
|
|
447
449
|
tagCache.delete(tag);
|
|
448
450
|
}
|
|
449
451
|
};
|
|
450
|
-
const processTagsForChangeMessage = (tags, removedTags, rowId) => {
|
|
452
|
+
const processTagsForChangeMessage = (tags, removedTags, rowId, activeConditions) => {
|
|
451
453
|
if (!rowTagSets.has(rowId)) {
|
|
452
454
|
rowTagSets.set(rowId, /* @__PURE__ */ new Set());
|
|
453
455
|
}
|
|
454
456
|
const rowTagSet = rowTagSets.get(rowId);
|
|
455
457
|
if (tags) {
|
|
456
458
|
addTagsToRow(tags, rowId, rowTagSet);
|
|
459
|
+
if (disjunctPositions === void 0) {
|
|
460
|
+
const parsedTags = tags.map(parseTag$1);
|
|
461
|
+
disjunctPositions = deriveDisjunctPositions(parsedTags);
|
|
462
|
+
}
|
|
457
463
|
}
|
|
458
464
|
if (removedTags) {
|
|
459
465
|
removeTagsFromRow(removedTags, rowId, rowTagSet);
|
|
460
466
|
}
|
|
467
|
+
if (activeConditions && activeConditions.length > 0) {
|
|
468
|
+
rowActiveConditions.set(rowId, [...activeConditions]);
|
|
469
|
+
}
|
|
461
470
|
return rowTagSet;
|
|
462
471
|
};
|
|
463
472
|
const clearTagTrackingState = () => {
|
|
464
473
|
rowTagSets.clear();
|
|
465
474
|
tagIndex.length = 0;
|
|
466
475
|
tagLength = void 0;
|
|
476
|
+
rowActiveConditions.clear();
|
|
477
|
+
disjunctPositions = void 0;
|
|
467
478
|
};
|
|
468
479
|
const clearTagsForRow = (rowId) => {
|
|
469
480
|
if (tagLength === void 0) {
|
|
@@ -474,7 +485,7 @@ function createElectricSync(shapeOptions, options) {
|
|
|
474
485
|
return;
|
|
475
486
|
}
|
|
476
487
|
for (const tag of rowTagSet) {
|
|
477
|
-
const parsedTag = parseTag(tag);
|
|
488
|
+
const parsedTag = parseTag$1(tag);
|
|
478
489
|
const currentTagLength = getTagLength(parsedTag);
|
|
479
490
|
if (currentTagLength === tagLength) {
|
|
480
491
|
removeTagFromIndex(parsedTag, rowId, tagIndex, tagLength);
|
|
@@ -482,14 +493,30 @@ function createElectricSync(shapeOptions, options) {
|
|
|
482
493
|
tagCache.delete(tag);
|
|
483
494
|
}
|
|
484
495
|
rowTagSets.delete(rowId);
|
|
496
|
+
rowActiveConditions.delete(rowId);
|
|
485
497
|
};
|
|
486
498
|
const removeMatchingTagsFromRow = (rowId, pattern) => {
|
|
487
499
|
const rowTagSet = rowTagSets.get(rowId);
|
|
488
500
|
if (!rowTagSet) {
|
|
489
501
|
return false;
|
|
490
502
|
}
|
|
503
|
+
const activeConditions = rowActiveConditions.get(rowId);
|
|
504
|
+
if (activeConditions && disjunctPositions) {
|
|
505
|
+
activeConditions[pattern.pos] = false;
|
|
506
|
+
if (!rowVisible(activeConditions, disjunctPositions)) {
|
|
507
|
+
for (const tag of rowTagSet) {
|
|
508
|
+
const parsedTag = parseTag$1(tag);
|
|
509
|
+
removeTagFromIndex(parsedTag, rowId, tagIndex, tagLength);
|
|
510
|
+
tagCache.delete(tag);
|
|
511
|
+
}
|
|
512
|
+
rowTagSets.delete(rowId);
|
|
513
|
+
rowActiveConditions.delete(rowId);
|
|
514
|
+
return true;
|
|
515
|
+
}
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
491
518
|
for (const tag of rowTagSet) {
|
|
492
|
-
const parsedTag = parseTag(tag);
|
|
519
|
+
const parsedTag = parseTag$1(tag);
|
|
493
520
|
if (tagMatchesPattern(parsedTag, pattern)) {
|
|
494
521
|
rowTagSet.delete(tag);
|
|
495
522
|
removeTagFromIndex(parsedTag, rowId, tagIndex, tagLength);
|
|
@@ -526,6 +553,23 @@ function createElectricSync(shapeOptions, options) {
|
|
|
526
553
|
}
|
|
527
554
|
return txStarted;
|
|
528
555
|
};
|
|
556
|
+
const processMoveInEvent = (patterns) => {
|
|
557
|
+
if (tagLength === void 0) {
|
|
558
|
+
debug(
|
|
559
|
+
`${collectionId ? `[${collectionId}] ` : ``}Received move-in message but no tag length set yet, ignoring`
|
|
560
|
+
);
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
for (const pattern of patterns) {
|
|
564
|
+
const affectedRowIds = findRowsMatchingPattern(pattern, tagIndex);
|
|
565
|
+
for (const rowId of affectedRowIds) {
|
|
566
|
+
const activeConditions = rowActiveConditions.get(rowId);
|
|
567
|
+
if (activeConditions) {
|
|
568
|
+
activeConditions[pattern.pos] = true;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
};
|
|
529
573
|
const getSyncMetadata = () => {
|
|
530
574
|
const schema = relationSchema.state || `public`;
|
|
531
575
|
return {
|
|
@@ -678,6 +722,7 @@ You can provide an 'onError' handler on the shapeOptions to handle this error, a
|
|
|
678
722
|
const tags = changeMessage.headers.tags;
|
|
679
723
|
const removedTags = changeMessage.headers.removed_tags;
|
|
680
724
|
const hasTags = tags || removedTags;
|
|
725
|
+
const activeConditions = changeMessage.headers.active_conditions;
|
|
681
726
|
const rowId = collection.getKeyFromItem(changeMessage.value);
|
|
682
727
|
const operation = changeMessage.headers.operation;
|
|
683
728
|
const isDelete = operation === `delete`;
|
|
@@ -690,7 +735,12 @@ You can provide an 'onError' handler on the shapeOptions to handle this error, a
|
|
|
690
735
|
if (isDelete) {
|
|
691
736
|
clearTagsForRow(rowId);
|
|
692
737
|
} else if (hasTags) {
|
|
693
|
-
processTagsForChangeMessage(
|
|
738
|
+
processTagsForChangeMessage(
|
|
739
|
+
tags,
|
|
740
|
+
removedTags,
|
|
741
|
+
rowId,
|
|
742
|
+
activeConditions
|
|
743
|
+
);
|
|
694
744
|
}
|
|
695
745
|
write({
|
|
696
746
|
type: isDuplicateInsert ? `update` : operation,
|
|
@@ -719,7 +769,7 @@ You can provide an 'onError' handler on the shapeOptions to handle this error, a
|
|
|
719
769
|
let commitPoint = null;
|
|
720
770
|
batchCommitted.setState(() => false);
|
|
721
771
|
for (const message of messages) {
|
|
722
|
-
if (isChangeMessage(message) || isMoveOutMessage(message)) {
|
|
772
|
+
if (isChangeMessage(message) || isMoveOutMessage(message) || isMoveInMessage(message)) {
|
|
723
773
|
currentBatchMessages.setState((currentBuffer) => {
|
|
724
774
|
const newBuffer = [...currentBuffer, message];
|
|
725
775
|
if (newBuffer.length > MAX_BATCH_MESSAGES) {
|
|
@@ -782,6 +832,12 @@ You can provide an 'onError' handler on the shapeOptions to handle this error, a
|
|
|
782
832
|
transactionStarted
|
|
783
833
|
);
|
|
784
834
|
}
|
|
835
|
+
} else if (isMoveInMessage(message)) {
|
|
836
|
+
if (isBufferingInitialSync() && !transactionStarted) {
|
|
837
|
+
bufferedMessages.push(message);
|
|
838
|
+
} else {
|
|
839
|
+
processMoveInEvent(message.headers.patterns);
|
|
840
|
+
}
|
|
785
841
|
} else if (isMustRefetchMessage(message)) {
|
|
786
842
|
debug(
|
|
787
843
|
`${collectionId ? `[${collectionId}] ` : ``}Received must-refetch message, starting transaction with truncate`
|
|
@@ -826,6 +882,8 @@ You can provide an 'onError' handler on the shapeOptions to handle this error, a
|
|
|
826
882
|
write,
|
|
827
883
|
transactionStarted
|
|
828
884
|
);
|
|
885
|
+
} else if (isMoveInMessage(bufferedMsg)) {
|
|
886
|
+
processMoveInEvent(bufferedMsg.headers.patterns);
|
|
829
887
|
}
|
|
830
888
|
}
|
|
831
889
|
stageResumeMetadata();
|