mirror of
https://github.com/expo/entity.git
synced 2026-11-13 20:28:06 -10:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0704a8249 | ||
|
|
a2c6dd7488 | ||
|
|
e1b0ee5281 |
No files matched your search
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [0.22.0](https://github.com/expo/entity/compare/v0.21.0...v0.22.0) (2022-02-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Upgrade knex to 1.x in `@expo/entity-database-adapter-knex` ([#150](https://github.com/expo/entity/issues/150)) ([e1b0ee5](https://github.com/expo/entity/commit/e1b0ee528175646239d88aa71ffce73983eeb52f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.21.0](https://github.com/expo/entity/compare/v0.20.0...v0.21.0) (2022-01-03)
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -4,5 +4,5 @@
|
||||
],
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "0.21.0"
|
||||
"version": "0.22.0"
|
||||
}
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [0.22.0](https://github.com/expo/entity/compare/v0.21.0...v0.22.0) (2022-02-04)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-cache-adapter-redis
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.21.0](https://github.com/expo/entity/compare/v0.20.0...v0.21.0) (2022-01-03)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-cache-adapter-redis
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/entity-cache-adapter-redis",
|
||||
"version": "0.21.0",
|
||||
"version": "0.22.0",
|
||||
"description": "Redis cache adapter for @expo/entity",
|
||||
"files": [
|
||||
"build",
|
||||
@@ -33,6 +33,6 @@
|
||||
"ioredis": "^4.27.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/entity": "^0.21.0"
|
||||
"@expo/entity": "^0.22.0"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
import { CacheLoadResult, CacheStatus } from '@expo/entity';
|
||||
import {
|
||||
CacheLoadResult,
|
||||
CacheStatus,
|
||||
EntityConfiguration,
|
||||
transformCacheObjectToFields,
|
||||
transformFieldsToCacheObject,
|
||||
} from '@expo/entity';
|
||||
import { Redis } from 'ioredis';
|
||||
|
||||
import { redisTransformerMap } from './RedisCommon';
|
||||
import wrapNativeRedisCallAsync from './errors/wrapNativeRedisCallAsync';
|
||||
|
||||
// Sentinel value we store in Redis to negatively cache a database miss.
|
||||
@@ -26,12 +33,15 @@ export interface GenericRedisCacheContext {
|
||||
ttlSecondsNegative: number;
|
||||
}
|
||||
|
||||
export default class GenericRedisCacher {
|
||||
constructor(private readonly context: GenericRedisCacheContext) {}
|
||||
export default class GenericRedisCacher<TFields> {
|
||||
constructor(
|
||||
private readonly context: GenericRedisCacheContext,
|
||||
private readonly entityConfiguration: EntityConfiguration<TFields>
|
||||
) {}
|
||||
|
||||
public async loadManyAsync(
|
||||
keys: readonly string[]
|
||||
): Promise<ReadonlyMap<string, CacheLoadResult>> {
|
||||
): Promise<ReadonlyMap<string, CacheLoadResult<TFields>>> {
|
||||
if (keys.length === 0) {
|
||||
return new Map();
|
||||
}
|
||||
@@ -40,7 +50,7 @@ export default class GenericRedisCacher {
|
||||
this.context.redisClient.mget(...keys)
|
||||
);
|
||||
|
||||
const results = new Map<string, CacheLoadResult>();
|
||||
const results = new Map<string, CacheLoadResult<TFields>>();
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i]!;
|
||||
const redisResult = redisResults[i];
|
||||
@@ -52,7 +62,11 @@ export default class GenericRedisCacher {
|
||||
} else if (redisResult) {
|
||||
results.set(key, {
|
||||
status: CacheStatus.HIT,
|
||||
item: JSON.parse(redisResult),
|
||||
item: transformCacheObjectToFields(
|
||||
this.entityConfiguration,
|
||||
redisTransformerMap,
|
||||
JSON.parse(redisResult)
|
||||
),
|
||||
});
|
||||
} else {
|
||||
results.set(key, {
|
||||
@@ -63,7 +77,7 @@ export default class GenericRedisCacher {
|
||||
return results;
|
||||
}
|
||||
|
||||
public async cacheManyAsync(objectMap: ReadonlyMap<string, object>): Promise<void> {
|
||||
public async cacheManyAsync(objectMap: ReadonlyMap<string, Readonly<TFields>>): Promise<void> {
|
||||
if (objectMap.size === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -72,7 +86,9 @@ export default class GenericRedisCacher {
|
||||
objectMap.forEach((object, key) => {
|
||||
redisTransaction = redisTransaction.set(
|
||||
key,
|
||||
JSON.stringify(object),
|
||||
JSON.stringify(
|
||||
transformFieldsToCacheObject(this.entityConfiguration, redisTransformerMap, object)
|
||||
),
|
||||
'EX',
|
||||
this.context.ttlSecondsPositive
|
||||
);
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
import {
|
||||
EntityCacheAdapter,
|
||||
EntityConfiguration,
|
||||
CacheLoadResult,
|
||||
FieldTransformerMap,
|
||||
mapKeys,
|
||||
} from '@expo/entity';
|
||||
import { EntityCacheAdapter, EntityConfiguration, CacheLoadResult, mapKeys } from '@expo/entity';
|
||||
import invariant from 'invariant';
|
||||
import { Redis } from 'ioredis';
|
||||
|
||||
import GenericRedisCacher from './GenericRedisCacher';
|
||||
import { redisTransformerMap } from './RedisCommon';
|
||||
|
||||
export interface RedisCacheAdapterContext {
|
||||
/**
|
||||
@@ -49,28 +42,27 @@ export interface RedisCacheAdapterContext {
|
||||
}
|
||||
|
||||
export default class RedisCacheAdapter<TFields> extends EntityCacheAdapter<TFields> {
|
||||
private readonly genericRedisCacher: GenericRedisCacher;
|
||||
private readonly genericRedisCacher: GenericRedisCacher<TFields>;
|
||||
constructor(
|
||||
entityConfiguration: EntityConfiguration<TFields>,
|
||||
private readonly context: RedisCacheAdapterContext
|
||||
) {
|
||||
super(entityConfiguration);
|
||||
|
||||
this.genericRedisCacher = new GenericRedisCacher({
|
||||
redisClient: context.redisClient,
|
||||
ttlSecondsNegative: context.ttlSecondsNegative,
|
||||
ttlSecondsPositive: context.ttlSecondsPositive,
|
||||
});
|
||||
}
|
||||
|
||||
public getFieldTransformerMap(): FieldTransformerMap {
|
||||
return redisTransformerMap;
|
||||
this.genericRedisCacher = new GenericRedisCacher(
|
||||
{
|
||||
redisClient: context.redisClient,
|
||||
ttlSecondsNegative: context.ttlSecondsNegative,
|
||||
ttlSecondsPositive: context.ttlSecondsPositive,
|
||||
},
|
||||
entityConfiguration
|
||||
);
|
||||
}
|
||||
|
||||
public async loadManyAsync<N extends keyof TFields>(
|
||||
fieldName: N,
|
||||
fieldValues: readonly NonNullable<TFields[N]>[]
|
||||
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult>> {
|
||||
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>> {
|
||||
const redisCacheKeyToFieldValueMapping = new Map(
|
||||
fieldValues.map((fieldValue) => [this.makeCacheKey(fieldName, fieldValue), fieldValue])
|
||||
);
|
||||
@@ -91,7 +83,7 @@ export default class RedisCacheAdapter<TFields> extends EntityCacheAdapter<TFiel
|
||||
|
||||
public async cacheManyAsync<N extends keyof TFields>(
|
||||
fieldName: N,
|
||||
objectMap: ReadonlyMap<NonNullable<TFields[N]>, object>
|
||||
objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>
|
||||
): Promise<void> {
|
||||
await this.genericRedisCacher.cacheManyAsync(
|
||||
mapKeys(objectMap, (fieldValue) => this.makeCacheKey(fieldName, fieldValue))
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [0.22.0](https://github.com/expo/entity/compare/v0.21.0...v0.22.0) (2022-02-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Upgrade knex to 1.x in `@expo/entity-database-adapter-knex` ([#150](https://github.com/expo/entity/issues/150)) ([e1b0ee5](https://github.com/expo/entity/commit/e1b0ee528175646239d88aa71ffce73983eeb52f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.21.0](https://github.com/expo/entity/compare/v0.20.0...v0.21.0) (2022-01-03)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/entity-database-adapter-knex",
|
||||
"version": "0.21.0",
|
||||
"version": "0.22.0",
|
||||
"description": "Knex database adapter for @expo/entity",
|
||||
"files": [
|
||||
"build",
|
||||
@@ -30,9 +30,10 @@
|
||||
"@expo/entity": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"knex": "^0.95.6"
|
||||
"knex": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/entity": "^0.21.0"
|
||||
"@expo/entity": "^0.22.0",
|
||||
"pg": "^8.7.1"
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [0.22.0](https://github.com/expo/entity/compare/v0.21.0...v0.22.0) (2022-02-04)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-example
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.21.0](https://github.com/expo/entity/compare/v0.20.0...v0.21.0) (2022-01-03)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-example
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@expo/entity-example",
|
||||
"private": true,
|
||||
"version": "0.21.0",
|
||||
"version": "0.22.0",
|
||||
"description": "An example integration of the @expo/entity framework",
|
||||
"scripts": {
|
||||
"tsc": "tsc",
|
||||
@@ -23,7 +23,7 @@
|
||||
"author": "Expo",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@expo/entity": "^0.21.0",
|
||||
"@expo/entity": "^0.22.0",
|
||||
"apollo-server-koa": "^2.16.1",
|
||||
"graphql": "^15.3.0",
|
||||
"koa": "^2.13.0",
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [0.22.0](https://github.com/expo/entity/compare/v0.21.0...v0.22.0) (2022-02-04)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-full-integration-tests
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.21.0](https://github.com/expo/entity/compare/v0.20.0...v0.21.0) (2022-01-03)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-full-integration-tests
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@expo/entity-full-integration-tests",
|
||||
"private": true,
|
||||
"version": "0.21.0",
|
||||
"version": "0.22.0",
|
||||
"description": "Full redis and knex integration tests for the entity framework",
|
||||
"scripts": {
|
||||
"tsc": "tsc",
|
||||
@@ -27,8 +27,8 @@
|
||||
"@expo/entity-database-adapter-knex": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/entity": "^0.21.0",
|
||||
"@expo/entity-cache-adapter-redis": "^0.21.0",
|
||||
"@expo/entity-database-adapter-knex": "^0.21.0"
|
||||
"@expo/entity": "^0.22.0",
|
||||
"@expo/entity-cache-adapter-redis": "^0.22.0",
|
||||
"@expo/entity-database-adapter-knex": "^0.22.0"
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [0.22.0](https://github.com/expo/entity/compare/v0.21.0...v0.22.0) (2022-02-04)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-ip-address-field
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.21.0](https://github.com/expo/entity/compare/v0.20.0...v0.21.0) (2022-01-03)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-ip-address-field
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/entity-ip-address-field",
|
||||
"version": "0.21.0",
|
||||
"version": "0.22.0",
|
||||
"description": "IP address EntityField definitions for @expo/entity",
|
||||
"files": [
|
||||
"build",
|
||||
@@ -28,7 +28,7 @@
|
||||
"ip-address": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/entity": "^0.21.0",
|
||||
"@expo/entity": "^0.22.0",
|
||||
"@types/jsbn": "^1.2.29"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [0.22.0](https://github.com/expo/entity/compare/v0.21.0...v0.22.0) (2022-02-04)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-secondary-cache-redis
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.21.0](https://github.com/expo/entity/compare/v0.20.0...v0.21.0) (2022-01-03)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity-secondary-cache-redis
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/entity-secondary-cache-redis",
|
||||
"version": "0.21.0",
|
||||
"version": "0.22.0",
|
||||
"description": "Redis secondary cache for @expo/entity",
|
||||
"files": [
|
||||
"build",
|
||||
@@ -34,8 +34,8 @@
|
||||
"ioredis": "^4.17.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/entity": "^0.21.0",
|
||||
"@expo/entity-cache-adapter-redis": "^0.21.0",
|
||||
"@expo/entity": "^0.22.0",
|
||||
"@expo/entity-cache-adapter-redis": "^0.22.0",
|
||||
"nullthrows": "^1.1.1"
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,9 @@ import {
|
||||
EntityConfiguration,
|
||||
filterMap,
|
||||
ISecondaryEntityCache,
|
||||
transformCacheObjectToFields,
|
||||
transformFieldsToCacheObject,
|
||||
zipToMap,
|
||||
} from '@expo/entity';
|
||||
import {
|
||||
GenericRedisCacheContext,
|
||||
GenericRedisCacher,
|
||||
redisTransformerMap,
|
||||
} from '@expo/entity-cache-adapter-redis';
|
||||
import { GenericRedisCacheContext, GenericRedisCacher } from '@expo/entity-cache-adapter-redis';
|
||||
import invariant from 'invariant';
|
||||
|
||||
/**
|
||||
@@ -22,14 +16,14 @@ import invariant from 'invariant';
|
||||
export default class RedisSecondaryEntityCache<TFields, TLoadParams>
|
||||
implements ISecondaryEntityCache<TFields, TLoadParams>
|
||||
{
|
||||
private readonly genericRedisCacher: GenericRedisCacher;
|
||||
private readonly genericRedisCacher: GenericRedisCacher<TFields>;
|
||||
|
||||
constructor(
|
||||
private readonly entityConfiguration: EntityConfiguration<TFields>,
|
||||
entityConfiguration: EntityConfiguration<TFields>,
|
||||
genericRedisCacheContext: GenericRedisCacheContext,
|
||||
private readonly constructRedisKey: (params: Readonly<TLoadParams>) => string
|
||||
) {
|
||||
this.genericRedisCacher = new GenericRedisCacher(genericRedisCacheContext);
|
||||
this.genericRedisCacher = new GenericRedisCacher(genericRedisCacheContext, entityConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,14 +68,7 @@ export default class RedisSecondaryEntityCache<TFields, TLoadParams>
|
||||
if (cacheLoadResult.status === CacheStatus.HIT) {
|
||||
const loadParams = redisKeyToLoadParamsMap.get(redisKey);
|
||||
invariant(loadParams !== undefined, 'load params should be in redis key map');
|
||||
results.set(
|
||||
loadParams,
|
||||
transformCacheObjectToFields(
|
||||
this.entityConfiguration,
|
||||
redisTransformerMap,
|
||||
cacheLoadResult.item
|
||||
)
|
||||
);
|
||||
results.set(loadParams, cacheLoadResult.item);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -103,13 +90,10 @@ export default class RedisSecondaryEntityCache<TFields, TLoadParams>
|
||||
results.set(fetchMiss, null);
|
||||
}
|
||||
|
||||
const objectsToCache: Map<string, object> = new Map();
|
||||
const objectsToCache: Map<string, Readonly<TFields>> = new Map();
|
||||
for (const [loadParams, object] of fetchResults.entries()) {
|
||||
if (object) {
|
||||
objectsToCache.set(
|
||||
this.constructRedisKey(loadParams),
|
||||
transformFieldsToCacheObject(this.entityConfiguration, redisTransformerMap, object)
|
||||
);
|
||||
objectsToCache.set(this.constructRedisKey(loadParams), object);
|
||||
results.set(loadParams, object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [0.22.0](https://github.com/expo/entity/compare/v0.21.0...v0.22.0) (2022-02-04)
|
||||
|
||||
**Note:** Version bump only for package @expo/entity
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.21.0](https://github.com/expo/entity/compare/v0.20.0...v0.21.0) (2022-01-03)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/entity",
|
||||
"version": "0.21.0",
|
||||
"version": "0.22.0",
|
||||
"description": "A privacy-first data model",
|
||||
"files": [
|
||||
"build",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import EntityConfiguration from './EntityConfiguration';
|
||||
import { FieldTransformerMap } from './internal/EntityFieldTransformationUtils';
|
||||
import { CacheLoadResult } from './internal/ReadThroughEntityCache';
|
||||
|
||||
/**
|
||||
@@ -9,13 +8,6 @@ import { CacheLoadResult } from './internal/ReadThroughEntityCache';
|
||||
export default abstract class EntityCacheAdapter<TFields> {
|
||||
constructor(protected readonly entityConfiguration: EntityConfiguration<TFields>) {}
|
||||
|
||||
/**
|
||||
* Transformer definitions for field types. Used to modify values as they are read from or written to
|
||||
* the cache. Override in concrete subclasses to change transformation behavior.
|
||||
* If a field type is not present in the map, then fields of that type will not be transformed.
|
||||
*/
|
||||
public abstract getFieldTransformerMap(): FieldTransformerMap;
|
||||
|
||||
/**
|
||||
* Load many objects from cache.
|
||||
* @param fieldName - object field being queried
|
||||
@@ -25,7 +17,7 @@ export default abstract class EntityCacheAdapter<TFields> {
|
||||
public abstract loadManyAsync<N extends keyof TFields>(
|
||||
fieldName: N,
|
||||
fieldValues: readonly NonNullable<TFields[N]>[]
|
||||
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult>>;
|
||||
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>>;
|
||||
|
||||
/**
|
||||
* Cache many objects fetched from the DB.
|
||||
@@ -34,7 +26,7 @@ export default abstract class EntityCacheAdapter<TFields> {
|
||||
*/
|
||||
public abstract cacheManyAsync<N extends keyof TFields>(
|
||||
fieldName: N,
|
||||
objectMap: ReadonlyMap<NonNullable<TFields[N]>, object>
|
||||
objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,11 +3,6 @@ import invariant from 'invariant';
|
||||
import EntityCacheAdapter from '../EntityCacheAdapter';
|
||||
import EntityConfiguration from '../EntityConfiguration';
|
||||
import { filterMap } from '../utils/collections/maps';
|
||||
import {
|
||||
FieldTransformerMap,
|
||||
transformCacheObjectToFields,
|
||||
transformFieldsToCacheObject,
|
||||
} from './EntityFieldTransformationUtils';
|
||||
|
||||
export enum CacheStatus {
|
||||
HIT,
|
||||
@@ -15,10 +10,10 @@ export enum CacheStatus {
|
||||
NEGATIVE,
|
||||
}
|
||||
|
||||
export type CacheLoadResult =
|
||||
export type CacheLoadResult<TFields> =
|
||||
| {
|
||||
status: CacheStatus.HIT;
|
||||
item: Readonly<object>;
|
||||
item: Readonly<TFields>;
|
||||
}
|
||||
| {
|
||||
status: CacheStatus.MISS;
|
||||
@@ -32,14 +27,10 @@ export type CacheLoadResult =
|
||||
* {@link EntityCacheAdapter} within the {@link EntityDataManager}.
|
||||
*/
|
||||
export default class ReadThroughEntityCache<TFields> {
|
||||
private readonly fieldTransformerMap: FieldTransformerMap;
|
||||
|
||||
constructor(
|
||||
private readonly entityConfiguration: EntityConfiguration<TFields>,
|
||||
private readonly entityCacheAdapter: EntityCacheAdapter<TFields>
|
||||
) {
|
||||
this.fieldTransformerMap = entityCacheAdapter.getFieldTransformerMap();
|
||||
}
|
||||
) {}
|
||||
|
||||
private isFieldCacheable<N extends keyof TFields>(fieldName: N): boolean {
|
||||
return this.entityConfiguration.cacheableKeys.has(fieldName);
|
||||
@@ -91,13 +82,7 @@ export default class ReadThroughEntityCache<TFields> {
|
||||
const results: Map<NonNullable<TFields[N]>, readonly Readonly<TFields>[]> = new Map();
|
||||
cacheLoadResults.forEach((cacheLoadResult, fieldValue) => {
|
||||
if (cacheLoadResult.status === CacheStatus.HIT) {
|
||||
results.set(fieldValue, [
|
||||
transformCacheObjectToFields(
|
||||
this.entityConfiguration,
|
||||
this.fieldTransformerMap,
|
||||
cacheLoadResult.item
|
||||
),
|
||||
]);
|
||||
results.set(fieldValue, [cacheLoadResult.item]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -110,7 +95,7 @@ export default class ReadThroughEntityCache<TFields> {
|
||||
return !objectsFromFulfillerForFv || objectsFromFulfillerForFv.length === 0;
|
||||
});
|
||||
|
||||
const objectsToCache: Map<NonNullable<TFields[N]>, object> = new Map();
|
||||
const objectsToCache: Map<NonNullable<TFields[N]>, Readonly<TFields>> = new Map();
|
||||
for (const [fieldValue, objects] of dbFetchResults.entries()) {
|
||||
if (objects.length > 1) {
|
||||
// multiple objects received for what was supposed to be a unique query, don't add to return map nor cache
|
||||
@@ -123,14 +108,7 @@ export default class ReadThroughEntityCache<TFields> {
|
||||
}
|
||||
const uniqueObject = objects[0];
|
||||
if (uniqueObject) {
|
||||
objectsToCache.set(
|
||||
fieldValue,
|
||||
transformFieldsToCacheObject(
|
||||
this.entityConfiguration,
|
||||
this.fieldTransformerMap,
|
||||
uniqueObject
|
||||
)
|
||||
);
|
||||
objectsToCache.set(fieldValue, uniqueObject);
|
||||
results.set(fieldValue, [uniqueObject]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ describe(ReadThroughEntityCache, () => {
|
||||
describe('readManyThroughAsync', () => {
|
||||
it('fetches from DB upon cache miss and caches the result', async () => {
|
||||
const cacheAdapterMock = mock<EntityCacheAdapter<BlahFields>>();
|
||||
when(cacheAdapterMock.getFieldTransformerMap()).thenReturn(new Map());
|
||||
const cacheAdapter = instance(cacheAdapterMock);
|
||||
const entityCache = new ReadThroughEntityCache(makeEntityConfiguration(true), cacheAdapter);
|
||||
const fetcher = createIdFetcher(['wat', 'who']);
|
||||
@@ -77,7 +76,6 @@ describe(ReadThroughEntityCache, () => {
|
||||
|
||||
it('does not fetch from the DB or cache results when all cache fetches are hits', async () => {
|
||||
const cacheAdapterMock = mock<EntityCacheAdapter<BlahFields>>();
|
||||
when(cacheAdapterMock.getFieldTransformerMap()).thenReturn(new Map());
|
||||
const cacheAdapter = instance(cacheAdapterMock);
|
||||
const entityCache = new ReadThroughEntityCache(makeEntityConfiguration(true), cacheAdapter);
|
||||
const fetcher = createIdFetcher(['wat', 'who']);
|
||||
@@ -114,7 +112,6 @@ describe(ReadThroughEntityCache, () => {
|
||||
|
||||
it('negatively caches db misses', async () => {
|
||||
const cacheAdapterMock = mock<EntityCacheAdapter<BlahFields>>();
|
||||
when(cacheAdapterMock.getFieldTransformerMap()).thenReturn(new Map());
|
||||
const cacheAdapter = instance(cacheAdapterMock);
|
||||
const entityCache = new ReadThroughEntityCache(makeEntityConfiguration(true), cacheAdapter);
|
||||
|
||||
@@ -135,7 +132,6 @@ describe(ReadThroughEntityCache, () => {
|
||||
|
||||
it('does not return or fetch negatively cached results from DB', async () => {
|
||||
const cacheAdapterMock = mock<EntityCacheAdapter<BlahFields>>();
|
||||
when(cacheAdapterMock.getFieldTransformerMap()).thenReturn(new Map());
|
||||
const cacheAdapter = instance(cacheAdapterMock);
|
||||
const entityCache = new ReadThroughEntityCache(makeEntityConfiguration(true), cacheAdapter);
|
||||
const fetcher = createIdFetcher([]);
|
||||
@@ -153,7 +149,6 @@ describe(ReadThroughEntityCache, () => {
|
||||
|
||||
it('does a mix and match of hit, miss, and negative', async () => {
|
||||
const cacheAdapterMock = mock<EntityCacheAdapter<BlahFields>>();
|
||||
when(cacheAdapterMock.getFieldTransformerMap()).thenReturn(new Map());
|
||||
const cacheAdapter = instance(cacheAdapterMock);
|
||||
const entityCache = new ReadThroughEntityCache(makeEntityConfiguration(true), cacheAdapter);
|
||||
const fetcher = createIdFetcher(['wat', 'who', 'why']);
|
||||
@@ -189,7 +184,6 @@ describe(ReadThroughEntityCache, () => {
|
||||
|
||||
it('does not call into cache for field that is not cacheable', async () => {
|
||||
const cacheAdapterMock = mock<EntityCacheAdapter<BlahFields>>();
|
||||
when(cacheAdapterMock.getFieldTransformerMap()).thenReturn(new Map());
|
||||
const cacheAdapter = instance(cacheAdapterMock);
|
||||
const entityCache = new ReadThroughEntityCache(makeEntityConfiguration(false), cacheAdapter);
|
||||
const fetcher = createIdFetcher(['wat']);
|
||||
@@ -197,44 +191,6 @@ describe(ReadThroughEntityCache, () => {
|
||||
verify(cacheAdapterMock.loadManyAsync('id', anything())).never();
|
||||
expect(result).toEqual(new Map([['wat', [{ id: 'wat' }]]]));
|
||||
});
|
||||
|
||||
it('transforms fields for cache storage', async () => {
|
||||
const cacheAdapterMock = mock<EntityCacheAdapter<BlahFields>>();
|
||||
when(cacheAdapterMock.getFieldTransformerMap()).thenReturn(
|
||||
new Map([
|
||||
[
|
||||
UUIDField.name,
|
||||
{
|
||||
read: (val) => val.split('-')[0],
|
||||
write: (val) => `${val}-in-cache`,
|
||||
},
|
||||
],
|
||||
])
|
||||
);
|
||||
const cacheAdapter = instance(cacheAdapterMock);
|
||||
const entityCache = new ReadThroughEntityCache(makeEntityConfiguration(true), cacheAdapter);
|
||||
const fetcher = createIdFetcher(['wat', 'who']);
|
||||
|
||||
when(cacheAdapterMock.loadManyAsync('id', deepEqual(['wat', 'who']))).thenResolve(
|
||||
new Map([
|
||||
['wat', { status: CacheStatus.MISS }],
|
||||
['who', { status: CacheStatus.HIT, item: { id: 'who-in-cache' } }],
|
||||
])
|
||||
);
|
||||
|
||||
const result = await entityCache.readManyThroughAsync('id', ['wat', 'who'], fetcher);
|
||||
|
||||
verify(cacheAdapterMock.loadManyAsync('id', deepEqual(['wat', 'who']))).once();
|
||||
verify(
|
||||
cacheAdapterMock.cacheManyAsync('id', deepEqual(new Map([['wat', { id: 'wat-in-cache' }]])))
|
||||
).once();
|
||||
expect(result).toEqual(
|
||||
new Map([
|
||||
['wat', [{ id: 'wat' }]],
|
||||
['who', [{ id: 'who' }]],
|
||||
])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalidateManyAsync', () => {
|
||||
|
||||
@@ -3,7 +3,6 @@ import invariant from 'invariant';
|
||||
import EntityCacheAdapter from '../../EntityCacheAdapter';
|
||||
import EntityConfiguration from '../../EntityConfiguration';
|
||||
import IEntityCacheAdapterProvider from '../../IEntityCacheAdapterProvider';
|
||||
import { FieldTransformerMap } from '../../internal/EntityFieldTransformationUtils';
|
||||
import { CacheStatus, CacheLoadResult } from '../../internal/ReadThroughEntityCache';
|
||||
|
||||
export class NoCacheStubCacheAdapterProvider implements IEntityCacheAdapterProvider {
|
||||
@@ -15,15 +14,11 @@ export class NoCacheStubCacheAdapterProvider implements IEntityCacheAdapterProvi
|
||||
}
|
||||
|
||||
export class NoCacheStubCacheAdapter<TFields> extends EntityCacheAdapter<TFields> {
|
||||
public getFieldTransformerMap(): FieldTransformerMap {
|
||||
return new Map();
|
||||
}
|
||||
|
||||
public async loadManyAsync<N extends keyof TFields>(
|
||||
_fieldName: N,
|
||||
fieldValues: readonly NonNullable<TFields[N]>[]
|
||||
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult>> {
|
||||
return fieldValues.reduce((acc: Map<NonNullable<TFields[N]>, CacheLoadResult>, v) => {
|
||||
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>> {
|
||||
return fieldValues.reduce((acc: Map<NonNullable<TFields[N]>, CacheLoadResult<TFields>>, v) => {
|
||||
acc.set(v, {
|
||||
status: CacheStatus.MISS,
|
||||
});
|
||||
@@ -33,7 +28,7 @@ export class NoCacheStubCacheAdapter<TFields> extends EntityCacheAdapter<TFields
|
||||
|
||||
public async cacheManyAsync<N extends keyof TFields>(
|
||||
_fieldName: N,
|
||||
_objectMap: ReadonlyMap<NonNullable<TFields[N]>, object>
|
||||
_objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>
|
||||
): Promise<void> {}
|
||||
|
||||
public async cacheDBMissesAsync<N extends keyof TFields>(
|
||||
@@ -53,27 +48,26 @@ export class InMemoryFullCacheStubCacheAdapterProvider implements IEntityCacheAd
|
||||
getCacheAdapter<TFields>(
|
||||
entityConfiguration: EntityConfiguration<TFields>
|
||||
): EntityCacheAdapter<TFields> {
|
||||
return new InMemoryFullCacheStubCacheAdapter(entityConfiguration, this.cache);
|
||||
return new InMemoryFullCacheStubCacheAdapter(
|
||||
entityConfiguration,
|
||||
this.cache as Map<string, Readonly<TFields>>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class InMemoryFullCacheStubCacheAdapter<TFields> extends EntityCacheAdapter<TFields> {
|
||||
constructor(
|
||||
entityConfiguration: EntityConfiguration<TFields>,
|
||||
readonly cache: Map<string, Readonly<object>>
|
||||
readonly cache: Map<string, Readonly<TFields>>
|
||||
) {
|
||||
super(entityConfiguration);
|
||||
}
|
||||
|
||||
public getFieldTransformerMap(): FieldTransformerMap {
|
||||
return new Map();
|
||||
}
|
||||
|
||||
public async loadManyAsync<N extends keyof TFields>(
|
||||
fieldName: N,
|
||||
fieldValues: readonly NonNullable<TFields[N]>[]
|
||||
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult>> {
|
||||
const results = new Map<NonNullable<TFields[N]>, CacheLoadResult>();
|
||||
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>> {
|
||||
const results = new Map<NonNullable<TFields[N]>, CacheLoadResult<TFields>>();
|
||||
fieldValues.forEach((fieldValue) => {
|
||||
const cacheKey = this.createCacheKey(fieldName, fieldValue);
|
||||
if (!this.cache.has(cacheKey)) {
|
||||
@@ -94,7 +88,7 @@ export class InMemoryFullCacheStubCacheAdapter<TFields> extends EntityCacheAdapt
|
||||
|
||||
public async cacheManyAsync<N extends keyof TFields>(
|
||||
fieldName: N,
|
||||
objectMap: ReadonlyMap<NonNullable<TFields[N]>, object>
|
||||
objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>
|
||||
): Promise<void> {
|
||||
objectMap.forEach((obj, fieldValue) => {
|
||||
const cacheKey = this.createCacheKey(fieldName, fieldValue);
|
||||
|
||||
@@ -508,27 +508,27 @@
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@expo/entity-cache-adapter-redis@file:packages/entity-cache-adapter-redis":
|
||||
version "0.18.0"
|
||||
version "0.21.0"
|
||||
dependencies:
|
||||
ioredis "^4.27.3"
|
||||
|
||||
"@expo/entity-database-adapter-knex@file:packages/entity-database-adapter-knex":
|
||||
version "0.18.0"
|
||||
version "0.21.0"
|
||||
dependencies:
|
||||
knex "^0.95.6"
|
||||
knex "^1.0.2"
|
||||
|
||||
"@expo/entity-ip-address-field@file:packages/entity-ip-address-field":
|
||||
version "0.18.0"
|
||||
version "0.21.0"
|
||||
dependencies:
|
||||
ip-address "^8.1.0"
|
||||
|
||||
"@expo/entity-secondary-cache-redis@file:packages/entity-secondary-cache-redis":
|
||||
version "0.18.0"
|
||||
version "0.21.0"
|
||||
dependencies:
|
||||
ioredis "^4.17.3"
|
||||
|
||||
"@expo/entity@file:packages/entity":
|
||||
version "0.18.0"
|
||||
version "0.21.0"
|
||||
dependencies:
|
||||
"@expo/results" "^1.0.0"
|
||||
dataloader "^2.0.0"
|
||||
@@ -3270,10 +3270,10 @@ color-name@~1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
colorette@1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
|
||||
integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
|
||||
colorette@2.0.16:
|
||||
version "2.0.16"
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da"
|
||||
integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==
|
||||
|
||||
columnify@^1.5.4:
|
||||
version "1.5.4"
|
||||
@@ -3295,10 +3295,10 @@ commander@^2.20.3, commander@~2.20.3:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
commander@^7.1.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
|
||||
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
|
||||
commander@^8.3.0:
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
|
||||
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
|
||||
|
||||
compare-func@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -3582,13 +3582,20 @@ dateformat@~1.0.4-1.2.3:
|
||||
get-stdin "^4.0.1"
|
||||
meow "^3.3.0"
|
||||
|
||||
debug@4, [email protected], debug@^4.3.1:
|
||||
debug@4, debug@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
|
||||
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
[email protected]:
|
||||
version "4.3.3"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
|
||||
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
@@ -4694,10 +4701,10 @@ get-value@^2.0.3, get-value@^2.0.6:
|
||||
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
|
||||
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
|
||||
|
||||
getopts@2.2.5:
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b"
|
||||
integrity sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==
|
||||
getopts@2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4"
|
||||
integrity sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
@@ -6228,23 +6235,23 @@ kleur@^3.0.3:
|
||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
||||
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
||||
|
||||
knex@^0.95.6:
|
||||
version "0.95.6"
|
||||
resolved "https://registry.yarnpkg.com/knex/-/knex-0.95.6.tgz#5fc60ffc2935567bf122925526b1b06b8dbca785"
|
||||
integrity sha512-noRcmkJl1MdicUbezrcr8OtVLcqQ/cfLIwgAx5EaxNxQOIJff88rBeyLywUScGhQNd/b78DIKKXZzLMrm6h/cw==
|
||||
knex@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/knex/-/knex-1.0.2.tgz#1b79273f39f587a631c1a5515482c203d5971781"
|
||||
integrity sha512-RuDKTylj6X/3nYomnsFV8sOdxTcehLHczOd3yrUdULE4pQR8jVlZxYt3vvIU04otJF0Cw9DCtRt05S4PN4kDpw==
|
||||
dependencies:
|
||||
colorette "1.2.1"
|
||||
commander "^7.1.0"
|
||||
debug "4.3.1"
|
||||
colorette "2.0.16"
|
||||
commander "^8.3.0"
|
||||
debug "4.3.3"
|
||||
escalade "^3.1.1"
|
||||
esm "^3.2.25"
|
||||
getopts "2.2.5"
|
||||
getopts "2.3.0"
|
||||
interpret "^2.2.0"
|
||||
lodash "^4.17.21"
|
||||
pg-connection-string "2.4.0"
|
||||
rechoir "^0.7.0"
|
||||
pg-connection-string "2.5.0"
|
||||
rechoir "^0.8.0"
|
||||
resolve-from "^5.0.0"
|
||||
tarn "^3.0.1"
|
||||
tarn "^3.0.2"
|
||||
tildify "2.0.0"
|
||||
|
||||
koa-body@^4.2.0:
|
||||
@@ -7669,12 +7676,7 @@ performance-now@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
pg-connection-string@2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.4.0.tgz#c979922eb47832999a204da5dbe1ebf2341b6a10"
|
||||
integrity sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ==
|
||||
|
||||
pg-connection-string@^2.5.0:
|
||||
pg-connection-string@2.5.0, pg-connection-string@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34"
|
||||
integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==
|
||||
@@ -8139,12 +8141,12 @@ rechoir@^0.6.2:
|
||||
dependencies:
|
||||
resolve "^1.1.6"
|
||||
|
||||
rechoir@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca"
|
||||
integrity sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==
|
||||
rechoir@^0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22"
|
||||
integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==
|
||||
dependencies:
|
||||
resolve "^1.9.0"
|
||||
resolve "^1.20.0"
|
||||
|
||||
redent@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -8316,7 +8318,7 @@ resolve@^1.18.1, resolve@~1.19.0:
|
||||
is-core-module "^2.1.0"
|
||||
path-parse "^1.0.6"
|
||||
|
||||
resolve@^1.20.0, resolve@^1.9.0:
|
||||
resolve@^1.20.0:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
||||
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
||||
@@ -9108,10 +9110,10 @@ tar@^6.0.2, tar@^6.1.0:
|
||||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
tarn@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.1.tgz#ebac2c6dbc6977d34d4526e0a7814200386a8aec"
|
||||
integrity sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw==
|
||||
tarn@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693"
|
||||
integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==
|
||||
|
||||
temp-dir@^1.0.0:
|
||||
version "1.0.0"
|
||||
|
||||
Reference in new issue
Block a user