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

@data-eden/athena

Package Overview
Dependencies
Maintainers
4
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@data-eden/athena - npm Package Compare versions

Comparing version 0.7.2 to 0.8.0

__tests__/client.test.ts

52

__tests__/signal-cache.test.ts

@@ -438,2 +438,54 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */

});
test('can resolve cycle with array property with multiple values', () => {
cache.evict('Person:1');
cache.evict('Pet:1');
cache.storeEntity('Person:1', {
...Person1,
pets: [
{
__link: 'Pet:1',
},
{
__link: 'Pet:2',
},
],
});
cache.storeEntity('Pet:1', {
...Pet1,
owner: {
__link: 'Person:1',
},
});
cache.storeEntity('Pet:2', {
...Pet2,
owner: {
__link: 'Person:1',
},
});
const pet1 = cache.resolve('Pet:1');
expect(pet1.__typename).toEqual('Pet');
expect(pet1.name).toEqual('Hitch');
expect(pet1.owner.__typename).toEqual('Person');
expect(pet1.owner.name).toEqual('Foo');
expect(pet1.owner.pets[0].name).toEqual('Hitch');
expect(pet1.owner.pets[0].owner.__typename).toEqual('Person');
const pet2 = cache.resolve('Pet:2');
expect(pet2.__typename).toEqual('Pet');
expect(pet2.name).toEqual('Dre');
expect(pet2.owner.__typename).toEqual('Person');
expect(pet2.owner.name).toEqual('Foo');
expect(pet2.owner.pets[1].name).toEqual('Dre');
expect(pet2.owner.pets[1].owner.__typename).toEqual('Person');
// Owners for both pets should be the same object
expect(pet1.owner).toBe(pet2.owner);
});
});

@@ -440,0 +492,0 @@

4

