Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@instantdb/core

Package Overview
Dependencies
Maintainers
0
Versions
206
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@instantdb/core - npm Package Compare versions

Comparing version 0.10.27 to 0.10.28

__tests__/src/uuid.test.js

4

dist/index.d.ts
import Reactor from "./Reactor";
import { tx, TransactionChunk, EmptyChunk, getOps } from "./instatx";
import { tx, lookup, TransactionChunk, EmptyChunk, getOps } from "./instatx";
import weakHash from "./utils/weakHash";

@@ -281,3 +281,3 @@ import id from "./utils/uuid";

declare function coerceQuery(o: any): any;
export { init, id, tx, getOps, coerceQuery, weakHash, IndexedDBStorage, WindowNetworkListener, InstantCore as InstantClient, Auth, RoomSchemaShape, Query, QueryResponse, InstantObject, Exactly, TransactionChunk, QueryState, AuthState, User, AuthToken, EmptyChunk, SubscriptionState, LifecycleSubscriptionState, PresenceOpts, PresenceSlice, PresenceResponse, };
export { init, id, tx, lookup, getOps, coerceQuery, weakHash, IndexedDBStorage, WindowNetworkListener, InstantCore as InstantClient, Auth, RoomSchemaShape, Query, QueryResponse, InstantObject, Exactly, TransactionChunk, QueryState, AuthState, User, AuthToken, EmptyChunk, SubscriptionState, LifecycleSubscriptionState, PresenceOpts, PresenceSlice, PresenceResponse, };
/**

@@ -284,0 +284,0 @@ * @deprecated since 0.7.0, use client returned from `init` instead

@@ -6,6 +6,7 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.getLocalId = exports.getDB = exports.auth = exports.transact = exports.Auth = exports.InstantClient = exports.WindowNetworkListener = exports.IndexedDBStorage = exports.weakHash = exports.coerceQuery = exports.getOps = exports.tx = exports.id = exports.init = void 0;
exports.getLocalId = exports.getDB = exports.auth = exports.transact = exports.Auth = exports.InstantClient = exports.WindowNetworkListener = exports.IndexedDBStorage = exports.weakHash = exports.coerceQuery = exports.getOps = exports.lookup = exports.tx = exports.id = exports.init = void 0;
const Reactor_1 = __importDefault(require("./Reactor"));
const instatx_1 = require("./instatx");
Object.defineProperty(exports, "tx", { enumerable: true, get: function () { return instatx_1.tx; } });
Object.defineProperty(exports, "lookup", { enumerable: true, get: function () { return instatx_1.lookup; } });
Object.defineProperty(exports, "getOps", { enumerable: true, get: function () { return instatx_1.getOps; } });

@@ -12,0 +13,0 @@ const weakHash_1 = __importDefault(require("./utils/weakHash"));

@@ -27,2 +27,25 @@ "use strict";

exports.getAttrByReverseIdentName = getAttrByReverseIdentName;
function explodeLookupRef(eid) {
if (Array.isArray(eid)) {
return eid;
}
const entries = Object.entries(eid);
if (entries.length !== 1) {
throw new Error("lookup must be an object with a single unique attr and value.");
}
return entries[0];
}
function extractLookup(attrs, etype, eid) {
if (typeof eid === "string" && !(0, instatx_1.isLookup)(eid)) {
return eid;
}
const [identName, value] = typeof eid === "string" && (0, instatx_1.isLookup)(eid)
? (0, instatx_1.parseLookup)(eid)
: explodeLookupRef(eid);
const attr = getAttrByFwdIdentName(attrs, etype, identName);
if (!attr || !attr["unique?"]) {
throw new Error(`${identName} is not a unique attribute.`);
}
return [attr.id, value];
}
function expandLink(attrs, [etype, eidA, obj]) {

@@ -35,4 +58,14 @@ const addTriples = Object.entries(obj).flatMap(([label, eidOrEids]) => {

const txStep = fwdAttr
? ["add-triple", eidA, fwdAttr.id, eidB]
: ["add-triple", eidB, revAttr.id, eidA];
? [
"add-triple",
extractLookup(attrs, etype, eidA),
fwdAttr.id,
extractLookup(attrs, fwdAttr["reverse-identity"][1], eidB),
]
: [
"add-triple",
extractLookup(attrs, revAttr["forward-identity"][1], eidB),
revAttr.id,
extractLookup(attrs, etype, eidA),
];
return txStep;

@@ -50,4 +83,14 @@ });

const txStep = fwdAttr
? ["retract-triple", eidA, fwdAttr.id, eidB]
: ["retract-triple", eidB, revAttr.id, eidA];
? [
"retract-triple",
extractLookup(attrs, etype, eidA),
fwdAttr.id,
extractLookup(attrs, fwdAttr["reverse-identity"][1], eidB),
]
: [
"retract-triple",
extractLookup(attrs, revAttr["forward-identity"][1], eidB),
revAttr.id,
extractLookup(attrs, etype, eidA),
];
return txStep;

@@ -59,24 +102,27 @@ });

function expandUpdate(attrs, [etype, eid, obj]) {
const lookup = extractLookup(attrs, etype, eid);
const attrTuples = Object.entries(obj)
.concat([["id", eid]])
.concat([["id", extractLookup(attrs, etype, eid)]])
.map(([identName, value]) => {
const attr = getAttrByFwdIdentName(attrs, etype, identName);
return ["add-triple", eid, attr.id, value];
return ["add-triple", lookup, attr.id, value];
});
return attrTuples;
}
function expandDelete(_attrs, [_etype, eid]) {
return [["delete-entity", eid]];
function expandDelete(attrs, [etype, eid]) {
const lookup = extractLookup(attrs, etype, eid);
return [["delete-entity", lookup]];
}
function expandDeepMerge(attrs, [etype, eid, obj]) {
const lookup = extractLookup(attrs, etype, eid);
const attrTuples = Object.entries(obj).map(([identName, value]) => {
const attr = getAttrByFwdIdentName(attrs, etype, identName);
const coercedValue = (0, object_1.immutableDeepReplace)(value, undefined, null);
return ["deep-merge-triple", eid, attr.id, coercedValue];
return ["deep-merge-triple", lookup, attr.id, coercedValue];
});
const idTuple = [
"add-triple",
eid,
lookup,
getAttrByFwdIdentName(attrs, etype, "id").id,
eid,
lookup,
];

@@ -83,0 +129,0 @@ return attrTuples.concat([idTuple]);

@@ -5,3 +5,5 @@ declare type Action = "update" | "link" | "unlink" | "delete" | "merge";

declare type Args = any;
export declare type Op = [Action, EType, Id, Args];
declare type LookupRef = [string, any];
declare type Lookup = string;
export declare type Op = [Action, EType, Id | LookupRef, Args];
export interface TransactionChunk {

@@ -95,2 +97,11 @@ __ops: Op[];

/**
* Creates a lookup to use in place of an id in a transaction
*
* @example
* tx.users[lookup('email', 'lyndon@example.com')].update({name: 'Lyndon'})
*/
export declare function lookup(attribute: string, value: string): Lookup;
export declare function isLookup(k: string): boolean;
export declare function parseLookup(k: string): LookupRef;
/**
* A handy builder for changes.

@@ -97,0 +108,0 @@ *

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getOps = exports.tx = void 0;
exports.getOps = exports.tx = exports.parseLookup = exports.isLookup = exports.lookup = void 0;
function transactionChunk(etype, id, prevOps) {

@@ -18,5 +18,27 @@ return new Proxy({}, {

}
/**
* Creates a lookup to use in place of an id in a transaction
*
* @example
* tx.users[lookup('email', 'lyndon@example.com')].update({name: 'Lyndon'})
*/
function lookup(attribute, value) {
return `lookup__${attribute}__${JSON.stringify(value)}`;
}
exports.lookup = lookup;
function isLookup(k) {
return k.startsWith("lookup__");
}
exports.isLookup = isLookup;
function parseLookup(k) {
const [_, eid, ...vJSON] = k.split("__");
return [eid, JSON.parse(vJSON.join("__"))];
}
exports.parseLookup = parseLookup;
function etypeChunk(etype) {
return new Proxy({}, {
get(_target, id) {
if (isLookup(id)) {
return transactionChunk(etype, parseLookup(id), []);
}
return transactionChunk(etype, id, []);

@@ -23,0 +45,0 @@ },

import Reactor from "./Reactor";
import { tx, TransactionChunk, EmptyChunk, getOps } from "./instatx";
import { tx, lookup, TransactionChunk, EmptyChunk, getOps } from "./instatx";
import weakHash from "./utils/weakHash";

@@ -281,3 +281,3 @@ import id from "./utils/uuid";

declare function coerceQuery(o: any): any;
export { init, id, tx, getOps, coerceQuery, weakHash, IndexedDBStorage, WindowNetworkListener, InstantCore as InstantClient, Auth, RoomSchemaShape, Query, QueryResponse, InstantObject, Exactly, TransactionChunk, QueryState, AuthState, User, AuthToken, EmptyChunk, SubscriptionState, LifecycleSubscriptionState, PresenceOpts, PresenceSlice, PresenceResponse, };
export { init, id, tx, lookup, getOps, coerceQuery, weakHash, IndexedDBStorage, WindowNetworkListener, InstantCore as InstantClient, Auth, RoomSchemaShape, Query, QueryResponse, InstantObject, Exactly, TransactionChunk, QueryState, AuthState, User, AuthToken, EmptyChunk, SubscriptionState, LifecycleSubscriptionState, PresenceOpts, PresenceSlice, PresenceResponse, };
/**

@@ -284,0 +284,0 @@ * @deprecated since 0.7.0, use client returned from `init` instead

import Reactor from "./Reactor";
import { tx, getOps } from "./instatx";
import { tx, lookup, getOps } from "./instatx";
import weakHash from "./utils/weakHash";

@@ -306,3 +306,3 @@ import id from "./utils/uuid";

// bada bing bada boom
init, id, tx,
init, id, tx, lookup,
// util

@@ -309,0 +309,0 @@ getOps, coerceQuery, weakHash, IndexedDBStorage, WindowNetworkListener, InstantCore as InstantClient, Auth, };

@@ -1,2 +0,2 @@

import { getOps } from "./instatx";
import { getOps, isLookup, parseLookup } from "./instatx";
import { immutableDeepReplace } from "./utils/object";

@@ -19,2 +19,25 @@ import uuid from "./utils/uuid";

}
function explodeLookupRef(eid) {
if (Array.isArray(eid)) {
return eid;
}
const entries = Object.entries(eid);
if (entries.length !== 1) {
throw new Error("lookup must be an object with a single unique attr and value.");
}
return entries[0];
}
function extractLookup(attrs, etype, eid) {
if (typeof eid === "string" && !isLookup(eid)) {
return eid;
}
const [identName, value] = typeof eid === "string" && isLookup(eid)
? parseLookup(eid)
: explodeLookupRef(eid);
const attr = getAttrByFwdIdentName(attrs, etype, identName);
if (!attr || !attr["unique?"]) {
throw new Error(`${identName} is not a unique attribute.`);
}
return [attr.id, value];
}
function expandLink(attrs, [etype, eidA, obj]) {

@@ -27,4 +50,14 @@ const addTriples = Object.entries(obj).flatMap(([label, eidOrEids]) => {

const txStep = fwdAttr
? ["add-triple", eidA, fwdAttr.id, eidB]
: ["add-triple", eidB, revAttr.id, eidA];
? [
"add-triple",
extractLookup(attrs, etype, eidA),
fwdAttr.id,
extractLookup(attrs, fwdAttr["reverse-identity"][1], eidB),
]
: [
"add-triple",
extractLookup(attrs, revAttr["forward-identity"][1], eidB),
revAttr.id,
extractLookup(attrs, etype, eidA),
];
return txStep;

@@ -42,4 +75,14 @@ });

const txStep = fwdAttr
? ["retract-triple", eidA, fwdAttr.id, eidB]
: ["retract-triple", eidB, revAttr.id, eidA];
? [
"retract-triple",
extractLookup(attrs, etype, eidA),
fwdAttr.id,
extractLookup(attrs, fwdAttr["reverse-identity"][1], eidB),
]
: [
"retract-triple",
extractLookup(attrs, revAttr["forward-identity"][1], eidB),
revAttr.id,
extractLookup(attrs, etype, eidA),
];
return txStep;

@@ -51,24 +94,27 @@ });

function expandUpdate(attrs, [etype, eid, obj]) {
const lookup = extractLookup(attrs, etype, eid);
const attrTuples = Object.entries(obj)
.concat([["id", eid]])
.concat([["id", extractLookup(attrs, etype, eid)]])
.map(([identName, value]) => {
const attr = getAttrByFwdIdentName(attrs, etype, identName);
return ["add-triple", eid, attr.id, value];
return ["add-triple", lookup, attr.id, value];
});
return attrTuples;
}
function expandDelete(_attrs, [_etype, eid]) {
return [["delete-entity", eid]];
function expandDelete(attrs, [etype, eid]) {
const lookup = extractLookup(attrs, etype, eid);
return [["delete-entity", lookup]];
}
function expandDeepMerge(attrs, [etype, eid, obj]) {
const lookup = extractLookup(attrs, etype, eid);
const attrTuples = Object.entries(obj).map(([identName, value]) => {
const attr = getAttrByFwdIdentName(attrs, etype, identName);
const coercedValue = immutableDeepReplace(value, undefined, null);
return ["deep-merge-triple", eid, attr.id, coercedValue];
return ["deep-merge-triple", lookup, attr.id, coercedValue];
});
const idTuple = [
"add-triple",
eid,
lookup,
getAttrByFwdIdentName(attrs, etype, "id").id,
eid,
lookup,
];

@@ -75,0 +121,0 @@ return attrTuples.concat([idTuple]);

@@ -5,3 +5,5 @@ declare type Action = "update" | "link" | "unlink" | "delete" | "merge";

declare type Args = any;
export declare type Op = [Action, EType, Id, Args];
declare type LookupRef = [string, any];
declare type Lookup = string;
export declare type Op = [Action, EType, Id | LookupRef, Args];
export interface TransactionChunk {

@@ -95,2 +97,11 @@ __ops: Op[];

/**
* Creates a lookup to use in place of an id in a transaction
*
* @example
* tx.users[lookup('email', 'lyndon@example.com')].update({name: 'Lyndon'})
*/
export declare function lookup(attribute: string, value: string): Lookup;
export declare function isLookup(k: string): boolean;
export declare function parseLookup(k: string): LookupRef;
/**
* A handy builder for changes.

@@ -97,0 +108,0 @@ *

@@ -15,5 +15,24 @@ function transactionChunk(etype, id, prevOps) {

}
/**
* Creates a lookup to use in place of an id in a transaction
*
* @example
* tx.users[lookup('email', 'lyndon@example.com')].update({name: 'Lyndon'})
*/
export function lookup(attribute, value) {
return `lookup__${attribute}__${JSON.stringify(value)}`;
}
export function isLookup(k) {
return k.startsWith("lookup__");
}
export function parseLookup(k) {
const [_, eid, ...vJSON] = k.split("__");
return [eid, JSON.parse(vJSON.join("__"))];
}
function etypeChunk(etype) {
return new Proxy({}, {
get(_target, id) {
if (isLookup(id)) {
return transactionChunk(etype, parseLookup(id), []);
}
return transactionChunk(etype, id, []);

@@ -20,0 +39,0 @@ },

@@ -71,3 +71,61 @@ import { produce, enableMapSet } from "immer";

}
function retractTriple(store, triple) {
// We may have local triples with lookup refs in them,
// we need to convert those lookup refs to eids to insert them
// into the store. If we can't find the lookup ref locally,
// then we drop the triple and have to wait for the server response
// to see the optimistic updates.
function resolveLookupRefs(store, triple) {
var _a, _b;
let eid;
// Check if `e` is a lookup ref
if (Array.isArray(triple[0])) {
const [a, v] = triple[0];
const eMaps = store.aev.get(a);
if (!eMaps) {
// We don't have the attr, so don't try to add the
// triple to the store
return null;
}
// This would be a lot more efficient with a ave index
const triples = allMapValues(eMaps, 2);
eid = (_a = triples.find((x) => x[2] === v)) === null || _a === void 0 ? void 0 : _a[0];
}
else {
eid = triple[0];
}
if (!eid) {
// We don't know the eid that the ref refers to, so
// we can't add the triple to the store.
return null;
}
// Check if v is a lookup ref
const lookupV = triple[2];
if (Array.isArray(lookupV) &&
lookupV.length === 2 &&
store.aev.get(lookupV[0])) {
const [a, v] = lookupV;
const eMaps = store.aev.get(a);
if (!eMaps) {
// We don't have the attr, so don't try to add the
// triple to the store
return null;
}
const triples = allMapValues(eMaps, 2);
const value = (_b = triples.find((x) => x[2] === v)) === null || _b === void 0 ? void 0 : _b[0];
if (!value) {
return null;
}
const [_e, aid, _v, ...rest] = triple;
return [eid, aid, value, ...rest];
}
else {
const [_, ...rest] = triple;
return [eid, ...rest];
}
}
function retractTriple(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [eid, aid, v] = triple;

@@ -119,3 +177,7 @@ const attr = getAttr(store.attrs, aid);

}
function addTriple(store, triple) {
function addTriple(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [eid, aid, v] = triple;

@@ -143,4 +205,8 @@ const attr = getAttr(store.attrs, aid);

}
function mergeTriple(store, triple) {
function mergeTriple(store, rawTriple) {
var _a;
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [eid, aid, update] = triple;

@@ -173,3 +239,8 @@ const attr = getAttr(store.attrs, aid);

}
function deleteEntity(store, [id]) {
function deleteEntity(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [id] = triple;
// delete forward links

@@ -176,0 +247,0 @@ const eMap = store.eav.get(id);

@@ -75,3 +75,61 @@ "use strict";

exports.createStore = createStore;
function retractTriple(store, triple) {
// We may have local triples with lookup refs in them,
// we need to convert those lookup refs to eids to insert them
// into the store. If we can't find the lookup ref locally,
// then we drop the triple and have to wait for the server response
// to see the optimistic updates.
function resolveLookupRefs(store, triple) {
var _a, _b;
let eid;
// Check if `e` is a lookup ref
if (Array.isArray(triple[0])) {
const [a, v] = triple[0];
const eMaps = store.aev.get(a);
if (!eMaps) {
// We don't have the attr, so don't try to add the
// triple to the store
return null;
}
// This would be a lot more efficient with a ave index
const triples = allMapValues(eMaps, 2);
eid = (_a = triples.find((x) => x[2] === v)) === null || _a === void 0 ? void 0 : _a[0];
}
else {
eid = triple[0];
}
if (!eid) {
// We don't know the eid that the ref refers to, so
// we can't add the triple to the store.
return null;
}
// Check if v is a lookup ref
const lookupV = triple[2];
if (Array.isArray(lookupV) &&
lookupV.length === 2 &&
store.aev.get(lookupV[0])) {
const [a, v] = lookupV;
const eMaps = store.aev.get(a);
if (!eMaps) {
// We don't have the attr, so don't try to add the
// triple to the store
return null;
}
const triples = allMapValues(eMaps, 2);
const value = (_b = triples.find((x) => x[2] === v)) === null || _b === void 0 ? void 0 : _b[0];
if (!value) {
return null;
}
const [_e, aid, _v, ...rest] = triple;
return [eid, aid, value, ...rest];
}
else {
const [_, ...rest] = triple;
return [eid, ...rest];
}
}
function retractTriple(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [eid, aid, v] = triple;

@@ -123,3 +181,7 @@ const attr = getAttr(store.attrs, aid);

}
function addTriple(store, triple) {
function addTriple(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [eid, aid, v] = triple;

@@ -147,4 +209,8 @@ const attr = getAttr(store.attrs, aid);

}
function mergeTriple(store, triple) {
function mergeTriple(store, rawTriple) {
var _a;
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [eid, aid, update] = triple;

@@ -177,3 +243,8 @@ const attr = getAttr(store.attrs, aid);

}
function deleteEntity(store, [id]) {
function deleteEntity(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [id] = triple;
// delete forward links

@@ -180,0 +251,0 @@ const eMap = store.eav.get(id);

{
"name": "@instantdb/core",
"version": "0.10.27",
"version": "0.10.28",
"description": "Instant's core local abstraction",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

import Reactor from "./Reactor";
import { tx, TransactionChunk, EmptyChunk, getOps } from "./instatx";
import { tx, lookup, TransactionChunk, EmptyChunk, getOps } from "./instatx";
import weakHash from "./utils/weakHash";

@@ -438,2 +438,3 @@ import id from "./utils/uuid";

tx,
lookup,

@@ -440,0 +441,0 @@ // util

@@ -1,2 +0,2 @@

import { getOps } from "./instatx";
import { getOps, isLookup, parseLookup } from "./instatx";
import { immutableDeepReplace } from "./utils/object";

@@ -21,2 +21,30 @@ import uuid from "./utils/uuid";

function explodeLookupRef(eid) {
if (Array.isArray(eid)) {
return eid;
}
const entries = Object.entries(eid);
if (entries.length !== 1) {
throw new Error(
"lookup must be an object with a single unique attr and value.",
);
}
return entries[0];
}
function extractLookup(attrs, etype, eid) {
if (typeof eid === "string" && !isLookup(eid)) {
return eid;
}
const [identName, value] =
typeof eid === "string" && isLookup(eid)
? parseLookup(eid)
: explodeLookupRef(eid);
const attr = getAttrByFwdIdentName(attrs, etype, identName);
if (!attr || !attr["unique?"]) {
throw new Error(`${identName} is not a unique attribute.`);
}
return [attr.id, value];
}
function expandLink(attrs, [etype, eidA, obj]) {

@@ -29,4 +57,14 @@ const addTriples = Object.entries(obj).flatMap(([label, eidOrEids]) => {

const txStep = fwdAttr
? ["add-triple", eidA, fwdAttr.id, eidB]
: ["add-triple", eidB, revAttr.id, eidA];
? [
"add-triple",
extractLookup(attrs, etype, eidA),
fwdAttr.id,
extractLookup(attrs, fwdAttr["reverse-identity"][1], eidB),
]
: [
"add-triple",
extractLookup(attrs, revAttr["forward-identity"][1], eidB),
revAttr.id,
extractLookup(attrs, etype, eidA),
];
return txStep;

@@ -45,4 +83,14 @@ });

const txStep = fwdAttr
? ["retract-triple", eidA, fwdAttr.id, eidB]
: ["retract-triple", eidB, revAttr.id, eidA];
? [
"retract-triple",
extractLookup(attrs, etype, eidA),
fwdAttr.id,
extractLookup(attrs, fwdAttr["reverse-identity"][1], eidB),
]
: [
"retract-triple",
extractLookup(attrs, revAttr["forward-identity"][1], eidB),
revAttr.id,
extractLookup(attrs, etype, eidA),
];
return txStep;

@@ -55,21 +103,23 @@ });

function expandUpdate(attrs, [etype, eid, obj]) {
const lookup = extractLookup(attrs, etype, eid);
const attrTuples = Object.entries(obj)
.concat([["id", eid]])
.concat([["id", extractLookup(attrs, etype, eid)]])
.map(([identName, value]) => {
const attr = getAttrByFwdIdentName(attrs, etype, identName);
return ["add-triple", eid, attr.id, value];
return ["add-triple", lookup, attr.id, value];
});
return attrTuples;
}
function expandDelete(_attrs, [_etype, eid]) {
return [["delete-entity", eid]];
function expandDelete(attrs, [etype, eid]) {
const lookup = extractLookup(attrs, etype, eid);
return [["delete-entity", lookup]];
}
function expandDeepMerge(attrs, [etype, eid, obj]) {
const lookup = extractLookup(attrs, etype, eid);
const attrTuples = Object.entries(obj).map(([identName, value]) => {
const attr = getAttrByFwdIdentName(attrs, etype, identName);
const coercedValue = immutableDeepReplace(value, undefined, null);
return ["deep-merge-triple", eid, attr.id, coercedValue];
return ["deep-merge-triple", lookup, attr.id, coercedValue];
});

@@ -79,5 +129,5 @@

"add-triple",
eid,
lookup,
getAttrByFwdIdentName(attrs, etype, "id").id,
eid,
lookup,
];

@@ -84,0 +134,0 @@

@@ -5,3 +5,5 @@ type Action = "update" | "link" | "unlink" | "delete" | "merge";

type Args = any;
export type Op = [Action, EType, Id, Args];
type LookupRef = [string, any];
type Lookup = string;
export type Op = [Action, EType, Id | LookupRef, Args];

@@ -95,3 +97,3 @@ export interface TransactionChunk {

etype: EType,
id: Id,
id: Id | LookupRef,
prevOps: Op[],

@@ -112,2 +114,21 @@ ): TransactionChunk {

/**
* Creates a lookup to use in place of an id in a transaction
*
* @example
* tx.users[lookup('email', 'lyndon@example.com')].update({name: 'Lyndon'})
*/
export function lookup(attribute: string, value: string): Lookup {
return `lookup__${attribute}__${JSON.stringify(value)}`;
}
export function isLookup(k: string): boolean {
return k.startsWith("lookup__");
}
export function parseLookup(k: string): LookupRef {
const [_, eid, ...vJSON] = k.split("__");
return [eid, JSON.parse(vJSON.join("__"))];
}
function etypeChunk(etype: EType): ETypeChunk {

@@ -118,2 +139,5 @@ return new Proxy(

get(_target, id: Id) {
if (isLookup(id)) {
return transactionChunk(etype, parseLookup(id), []);
}
return transactionChunk(etype, id, []);

@@ -120,0 +144,0 @@ },

@@ -81,3 +81,64 @@ import { produce, enableMapSet } from "immer";

function retractTriple(store, triple) {
// We may have local triples with lookup refs in them,
// we need to convert those lookup refs to eids to insert them
// into the store. If we can't find the lookup ref locally,
// then we drop the triple and have to wait for the server response
// to see the optimistic updates.
function resolveLookupRefs(store, triple) {
let eid;
// Check if `e` is a lookup ref
if (Array.isArray(triple[0])) {
const [a, v] = triple[0];
const eMaps = store.aev.get(a);
if (!eMaps) {
// We don't have the attr, so don't try to add the
// triple to the store
return null;
}
// This would be a lot more efficient with a ave index
const triples = allMapValues(eMaps, 2);
eid = triples.find((x) => x[2] === v)?.[0];
} else {
eid = triple[0];
}
if (!eid) {
// We don't know the eid that the ref refers to, so
// we can't add the triple to the store.
return null;
}
// Check if v is a lookup ref
const lookupV = triple[2];
if (
Array.isArray(lookupV) &&
lookupV.length === 2 &&
store.aev.get(lookupV[0])
) {
const [a, v] = lookupV;
const eMaps = store.aev.get(a);
if (!eMaps) {
// We don't have the attr, so don't try to add the
// triple to the store
return null;
}
const triples = allMapValues(eMaps, 2);
const value = triples.find((x) => x[2] === v)?.[0];
if (!value) {
return null;
}
const [_e, aid, _v, ...rest] = triple;
return [eid, aid, value, ...rest];
} else {
const [_, ...rest] = triple;
return [eid, ...rest];
}
}
function retractTriple(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [eid, aid, v] = triple;

@@ -133,3 +194,7 @@ const attr = getAttr(store.attrs, aid);

function addTriple(store, triple) {
function addTriple(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [eid, aid, v] = triple;

@@ -145,2 +210,3 @@ const attr = getAttr(store.attrs, aid);

const enhancedTriple = [...triple, getCreatedAt(store, attr, triple)];
if (hasEA(attr)) {

@@ -159,3 +225,8 @@ setInMap(store.eav, [eid, aid], new Map([[v, enhancedTriple]]));

function mergeTriple(store, triple) {
function mergeTriple(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [eid, aid, update] = triple;

@@ -192,3 +263,9 @@ const attr = getAttr(store.attrs, aid);

function deleteEntity(store, [id]) {
function deleteEntity(store, rawTriple) {
const triple = resolveLookupRefs(store, rawTriple);
if (!triple) {
return;
}
const [id] = triple;
// delete forward links

@@ -195,0 +272,0 @@ const eMap = store.eav.get(id);

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 not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc