Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:

strategy:
matrix:
node-version: [8.x, 10.x, 12.x]
node-version: [8.x, 10.x, 12.x, 14.x]

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
Expand Down
2,883 changes: 1,604 additions & 1,279 deletions package-lock.json

Large diffs are not rendered by default.

33 changes: 16 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,26 @@
"devDependencies": {
"@semantic-release/changelog": "^3.0.4",
"@semantic-release/git": "^7.0.16",
"@types/ioredis": "^4.14.9",
"@types/jest": "^25.1.4",
"@types/lodash": "^4.14.149",
"@types/ioredis": "^4.16.7",
"@types/jest": "^25.2.3",
"@types/lodash": "^4.14.157",
"@types/memcached": "^2.2.6",
"@types/node": "^8",
"@types/uuid": "^7.0.0",
"@typescript-eslint/eslint-plugin": "^2.23.0",
"@typescript-eslint/parser": "^2.23.0",
"coveralls": "^3.0.4",
"cz-conventional-changelog": "^3.1.0",
"@types/node": "^8.10.61",
"@types/uuid": "^8.0.0",
"@typescript-eslint/eslint-plugin": "^3.4.0",
"@typescript-eslint/parser": "^3.4.0",
"coveralls": "^3.1.0",
"cz-conventional-changelog": "^3.2.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"ioredis": "^4.16.0",
"jest": "^25.1.0",
"eslint-config-prettier": "^6.11.0",
"ioredis": "^4.17.3",
"jest": "^25.5.4",
"memcached": "^2.2.2",
"prettier": "1.19.1",
"prettier": "^1.19.1",
"semantic-release": "^15.13.24",
"ts-jest": "^25.2.1",
"typedoc": "^0.16.11",
"typescript": "^3.8.3",
"uuid": "^7.0.2"
"ts-jest": "^25.5.1",
"typescript": "^3.9.5",
"uuid": "^8.2.0"
},
"config": {
"commitizen": {
Expand Down
12 changes: 4 additions & 8 deletions src/Cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ export type CacheOptions = (CacheWithCustomStorageOptions | CacheWithBaseStorage
hashKeys?: boolean;
};

export const isCustomStorageOptions = (options: object): options is CacheWithCustomStorageOptions =>
export const isCustomStorageOptions = (options: unknown): options is CacheWithCustomStorageOptions =>
Object.prototype.hasOwnProperty.call(options, "storage");

export const isBaseStorageOptions = (options: object): options is CacheWithBaseStorageOptions =>
export const isBaseStorageOptions = (options: unknown): options is CacheWithBaseStorageOptions =>
Object.prototype.hasOwnProperty.call(options, "adapter");

export interface ManagerSelectorOptions {
Expand Down Expand Up @@ -67,18 +67,14 @@ class Cache {
constructor(options: CacheOptions) {
if (isCustomStorageOptions(options)) {
this.storage = options.storage;
}

if (isBaseStorageOptions(options)) {
} else if (isBaseStorageOptions(options)) {
this.storage = new BaseStorage({
adapter: options.adapter,
tagsAdapter: options.tagsAdapter,
prefix: options.prefix,
hashKeys: options.hashKeys,
});
}

if (!this.storage) {
} else {
throw new Error("Either custom storage or storage adapter must be passed in options.");
}

Expand Down
11 changes: 11 additions & 0 deletions src/adapters/RedisStorageAdapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ describe("Redis adapter", () => {
expect(mock.set).toBeCalledWith("some_lock", "", "PX", DEFAULT_LOCK_EXPIRES, "NX");
});

it("acquireLock use passed lockExpireTimeout", async () => {
mock.set = jest.fn().mockImplementation(() => "OK");

const lockExpireTimeout = 12345;
const lockResult = await adapter.acquireLock("some", lockExpireTimeout);

expect(lockResult).toEqual(true);
expect(mock.set).toBeCalledTimes(1);
expect(mock.set).toBeCalledWith("some_lock", "", "PX", lockExpireTimeout, "NX");
});

it("releaseLock delete lock record with appropriate key, and returns true on success", async () => {
mock.del = jest.fn().mockImplementation(() => 1);

Expand Down
3 changes: 1 addition & 2 deletions src/adapters/RedisStorageAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { EventEmitter } from "events";
import _, { partial } from "lodash";
import { ConnectionStatus } from "../ConnectionStatus";
import { StorageAdapter } from "../StorageAdapter";
import { withTimeout } from "../with-timeout";
Expand Down Expand Up @@ -53,7 +52,7 @@ export class RedisStorageAdapter implements StorageAdapter {
this.redisInstance.on("reconnecting", () => this.setConnectionStatus(ConnectionStatus.CONNECTING));
this.redisInstance.on("end", () => this.setConnectionStatus(ConnectionStatus.DISCONNECTED));

this.withTimeout = partial(withTimeout, _, this.options.operationTimeout);
this.withTimeout = <T>(promise: Promise<T>) => withTimeout(promise, this.options.operationTimeout);
}

/**
Expand Down
32 changes: 16 additions & 16 deletions src/adapters/TestStorageAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { ConnectionStatus } from "../ConnectionStatus";
import { StorageAdapter, StorageAdapterOptions } from "../StorageAdapter";
import { StorageAdapter } from "../StorageAdapter";

class TestStorageAdapter implements StorageAdapter {
options: StorageAdapterOptions;
testInterface: any;
internalStorage: Record<string, string>;
isConnected: boolean;
internalStorage: any;

constructor(testInstance: any, isConnected = true) {
this.testInterface = testInstance;
this.testInterface.internalStorage = {};
constructor(storage: Record<string, string> = {}, isConnected = true) {
this.internalStorage = storage;
this.isConnected = isConnected;
}

Expand All @@ -30,22 +26,22 @@ class TestStorageAdapter implements StorageAdapter {

async set(key: string, value: string): Promise<boolean> {
this.checkConnection();
this.testInterface.internalStorage[key] = value;
this.internalStorage[key] = value;

return true;
}

async get(key: string): Promise<string> {
this.checkConnection();

return this.testInterface.internalStorage[key];
return this.internalStorage[key];
}

async del(key: string): Promise<boolean> {
this.checkConnection();

if (this.testInterface.internalStorage[key]) {
delete this.testInterface.internalStorage[key];
if (this.internalStorage[key]) {
delete this.internalStorage[key];

return true;
}
Expand All @@ -68,20 +64,24 @@ class TestStorageAdapter implements StorageAdapter {
async isLockExists(key: string): Promise<boolean> {
this.checkConnection();

return !!this.testInterface.internalStorage[`${key}_lock`];
return !!this.internalStorage[`${key}_lock`];
}

async mset(values: Map<string, any>): Promise<void> {
async mset(values: Map<string, string>): Promise<void> {
this.checkConnection();
values.forEach((value, key) => {
this.testInterface.internalStorage[key] = value;
this.internalStorage[key] = value;
});
}

async mget(keys: string[]): Promise<(string | null)[]> {
this.checkConnection();

return keys.map(key => this.testInterface.internalStorage[key] || null);
return keys.map(key => this.internalStorage[key] || null);
}

setOptions(): void {
return undefined;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { RunExecutorLockedKeyRetrieveStrategy } from "./RunExecutorLockedKeyRetrieveStrategy";

let instance;
let instance: RunExecutorLockedKeyRetrieveStrategy;

describe("RunExecutorLockedKeyRetrieveStrategy", () => {
beforeEach(() => {
Expand All @@ -14,6 +14,6 @@ describe("RunExecutorLockedKeyRetrieveStrategy", () => {
it("get calls context executor", async () => {
const executorMock = jest.fn().mockResolvedValue(true);

await expect(instance.get({ executor: executorMock })).resolves.toEqual(true);
await expect(instance.get({ executor: executorMock } as any)).resolves.toEqual(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
WaitForResultLockedKeyRetrieveStrategy,
} from "./WaitForResultLockedKeyRetrieveStrategy";

let instance;
let instance: any;

const loggerMock: any = {
error: jest.fn(),
Expand Down
12 changes: 9 additions & 3 deletions src/managers/ReadThroughManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const logger = {
error: jest.fn(),
};
let internalStorage = {};
let storage;
let manager;
let storage: TestStorage;
let manager: ReadThroughManager;

describe("ReadThroughManager", () => {
beforeEach(() => {
Expand Down Expand Up @@ -44,7 +44,7 @@ describe("ReadThroughManager", () => {
});

it("getLockedKeyRetrieveStrategy throws if cannot get strategy", () => {
expect(() => manager.getLockedKeyRetrieveStrategy("unknown")).toThrow();
expect(() => (manager as any).getLockedKeyRetrieveStrategy("unknown")).toThrow();
});

it("get returns result from executor if key lock throws error", async () => {
Expand Down Expand Up @@ -149,4 +149,10 @@ describe("ReadThroughManager", () => {

await expect(testManager.get("test", async () => ({ test: 123 }))).resolves.toEqual({ test: 123 });
});

it("del calls storage.del", async () => {
await manager.del("test");

expect(storage.del).toBeCalledWith("test");
});
});
18 changes: 9 additions & 9 deletions src/managers/RefreshAheadManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const logger = {
error: jest.fn(),
};
let internalStorage = {};
let storage;
let manager;
let storage: TestStorage;
let manager: RefreshAheadManager;

describe("RefreshAheadManager", () => {
beforeEach(() => {
Expand Down Expand Up @@ -72,7 +72,7 @@ describe("RefreshAheadManager", () => {
});

it("getLockedKeyRetrieveStrategy throws if cannot get strategy", () => {
expect(() => manager.getLockedKeyRetrieveStrategy("unknown")).toThrow();
expect(() => (manager as any).getLockedKeyRetrieveStrategy("unknown")).toThrow();
});

it("get returns result from executor if key lock throws error", async () => {
Expand Down Expand Up @@ -137,9 +137,9 @@ describe("RefreshAheadManager", () => {
const DATE = 1550082589000;
const DATE_ADVANCED = 1550082589405;
const realNow = Date.now;
const instanceRefresh = manager.refresh;
const instanceRefresh = (manager as any).refresh;

manager.refresh = async (...args): Promise<any> => {
(manager as any).refresh = async (...args: any[]): Promise<any> => {
await instanceRefresh.call(manager, ...args);
expect(await storage.get("test")).toMatchObject({ key: "test", value: '"234"' });
resolve();
Expand Down Expand Up @@ -169,9 +169,9 @@ describe("RefreshAheadManager", () => {
const DATE = 1550082589000;
const DATE_ADVANCED = 1550082589405;
const realNow = Date.now;
const instanceRefresh = manager.refresh;
const instanceRefresh = (manager as any).refresh;

manager.refresh = async (...args): Promise<any> => {
(manager as any).refresh = async (...args: any[]): Promise<any> => {
await instanceRefresh.call(manager, ...args);
resolve();
};
Expand Down Expand Up @@ -206,7 +206,7 @@ describe("RefreshAheadManager", () => {
const realNow = Date.now;
const realCatch = Promise.prototype.catch;

manager.refresh = jest.fn().mockImplementation(async () => {
(manager as any).refresh = jest.fn().mockImplementation(async () => {
throw new Error("Operation timeout");
});
Promise.prototype.catch = function(...args: any[]): any {
Expand Down Expand Up @@ -268,6 +268,6 @@ describe("RefreshAheadManager", () => {
});

it("isRecordExpireSoon returns false if record is null", () => {
expect(manager.isRecordExpireSoon(null)).toEqual(false);
expect((manager as any).isRecordExpireSoon(null)).toEqual(false);
});
});
6 changes: 3 additions & 3 deletions src/managers/WriteThroughManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const logger = {
error: jest.fn(),
};
let internalStorage = {};
let storage;
let manager;
let storage: TestStorage;
let manager: WriteThroughManager;

describe("WriteThroughManager", () => {
beforeEach(() => {
Expand Down Expand Up @@ -44,7 +44,7 @@ describe("WriteThroughManager", () => {
});

it("getLockedKeyRetrieveStrategy throws if cannot get strategy", () => {
expect(() => manager.getLockedKeyRetrieveStrategy("unknown")).toThrow();
expect(() => (manager as any).getLockedKeyRetrieveStrategy("unknown")).toThrow();
});

it("get returns result from executor if key lock throws error", async () => {
Expand Down
Loading