dist/client.d.ts
import type { DefaultVariables, DocumentInput, GraphQLRequest, IdFetcher, OperationResult, ReactiveAdapter } from './types.js';
export interface ClientArgs {
url: string;
id: IdFetcher;
getCacheKey: IdFetcher;
fetch?: typeof fetch;

@@ -17,3 +17,3 @@ buildRequest?: BuildRequest;

private cache;
private getId;
private getCacheKey;
private signalCache;

@@ -20,0 +20,0 @@ private buildRequest;

@@ -18,6 +18,6 @@ import { buildCache } from '@data-eden/cache';

this.url = options.url;
this.getId = options.id;
this.fetch = options.fetch || globalThis.fetch;
this.getCacheKey = options.getCacheKey;
this.fetch = options.fetch || globalThis.fetch.bind(globalThis);
this.buildRequest = options.buildRequest || defaultBuildRequest;
this.signalCache = new SignalCache(options.adapter, options.id);
this.signalCache = new SignalCache(options.adapter, options.getCacheKey);
const signalCache = this.signalCache;

@@ -69,3 +69,2 @@ this.cache = buildCache({

async processEntities(response) {
let fakeRevisionCounter = 0;
const parsedEntitiesList = parseEntities(response);

@@ -94,3 +93,3 @@ // This object maps "root" entities from a graphql docment to the key used to store them in the

for (const { parent, prop, entity } of parsedEntities) {
const key = this.getId(entity);
const key = this.getCacheKey(entity, parent);
// replace the entity object with the key we're using to store it in the cache so that we can

@@ -105,5 +104,3 @@ // later replace the key with the reactive entity

}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
await tx.merge(key, { entity, revision: fakeRevisionCounter++ });
await tx.merge(key, entity);
}

@@ -110,0 +107,0 @@ await tx.commit();

@@ -18,3 +18,3 @@ import type { DefaultRecord, DefaultVariables, Entity, IdFetcher, ReactiveAdapter, Scalar, WithSignal } from './types.js';

export declare class SignalCache {
getId: IdFetcher;
getCacheKey: IdFetcher;
signalAdapter: ReactiveAdapter;

@@ -26,6 +26,6 @@ queryLinks: Map<string, Link>;

private registry;
constructor(signalAdapter: ReactiveAdapter, getId?: IdFetcher);
constructor(signalAdapter: ReactiveAdapter, getCacheKey?: IdFetcher);
store({ query, variables, result }: Payload): void;
storeEntity(key: string, entity: Entity): void;
resolve(entityKey: string, visited?: Set<string>, exploring?: Set<string>): WithSignal<Entity<Record<string, any>>>;
resolve(entityKey: string, visited?: Set<string>, exploring?: Set<string>): WithSignal<Entity<Record<string, any>>> | undefined;
evict(entityKey: string): void;

@@ -32,0 +32,0 @@ private getSignal;

@@ -71,3 +71,3 @@ import { createSignalProxy } from './signal-proxy.js';

export class SignalCache {
constructor(signalAdapter, getId = defaultIdGetter) {
constructor(signalAdapter, getCacheKey = defaultIdGetter) {
this.queryLinks = new Map();

@@ -77,3 +77,3 @@ this.links = new Map();

this.signals = new Map();
this.getId = getId;
this.getCacheKey = getCacheKey;
this.signalAdapter = signalAdapter;

@@ -142,2 +142,7 @@ this.registry = new FinalizationRegistry((key) => {

const signal = this.getSignal(entityKey);
// If we've already visited this node in a given `resolve` computation, it means we've already
// fully materialized its data and can just return it from the signal cache
if (visited.has(entityKey)) {
return signal;
}
if (signal) {

@@ -176,3 +181,3 @@ root = signal;

const toRemove = parentArray.filter((v) => {
return !value.includes(this.getId(v));
return !value.includes(this.getCacheKey(v, parent));
});

@@ -198,7 +203,2 @@ for (let entity of toRemove) {

}
// If this node has already been visited, we know it has already been fully traveresed
// and don't need to continue
if (visited.has(value)) {
return false;
}
// If this node is already being explored, we're in a cycle and need to bail

@@ -220,2 +220,9 @@ if (exploring.has(value)) {

}
// If this node has already been visited, we know it has already been fully traversed
// and don't need to continue
if (visited.has(value)) {
return false;
}
// If we've made it here, it means that we've fully traversed all the elements in this path
// and can mark this node as having been visited so we don't traverse it again
exploring.delete(value);

@@ -222,0 +229,0 @@ visited.add(value);

@@ -49,3 +49,3 @@ import type { buildCache } from '@data-eden/cache';

}
export type IdFetcher<T = any> = (v: T) => string;
export type IdFetcher<T = any> = (v: T, parent: T) => string;
//# sourceMappingURL=types.d.ts.map
{
"name": "@data-eden/athena",
"version": "0.7.2",
"version": "0.8.0",
"repository": {

@@ -24,6 +24,7 @@ "type": "git",

"build": "tsc --build",
"dev": "tsc --watch",
"test": "vitest run"
},
"dependencies": {
"@data-eden/cache": "^0.7.2",
"@data-eden/cache": "^0.8.0",
"lodash-es": "^4.17.21"

@@ -30,0 +31,0 @@ },

@@ -19,3 +19,3 @@ import { buildCache } from '@data-eden/cache';

url: string;
id: IdFetcher;
getCacheKey: IdFetcher;
fetch?: typeof fetch;

@@ -45,3 +45,3 @@ buildRequest?: BuildRequest;

private cache: DataEdenCache;
private getId: IdFetcher;
private getCacheKey: IdFetcher;
private signalCache: SignalCache;

@@ -52,6 +52,6 @@ private buildRequest: BuildRequest;

this.url = options.url;
this.getId = options.id;
this.fetch = options.fetch || globalThis.fetch;
this.getCacheKey = options.getCacheKey;
this.fetch = options.fetch || globalThis.fetch.bind(globalThis);
this.buildRequest = options.buildRequest || defaultBuildRequest;
this.signalCache = new SignalCache(options.adapter, options.id);
this.signalCache = new SignalCache(options.adapter, options.getCacheKey);

@@ -133,4 +133,2 @@ const signalCache = this.signalCache;

): Promise<Data> {
let fakeRevisionCounter = 0;
const parsedEntitiesList = parseEntities(response);

@@ -161,3 +159,3 @@

for (const { parent, prop, entity } of parsedEntities) {
const key = this.getId(entity);
const key = this.getCacheKey(entity, parent);

@@ -175,5 +173,3 @@ // replace the entity object with the key we're using to store it in the cache so that we can

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
await tx.merge(key, { entity, revision: fakeRevisionCounter++ });
await tx.merge(key, entity);
}

@@ -180,0 +176,0 @@ await tx.commit();

@@ -126,3 +126,3 @@ import type { Entries } from 'type-fest';

export class SignalCache {
getId: IdFetcher;
getCacheKey: IdFetcher;
signalAdapter: ReactiveAdapter;

@@ -137,5 +137,5 @@ queryLinks = new Map<string, Link>();

signalAdapter: ReactiveAdapter,
getId: IdFetcher = defaultIdGetter
getCacheKey: IdFetcher = defaultIdGetter
) {
this.getId = getId;
this.getCacheKey = getCacheKey;
this.signalAdapter = signalAdapter;

@@ -224,2 +224,8 @@ this.registry = new FinalizationRegistry((key) => {

// If we've already visited this node in a given `resolve` computation, it means we've already
// fully materialized its data and can just return it from the signal cache
if (visited.has(entityKey)) {
return signal;
}
if (signal) {

@@ -267,3 +273,3 @@ root = signal;

const toRemove = parentArray.filter((v) => {
return !value.includes(this.getId(v));
return !value.includes(this.getCacheKey(v, parent));
});

@@ -294,8 +300,2 @@

// If this node has already been visited, we know it has already been fully traveresed
// and don't need to continue
if (visited.has(value)) {
return false;
}
// If this node is already being explored, we're in a cycle and need to bail

@@ -309,2 +309,3 @@ if (exploring.has(value)) {

const resolved = this.resolve(value, visited, exploring);
if (resolved) {

@@ -320,2 +321,10 @@ if (parentArray) {

// If this node has already been visited, we know it has already been fully traversed
// and don't need to continue
if (visited.has(value)) {
return false;
}
// If we've made it here, it means that we've fully traversed all the elements in this path
// and can mark this node as having been visited so we don't traverse it again
exploring.delete(value);

@@ -322,0 +331,0 @@ visited.add(value);

@@ -68,2 +68,2 @@ import type { buildCache } from '@data-eden/cache';

export type IdFetcher<T = any> = (v: T) => string;
export type IdFetcher<T = any> = (v: T, parent: T) => string;

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