@instantdb/core
Advanced tools
Comparing version 0.12.26 to 0.12.27
@@ -190,5 +190,49 @@ import { test, expect } from "vitest"; | ||
), | ||
).toThrowError('user_pref.email is not a valid lookup attribute.'); | ||
).toThrowError("user_pref.email is not a valid lookup attribute."); | ||
}); | ||
test("it doesn't throw if you have a period in your attr", () => { | ||
const aid = uuid(); | ||
const iid = uuid(); | ||
const pid = uuid(); | ||
const attrs = { | ||
[aid]: { | ||
id: aid, | ||
cardinality: "one", | ||
"forward-identity": [uuid(), "users", "attr.with.dot"], | ||
"index?": true, | ||
"unique?": true, | ||
"value-type": "blob", | ||
}, | ||
[iid]: { | ||
id: iid, | ||
cardinality: "one", | ||
"forward-identity": [uuid(), "users", "id"], | ||
"index?": false, | ||
"unique?": false, | ||
"value-type": "blob", | ||
}, | ||
[pid]: { | ||
id: pid, | ||
cardinality: "one", | ||
"forward-identity": [uuid(), "users", "a"], | ||
"index?": false, | ||
"unique?": false, | ||
"value-type": "blob", | ||
}, | ||
}; | ||
expect( | ||
instaml.transform( | ||
attrs, | ||
instatx.tx.users[instatx.lookup("attr.with.dot", "value")].update({ | ||
a: 1, | ||
}), | ||
), | ||
).toEqual([ | ||
["add-triple", [aid, "value"], iid, [aid, "value"]], | ||
["add-triple", [aid, "value"], pid, 1], | ||
]); | ||
}); | ||
test("it doesn't create duplicate ref attrs", () => { | ||
@@ -195,0 +239,0 @@ const aid = uuid(); |
@@ -8,2 +8,5 @@ // https://www.npmjs.com/package/fake-indexeddb | ||
import Reactor from "../../src/Reactor"; | ||
import InMemoryStorage from "../../src/InMemoryStorage"; | ||
import * as instaml from "../../src/instaml"; | ||
import * as instatx from "../../src/instatx"; | ||
import zenecaAttrs from "./data/zeneca/attrs.json"; | ||
@@ -13,2 +16,7 @@ import zenecaTriples from "./data/zeneca/triples.json"; | ||
const zenecaIdToAttr = zenecaAttrs.reduce((res, x) => { | ||
res[x.id] = x; | ||
return res; | ||
}, {}); | ||
test("querySubs round-trips", async () => { | ||
@@ -83,1 +91,94 @@ const appId = uuid(); | ||
}); | ||
test("rewrite mutations", () => { | ||
const appId = uuid(); | ||
const reactor = new Reactor({ appId }); | ||
const bookId = "bookId"; | ||
const bookshelfId = "bookshelfId"; | ||
const ops = [ | ||
instatx.tx.books[bookId].update({ title: "title" }), | ||
instatx.tx.users[instatx.lookup("handle", "stopa")].update({ | ||
email: "s@example.com", | ||
}), | ||
instatx.tx.bookshelves[bookshelfId].link({ | ||
users: { handle: "stopa" }, | ||
}), | ||
instatx.tx.bookshelves[bookshelfId].unlink({ | ||
users: ["handle", "joe"], | ||
}), | ||
instatx.tx.bookshelves[bookshelfId].unlink({ | ||
users: instatx.lookup("handle", "joe"), | ||
}), | ||
]; | ||
// create transactions without any attributes | ||
const optimisticSteps = instaml.transform({}, ops); | ||
const mutations = new Map([["k", { "tx-steps": optimisticSteps }]]); | ||
const rewrittenWithoutAttrs = reactor | ||
._rewriteMutations({}, mutations) | ||
.get("k")["tx-steps"]; | ||
// Check that we didn't clobber anything in our rewrite | ||
expect(rewrittenWithoutAttrs).toEqual(optimisticSteps); | ||
// rewrite them with the new server attributes | ||
const rewrittenSteps = reactor | ||
._rewriteMutations(zenecaIdToAttr, mutations) | ||
.get("k")["tx-steps"]; | ||
const serverSteps = instaml.transform(zenecaIdToAttr, ops); | ||
expect(rewrittenSteps).toEqual(serverSteps); | ||
}); | ||
test("rewrite mutations works with multiple transactions", () => { | ||
const appId = uuid(); | ||
const reactor = new Reactor({ appId }); | ||
reactor._initStorage(InMemoryStorage); | ||
const bookId = "bookId"; | ||
const bookshelfId = "bookshelfId"; | ||
const ops = [ | ||
instatx.tx.books[bookId].update({ title: "title" }), | ||
instatx.tx.users[instatx.lookup("handle", "stopa")].update({ | ||
email: "s@example.com", | ||
}), | ||
instatx.tx.bookshelves[bookshelfId].link({ | ||
users: { handle: "stopa" }, | ||
}), | ||
instatx.tx.bookshelves[bookshelfId].unlink({ | ||
users: ["handle", "joe"], | ||
}), | ||
instatx.tx.bookshelves[bookshelfId].unlink({ | ||
users: instatx.lookup("handle", "joe"), | ||
}), | ||
]; | ||
const keys = ["a", "b", "c", "d"]; | ||
for (const k of keys) { | ||
const attrs = reactor.optimisticAttrs(); | ||
const steps = instaml.transform(attrs, ops); | ||
const mut = { | ||
op: "transact", | ||
"tx-steps": steps, | ||
}; | ||
reactor.pendingMutations.set((prev) => { | ||
prev.set(k, mut); | ||
return prev; | ||
}); | ||
} | ||
// rewrite them with the new server attributes | ||
const rewrittenMutations = reactor._rewriteMutations( | ||
zenecaIdToAttr, | ||
reactor.pendingMutations.currentValue, | ||
); | ||
const serverSteps = instaml.transform(zenecaIdToAttr, ops); | ||
for (const k of keys) { | ||
expect(rewrittenMutations.get(k)["tx-steps"]).toEqual(serverSteps); | ||
} | ||
}); |
@@ -0,1 +1,2 @@ | ||
export function rewriteStep(attrMapping: any, txStep: any): any[]; | ||
export function getAttrByFwdIdentName(attrs: any, inputEtype: any, inputIdentName: any): any; | ||
@@ -2,0 +3,0 @@ export function getAttrByReverseIdentName(attrs: any, inputEtype: any, inputIdentName: any): any; |
@@ -6,2 +6,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.rewriteStep = rewriteStep; | ||
exports.getAttrByFwdIdentName = getAttrByFwdIdentName; | ||
@@ -13,2 +14,31 @@ exports.getAttrByReverseIdentName = getAttrByReverseIdentName; | ||
const uuid_1 = __importDefault(require("./utils/uuid")); | ||
// Rewrites optimistic attrs with the attrs we get back from the server. | ||
function rewriteStep(attrMapping, txStep) { | ||
const { attrIdMap, refSwapAttrIds } = attrMapping; | ||
const rewritten = []; | ||
for (const part of txStep) { | ||
const newValue = attrIdMap[part]; | ||
if (newValue) { | ||
// Rewrites attr id | ||
rewritten.push(newValue); | ||
} | ||
else if (Array.isArray(part) && part.length == 2 && attrIdMap[part[0]]) { | ||
// Rewrites attr id in lookups | ||
const [aid, value] = part; | ||
rewritten.push([attrIdMap[aid], value]); | ||
} | ||
else { | ||
rewritten.push(part); | ||
} | ||
} | ||
const [action] = txStep; | ||
if ((action === "add-triple" || action === "retract-triple") && | ||
refSwapAttrIds.has(txStep[2])) { | ||
// Reverse links if the optimistic link attr is backwards | ||
const tmp = rewritten[1]; | ||
rewritten[1] = rewritten[3]; | ||
rewritten[3] = tmp; | ||
} | ||
return rewritten; | ||
} | ||
function getAttrByFwdIdentName(attrs, inputEtype, inputIdentName) { | ||
@@ -39,4 +69,7 @@ return Object.values(attrs).find((attr) => { | ||
} | ||
function isRefLookupIdent(identName) { | ||
return identName.indexOf(".") !== -1; | ||
function isRefLookupIdent(attrs, etype, identName) { | ||
return (identName.indexOf(".") !== -1 && | ||
// attr names can have `.` in them, so use the attr we find with a `.` | ||
// before assuming it's a ref lookup. | ||
!getAttrByFwdIdentName(attrs, etype, identName)); | ||
} | ||
@@ -51,3 +84,3 @@ function extractRefLookupFwdName(identName) { | ||
function lookupIdentToAttr(attrs, etype, identName) { | ||
if (!isRefLookupIdent(identName)) { | ||
if (!isRefLookupIdent(attrs, etype, identName)) { | ||
return getAttrByFwdIdentName(attrs, etype, identName); | ||
@@ -230,3 +263,3 @@ } | ||
const identName = lookupPair[0]; | ||
if (isRefLookupIdent(identName)) { | ||
if (isRefLookupIdent(attrs, etype, identName)) { | ||
const label = extractRefLookupFwdName(identName); | ||
@@ -233,0 +266,0 @@ const fwdAttr = getAttrByFwdIdentName(attrs, etype, label); |
@@ -106,3 +106,3 @@ import { DataAttrDef, InstantGraph, LinkAttrDef } from "./schema"; | ||
*/ | ||
export declare function lookup(attribute: string, value: string): Lookup; | ||
export declare function lookup(attribute: string, value: any): Lookup; | ||
export declare function isLookup(k: string): boolean; | ||
@@ -109,0 +109,0 @@ export declare function parseLookup(k: string): LookupRef; |
@@ -0,1 +1,2 @@ | ||
export function rewriteStep(attrMapping: any, txStep: any): any[]; | ||
export function getAttrByFwdIdentName(attrs: any, inputEtype: any, inputIdentName: any): any; | ||
@@ -2,0 +3,0 @@ export function getAttrByReverseIdentName(attrs: any, inputEtype: any, inputIdentName: any): any; |
import { getOps, isLookup, parseLookup } from "./instatx"; | ||
import { immutableDeepReplace } from "./utils/object"; | ||
import uuid from "./utils/uuid"; | ||
// Rewrites optimistic attrs with the attrs we get back from the server. | ||
export function rewriteStep(attrMapping, txStep) { | ||
const { attrIdMap, refSwapAttrIds } = attrMapping; | ||
const rewritten = []; | ||
for (const part of txStep) { | ||
const newValue = attrIdMap[part]; | ||
if (newValue) { | ||
// Rewrites attr id | ||
rewritten.push(newValue); | ||
} | ||
else if (Array.isArray(part) && part.length == 2 && attrIdMap[part[0]]) { | ||
// Rewrites attr id in lookups | ||
const [aid, value] = part; | ||
rewritten.push([attrIdMap[aid], value]); | ||
} | ||
else { | ||
rewritten.push(part); | ||
} | ||
} | ||
const [action] = txStep; | ||
if ((action === "add-triple" || action === "retract-triple") && | ||
refSwapAttrIds.has(txStep[2])) { | ||
// Reverse links if the optimistic link attr is backwards | ||
const tmp = rewritten[1]; | ||
rewritten[1] = rewritten[3]; | ||
rewritten[3] = tmp; | ||
} | ||
return rewritten; | ||
} | ||
export function getAttrByFwdIdentName(attrs, inputEtype, inputIdentName) { | ||
@@ -29,4 +58,7 @@ return Object.values(attrs).find((attr) => { | ||
} | ||
function isRefLookupIdent(identName) { | ||
return identName.indexOf(".") !== -1; | ||
function isRefLookupIdent(attrs, etype, identName) { | ||
return (identName.indexOf(".") !== -1 && | ||
// attr names can have `.` in them, so use the attr we find with a `.` | ||
// before assuming it's a ref lookup. | ||
!getAttrByFwdIdentName(attrs, etype, identName)); | ||
} | ||
@@ -41,3 +73,3 @@ function extractRefLookupFwdName(identName) { | ||
function lookupIdentToAttr(attrs, etype, identName) { | ||
if (!isRefLookupIdent(identName)) { | ||
if (!isRefLookupIdent(attrs, etype, identName)) { | ||
return getAttrByFwdIdentName(attrs, etype, identName); | ||
@@ -220,3 +252,3 @@ } | ||
const identName = lookupPair[0]; | ||
if (isRefLookupIdent(identName)) { | ||
if (isRefLookupIdent(attrs, etype, identName)) { | ||
const label = extractRefLookupFwdName(identName); | ||
@@ -223,0 +255,0 @@ const fwdAttr = getAttrByFwdIdentName(attrs, etype, label); |
@@ -106,3 +106,3 @@ import { DataAttrDef, InstantGraph, LinkAttrDef } from "./schema"; | ||
*/ | ||
export declare function lookup(attribute: string, value: string): Lookup; | ||
export declare function lookup(attribute: string, value: any): Lookup; | ||
export declare function isLookup(k: string): boolean; | ||
@@ -109,0 +109,0 @@ export declare function parseLookup(k: string): LookupRef; |
@@ -88,3 +88,8 @@ /** | ||
pushTx: (chunks: any) => Promise<any>; | ||
pushOps: (txSteps: any) => Promise<any>; | ||
/** | ||
* @param {*} txSteps | ||
* @param {*} [error] | ||
* @returns | ||
*/ | ||
pushOps: (txSteps: any, error?: any) => Promise<any>; | ||
shutdown(): void; | ||
@@ -91,0 +96,0 @@ /** |
@@ -150,6 +150,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
this.pushTx = (chunks) => { | ||
const txSteps = instaml.transform(this.optimisticAttrs(), chunks); | ||
return this.pushOps(txSteps); | ||
try { | ||
const txSteps = instaml.transform(this.optimisticAttrs(), chunks); | ||
return this.pushOps(txSteps); | ||
} | ||
catch (e) { | ||
return this.pushOps([], e); | ||
} | ||
}; | ||
this.pushOps = (txSteps) => { | ||
/** | ||
* @param {*} txSteps | ||
* @param {*} [error] | ||
* @returns | ||
*/ | ||
this.pushOps = (txSteps, error) => { | ||
const eventId = uuid(); | ||
@@ -159,2 +169,3 @@ const mutation = { | ||
"tx-steps": txSteps, | ||
error, | ||
}; | ||
@@ -518,6 +529,3 @@ this.pendingMutations.set((prev) => { | ||
return muts; | ||
const findExistingAttr = ([action, attr]) => { | ||
if (action !== "add-attr") { | ||
return; | ||
} | ||
const findExistingAttr = (attr) => { | ||
const [_, etype, label] = attr["forward-identity"]; | ||
@@ -527,28 +535,42 @@ const existing = instaml.getAttrByFwdIdentName(attrs, etype, label); | ||
}; | ||
const rewriteTxSteps = (mapping, txSteps) => { | ||
return txSteps.reduce(([mapping, retTxSteps], txStep) => { | ||
const findReverseAttr = (attr) => { | ||
const [_, etype, label] = attr["forward-identity"]; | ||
const revAttr = instaml.getAttrByReverseIdentName(attrs, etype, label); | ||
return revAttr; | ||
}; | ||
const mapping = { attrIdMap: {}, refSwapAttrIds: new Set() }; | ||
const rewriteTxSteps = (txSteps) => { | ||
const retTxSteps = []; | ||
for (const txStep of txSteps) { | ||
const [action] = txStep; | ||
// Handles add-attr | ||
// If existing, we drop it, and track it | ||
// to update add/retract triples | ||
const existing = findExistingAttr(txStep); | ||
if (existing) { | ||
if (action === "add-attr") { | ||
const [_action, attr] = txStep; | ||
mapping[attr.id] = existing.id; | ||
return [mapping, retTxSteps]; | ||
const existing = findExistingAttr(attr); | ||
if (existing) { | ||
mapping.attrIdMap[attr.id] = existing.id; | ||
continue; | ||
} | ||
if (attr["value-type"] === "ref") { | ||
const revAttr = findReverseAttr(attr); | ||
if (revAttr) { | ||
mapping.attrIdMap[attr.id] = revAttr.id; | ||
mapping.refSwapAttrIds.add(attr.id); | ||
continue; | ||
} | ||
} | ||
} | ||
// Handles add-triple|retract-triple | ||
// If in mapping, we update the attr-id | ||
const [action, eid, attrId, ...rest] = txStep; | ||
const newTxStep = mapping[attrId] | ||
? [action, eid, mapping[attrId], ...rest] | ||
: txStep; | ||
const newTxStep = instaml.rewriteStep(mapping, txStep); | ||
retTxSteps.push(newTxStep); | ||
return [mapping, retTxSteps]; | ||
}, [mapping, []]); | ||
} | ||
return retTxSteps; | ||
}; | ||
const [_, __, rewritten] = [...muts.entries()].reduce(([attrs, mapping, newMuts], [k, mut]) => { | ||
const [newMapping, newTxSteps] = rewriteTxSteps(mapping, mut["tx-steps"]); | ||
newMuts.set(k, Object.assign(Object.assign({}, mut), { "tx-steps": newTxSteps })); | ||
return [attrs, newMapping, newMuts]; | ||
}, [attrs, {}, new Map()]); | ||
const rewritten = new Map(); | ||
for (const [k, mut] of muts.entries()) { | ||
rewritten.set(k, Object.assign(Object.assign({}, mut), { "tx-steps": rewriteTxSteps(mut["tx-steps"]) })); | ||
} | ||
return rewritten; | ||
@@ -612,2 +634,13 @@ } | ||
_sendMutation(eventId, mutation) { | ||
if (mutation.error) { | ||
this._finishTransaction(false, "error", eventId, { | ||
error: mutation.error, | ||
message: mutation.error.message, | ||
}); | ||
this.pendingMutations.set((prev) => { | ||
prev.delete(eventId); | ||
return prev; | ||
}); | ||
return; | ||
} | ||
if (this.status !== STATUS.AUTHENTICATED) { | ||
@@ -614,0 +647,0 @@ this._finishTransaction(true, "enqueued", eventId); |
@@ -88,3 +88,8 @@ /** | ||
pushTx: (chunks: any) => Promise<any>; | ||
pushOps: (txSteps: any) => Promise<any>; | ||
/** | ||
* @param {*} txSteps | ||
* @param {*} [error] | ||
* @returns | ||
*/ | ||
pushOps: (txSteps: any, error?: any) => Promise<any>; | ||
shutdown(): void; | ||
@@ -91,0 +96,0 @@ /** |
@@ -178,6 +178,16 @@ "use strict"; | ||
this.pushTx = (chunks) => { | ||
const txSteps = instaml.transform(this.optimisticAttrs(), chunks); | ||
return this.pushOps(txSteps); | ||
try { | ||
const txSteps = instaml.transform(this.optimisticAttrs(), chunks); | ||
return this.pushOps(txSteps); | ||
} | ||
catch (e) { | ||
return this.pushOps([], e); | ||
} | ||
}; | ||
this.pushOps = (txSteps) => { | ||
/** | ||
* @param {*} txSteps | ||
* @param {*} [error] | ||
* @returns | ||
*/ | ||
this.pushOps = (txSteps, error) => { | ||
const eventId = (0, uuid_1.default)(); | ||
@@ -187,2 +197,3 @@ const mutation = { | ||
"tx-steps": txSteps, | ||
error, | ||
}; | ||
@@ -546,6 +557,3 @@ this.pendingMutations.set((prev) => { | ||
return muts; | ||
const findExistingAttr = ([action, attr]) => { | ||
if (action !== "add-attr") { | ||
return; | ||
} | ||
const findExistingAttr = (attr) => { | ||
const [_, etype, label] = attr["forward-identity"]; | ||
@@ -555,28 +563,42 @@ const existing = instaml.getAttrByFwdIdentName(attrs, etype, label); | ||
}; | ||
const rewriteTxSteps = (mapping, txSteps) => { | ||
return txSteps.reduce(([mapping, retTxSteps], txStep) => { | ||
const findReverseAttr = (attr) => { | ||
const [_, etype, label] = attr["forward-identity"]; | ||
const revAttr = instaml.getAttrByReverseIdentName(attrs, etype, label); | ||
return revAttr; | ||
}; | ||
const mapping = { attrIdMap: {}, refSwapAttrIds: new Set() }; | ||
const rewriteTxSteps = (txSteps) => { | ||
const retTxSteps = []; | ||
for (const txStep of txSteps) { | ||
const [action] = txStep; | ||
// Handles add-attr | ||
// If existing, we drop it, and track it | ||
// to update add/retract triples | ||
const existing = findExistingAttr(txStep); | ||
if (existing) { | ||
if (action === "add-attr") { | ||
const [_action, attr] = txStep; | ||
mapping[attr.id] = existing.id; | ||
return [mapping, retTxSteps]; | ||
const existing = findExistingAttr(attr); | ||
if (existing) { | ||
mapping.attrIdMap[attr.id] = existing.id; | ||
continue; | ||
} | ||
if (attr["value-type"] === "ref") { | ||
const revAttr = findReverseAttr(attr); | ||
if (revAttr) { | ||
mapping.attrIdMap[attr.id] = revAttr.id; | ||
mapping.refSwapAttrIds.add(attr.id); | ||
continue; | ||
} | ||
} | ||
} | ||
// Handles add-triple|retract-triple | ||
// If in mapping, we update the attr-id | ||
const [action, eid, attrId, ...rest] = txStep; | ||
const newTxStep = mapping[attrId] | ||
? [action, eid, mapping[attrId], ...rest] | ||
: txStep; | ||
const newTxStep = instaml.rewriteStep(mapping, txStep); | ||
retTxSteps.push(newTxStep); | ||
return [mapping, retTxSteps]; | ||
}, [mapping, []]); | ||
} | ||
return retTxSteps; | ||
}; | ||
const [_, __, rewritten] = [...muts.entries()].reduce(([attrs, mapping, newMuts], [k, mut]) => { | ||
const [newMapping, newTxSteps] = rewriteTxSteps(mapping, mut["tx-steps"]); | ||
newMuts.set(k, Object.assign(Object.assign({}, mut), { "tx-steps": newTxSteps })); | ||
return [attrs, newMapping, newMuts]; | ||
}, [attrs, {}, new Map()]); | ||
const rewritten = new Map(); | ||
for (const [k, mut] of muts.entries()) { | ||
rewritten.set(k, Object.assign(Object.assign({}, mut), { "tx-steps": rewriteTxSteps(mut["tx-steps"]) })); | ||
} | ||
return rewritten; | ||
@@ -640,2 +662,13 @@ } | ||
_sendMutation(eventId, mutation) { | ||
if (mutation.error) { | ||
this._finishTransaction(false, "error", eventId, { | ||
error: mutation.error, | ||
message: mutation.error.message, | ||
}); | ||
this.pendingMutations.set((prev) => { | ||
prev.delete(eventId); | ||
return prev; | ||
}); | ||
return; | ||
} | ||
if (this.status !== STATUS.AUTHENTICATED) { | ||
@@ -642,0 +675,0 @@ this._finishTransaction(true, "enqueued", eventId); |
{ | ||
"name": "@instantdb/core", | ||
"version": "v0.12.26", | ||
"version": "v0.12.27", | ||
"description": "Instant's core local abstraction", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -5,2 +5,33 @@ import { getOps, isLookup, parseLookup } from "./instatx"; | ||
// Rewrites optimistic attrs with the attrs we get back from the server. | ||
export function rewriteStep(attrMapping, txStep) { | ||
const { attrIdMap, refSwapAttrIds } = attrMapping; | ||
const rewritten = []; | ||
for (const part of txStep) { | ||
const newValue = attrIdMap[part]; | ||
if (newValue) { | ||
// Rewrites attr id | ||
rewritten.push(newValue); | ||
} else if (Array.isArray(part) && part.length == 2 && attrIdMap[part[0]]) { | ||
// Rewrites attr id in lookups | ||
const [aid, value] = part; | ||
rewritten.push([attrIdMap[aid], value]); | ||
} else { | ||
rewritten.push(part); | ||
} | ||
} | ||
const [action] = txStep; | ||
if ( | ||
(action === "add-triple" || action === "retract-triple") && | ||
refSwapAttrIds.has(txStep[2]) | ||
) { | ||
// Reverse links if the optimistic link attr is backwards | ||
const tmp = rewritten[1]; | ||
rewritten[1] = rewritten[3]; | ||
rewritten[3] = tmp; | ||
} | ||
return rewritten; | ||
} | ||
export function getAttrByFwdIdentName(attrs, inputEtype, inputIdentName) { | ||
@@ -35,4 +66,9 @@ return Object.values(attrs).find((attr) => { | ||
function isRefLookupIdent(identName) { | ||
return identName.indexOf(".") !== -1; | ||
function isRefLookupIdent(attrs, etype, identName) { | ||
return ( | ||
identName.indexOf(".") !== -1 && | ||
// attr names can have `.` in them, so use the attr we find with a `.` | ||
// before assuming it's a ref lookup. | ||
!getAttrByFwdIdentName(attrs, etype, identName) | ||
); | ||
} | ||
@@ -50,3 +86,3 @@ | ||
function lookupIdentToAttr(attrs, etype, identName) { | ||
if (!isRefLookupIdent(identName)) { | ||
if (!isRefLookupIdent(attrs, etype, identName)) { | ||
return getAttrByFwdIdentName(attrs, etype, identName); | ||
@@ -269,3 +305,3 @@ } | ||
const identName = lookupPair[0]; | ||
if (isRefLookupIdent(identName)) { | ||
if (isRefLookupIdent(attrs, etype, identName)) { | ||
const label = extractRefLookupFwdName(identName); | ||
@@ -272,0 +308,0 @@ const fwdAttr = getAttrByFwdIdentName(attrs, etype, label); |
@@ -164,3 +164,3 @@ import { DataAttrDef, InstantGraph, LinkAttrDef } from "./schema"; | ||
*/ | ||
export function lookup(attribute: string, value: string): Lookup { | ||
export function lookup(attribute: string, value: any): Lookup { | ||
return `lookup__${attribute}__${JSON.stringify(value)}`; | ||
@@ -167,0 +167,0 @@ } |
@@ -508,6 +508,3 @@ // @ts-check | ||
if (!attrs) return muts; | ||
const findExistingAttr = ([action, attr]) => { | ||
if (action !== "add-attr") { | ||
return; | ||
} | ||
const findExistingAttr = (attr) => { | ||
const [_, etype, label] = attr["forward-identity"]; | ||
@@ -517,37 +514,45 @@ const existing = instaml.getAttrByFwdIdentName(attrs, etype, label); | ||
}; | ||
const rewriteTxSteps = (mapping, txSteps) => { | ||
return txSteps.reduce( | ||
([mapping, retTxSteps], txStep) => { | ||
// Handles add-attr | ||
// If existing, we drop it, and track it | ||
// to update add/retract triples | ||
const existing = findExistingAttr(txStep); | ||
const findReverseAttr = (attr) => { | ||
const [_, etype, label] = attr["forward-identity"]; | ||
const revAttr = instaml.getAttrByReverseIdentName(attrs, etype, label); | ||
return revAttr; | ||
}; | ||
const mapping = { attrIdMap: {}, refSwapAttrIds: new Set() }; | ||
const rewriteTxSteps = (txSteps) => { | ||
const retTxSteps = []; | ||
for (const txStep of txSteps) { | ||
const [action] = txStep; | ||
// Handles add-attr | ||
// If existing, we drop it, and track it | ||
// to update add/retract triples | ||
if (action === "add-attr") { | ||
const [_action, attr] = txStep; | ||
const existing = findExistingAttr(attr); | ||
if (existing) { | ||
const [_action, attr] = txStep; | ||
mapping[attr.id] = existing.id; | ||
return [mapping, retTxSteps]; | ||
mapping.attrIdMap[attr.id] = existing.id; | ||
continue; | ||
} | ||
// Handles add-triple|retract-triple | ||
// If in mapping, we update the attr-id | ||
const [action, eid, attrId, ...rest] = txStep; | ||
const newTxStep = mapping[attrId] | ||
? [action, eid, mapping[attrId], ...rest] | ||
: txStep; | ||
retTxSteps.push(newTxStep); | ||
return [mapping, retTxSteps]; | ||
}, | ||
[mapping, []], | ||
); | ||
if (attr["value-type"] === "ref") { | ||
const revAttr = findReverseAttr(attr); | ||
if (revAttr) { | ||
mapping.attrIdMap[attr.id] = revAttr.id; | ||
mapping.refSwapAttrIds.add(attr.id); | ||
continue; | ||
} | ||
} | ||
} | ||
// Handles add-triple|retract-triple | ||
// If in mapping, we update the attr-id | ||
const newTxStep = instaml.rewriteStep(mapping, txStep); | ||
retTxSteps.push(newTxStep); | ||
} | ||
return retTxSteps; | ||
}; | ||
const [_, __, rewritten] = [...muts.entries()].reduce( | ||
([attrs, mapping, newMuts], [k, mut]) => { | ||
const [newMapping, newTxSteps] = rewriteTxSteps( | ||
mapping, | ||
mut["tx-steps"], | ||
); | ||
newMuts.set(k, { ...mut, "tx-steps": newTxSteps }); | ||
return [attrs, newMapping, newMuts]; | ||
}, | ||
[attrs, {}, new Map()], | ||
); | ||
const rewritten = new Map(); | ||
for (const [k, mut] of muts.entries()) { | ||
rewritten.set(k, { ...mut, "tx-steps": rewriteTxSteps(mut["tx-steps"]) }); | ||
} | ||
return rewritten; | ||
@@ -644,7 +649,16 @@ } | ||
pushTx = (chunks) => { | ||
const txSteps = instaml.transform(this.optimisticAttrs(), chunks); | ||
return this.pushOps(txSteps); | ||
try { | ||
const txSteps = instaml.transform(this.optimisticAttrs(), chunks); | ||
return this.pushOps(txSteps); | ||
} catch (e) { | ||
return this.pushOps([], e); | ||
} | ||
}; | ||
pushOps = (txSteps) => { | ||
/** | ||
* @param {*} txSteps | ||
* @param {*} [error] | ||
* @returns | ||
*/ | ||
pushOps = (txSteps, error) => { | ||
const eventId = uuid(); | ||
@@ -654,2 +668,3 @@ const mutation = { | ||
"tx-steps": txSteps, | ||
error, | ||
}; | ||
@@ -683,2 +698,13 @@ this.pendingMutations.set((prev) => { | ||
_sendMutation(eventId, mutation) { | ||
if (mutation.error) { | ||
this._finishTransaction(false, "error", eventId, { | ||
error: mutation.error, | ||
message: mutation.error.message, | ||
}); | ||
this.pendingMutations.set((prev) => { | ||
prev.delete(eventId); | ||
return prev; | ||
}); | ||
return; | ||
} | ||
if (this.status !== STATUS.AUTHENTICATED) { | ||
@@ -685,0 +711,0 @@ this._finishTransaction(true, "enqueued", eventId); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
1968157
319
40065