Skip to content

Commit

Permalink
feat: initial upload
Browse files Browse the repository at this point in the history
  • Loading branch information
negezor committed Sep 3, 2020
1 parent 15177d7 commit 4ad4d15
Show file tree
Hide file tree
Showing 24 changed files with 5,306 additions and 1 deletion.
16 changes: 16 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# editorconfig.org
root = true

[*]
end_of_line = lf
indent_style = tab
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{yaml,yml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
83 changes: 83 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"env": {
"node": true
},
"extends": [
"airbnb-base",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json",
"sourceType": "module"
},
"plugins": [
"import",
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/no-unused-expressions": ["error"],
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "interface",
"format": ["PascalCase"],
"prefix": ["I"]
},
{
"selector": "property",
"format": ["camelCase", "UPPER_CASE", "PascalCase"]
}
],
"@typescript-eslint/ban-ts-comment": ["error", {
"ts-ignore": true,
"ts-expect-error": false
}],
"@typescript-eslint/ban-types": ["error", {
"types": {
"{}": false,
"object": false,
"Function": false
},
"extendDefaults": true
}],
"@typescript-eslint/indent": ["error", "tab"],
"@typescript-eslint/semi": ["error"],
"import/extensions": ["error", "ignorePackages", {
"js": "never",
"ts": "never"
}],
"import/prefer-default-export": "off",
"import/no-default-export": ["error"],
"import/no-cycle": "off",
"no-restricted-syntax": ["error", "WithStatement"],
"linebreak-style": ["error", "unix"],
"comma-dangle": ["error", "never"],
"no-param-reassign": ["error", {
"props": false
}],
"no-unused-expressions": "off",
"no-dupe-class-members": "off",
"no-await-in-loop": "off",
"arrow-parens": "off",
"no-continue": "off",
"no-tabs": ["error", {
"allowIndentationTabs": true
}],
"camelcase": "off",
"indent": "off",
"semi": "off"
},
"overrides": [
{
"files": ["packages/*/test/**/*.test.ts"],
"env": {
"jest": true
}
}
]
}
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Logs
logs
*.log
npm-debug.log*

# Dependency directories
node_modules

# Build
packages/*/lib
app.ts
app.js
app.mjs

docs/.vuepress/dist
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020 Vladlen
Copyright (c) 2020 Negezor

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
7 changes: 7 additions & 0 deletions jest.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "cacher-monorepo",
"verbose": true,
"preset": "ts-jest",
"testEnvironment": "node",
"testMatch": ["<rootDir>/packages/*/test/*.test.ts"]
}
34 changes: 34 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "cacher-monorepo",
"private": true,
"workspaces": [
"packages/*"
],
"engines": {
"node": ">=14.0.0"
},
"devDependencies": {
"@types/jest": "^26.0.13",
"@types/node": "^14.6.3",
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"eslint": "^7.8.1",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-plugin-import": "^2.22.0",
"jest": "^26.4.2",
"rollup": "^2.26.9",
"rollup-plugin-typescript2": "^0.27.2",
"ts-jest": "^26.3.0",
"typescript": "^4.0.2"
},
"scripts": {
"prepare": "yarn run rollup:build && yarn run test",
"build": "yarn run rollup:build",
"watch": "yarn run rollup:watch",
"rollup:build": "NODE_ENV=production rollup -c rollup.config.js",
"rollup:watch": "yarn run rollup:build -w",
"test": "yarn run test:jest && yarn run test:eslint",
"test:jest": "jest --config jest.config.json --no-cache",
"test:eslint": "eslint --ext .ts --ignore-path .gitignore packages/*/src/**/*.ts"
}
}
2 changes: 2 additions & 0 deletions packages/cacher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# cacher
Modern implement key-value storage
37 changes: 37 additions & 0 deletions packages/cacher/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@cacher/cacher",
"version": "1.0.0",
"description": "Modern implementation of key-value storage",
"license": "MIT",
"author": {
"name": "Vladlen (Negezor)",
"email": "[email protected]"
},
"repository": {
"type": "git",
"url": "git+https://github.com/negezor/cacher.git",
"directory": "packages/cacher"
},
"homepage": "https://github.com/negezor/cacher#readme",
"bugs": "https://github.com/negezor/cacher/issues",
"keywords": [
"cache"
],
"files": [
"lib"
],
"main": "lib/index.js",
"types": "./lib/index.d.ts",
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {

},
"dependencies": {

},
"devDependencies": {

}
}
22 changes: 22 additions & 0 deletions packages/cacher/src/adapters/adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface IAdapterSetOptions {
key: string;
value: string;
ttl?: number;
}

export interface IAdapterTouchOptions {
key: string;
ttl: number;
}

export interface IAdapter {
get(keys: string[]): Promise<(string | undefined)[]>;

set(keys: IAdapterSetOptions[]): Promise<void>;

delete(keys: string[]): Promise<void>;

touch(keys: IAdapterTouchOptions[]): Promise<void>;

clear(namespace: string): Promise<void>;
}
3 changes: 3 additions & 0 deletions packages/cacher/src/adapters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './adapter';

export * from './memory';
49 changes: 49 additions & 0 deletions packages/cacher/src/adapters/memory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { IAdapter, IAdapterSetOptions } from './adapter';

export interface IMapLike<K, V> {
get(key: K): V | undefined;
set(key: K, value: V): this | undefined;
delete(key: K): boolean;
keys(): K[] | IterableIterator<K>;
}

export interface IMemoryAdapterOptions {
storage?: IMapLike<string, string>;
}

export class MemoryAdapter implements IAdapter {
protected readonly storage: IMapLike<string, string>;

public constructor({ storage = new Map() }: IMemoryAdapterOptions = {}) {
this.storage = storage;
}

public async get(keys: string[]): Promise<(string | undefined)[]> {
return keys.map(key => (
this.storage.get(key) ?? undefined
));
}

public async set(keys: IAdapterSetOptions[]): Promise<void> {
for (const { key, value } of keys) {
this.storage.set(key, value);
}
}

public async delete(keys: string[]): Promise<void> {
for (const key of keys) {
this.storage.delete(key);
}
}

// eslint-disable-next-line @typescript-eslint/no-empty-function, class-methods-use-this
public async touch(): Promise<void> {}

public async clear(namespace: string): Promise<void> {
for (const key of this.storage.keys()) {
if (key.startsWith(namespace)) {
this.storage.delete(key);
}
}
}
}
99 changes: 99 additions & 0 deletions packages/cacher/src/cacher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { IAdapter, MemoryAdapter } from './adapters';
import {
ICacherOptions,
ICacherGetOptions,
ICacherSetOptions,
ICacherTouchOptions,

Serializer,
Deserializer,

AllowArray
} from './types';
import { arraify } from './helpers';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export class Cacher<V = any> {
protected adapter: IAdapter;

protected namespace: string;

protected serializer: Serializer<V>;

protected deserializer: Deserializer<V>;

public constructor({
adapter = new MemoryAdapter(),

namespace,

serializer = JSON.stringify,
deserializer = JSON.parse
}: ICacherOptions<V>) {
this.adapter = adapter;

this.namespace = namespace;

this.serializer = serializer;
this.deserializer = deserializer;
}

public async get<K extends string = string, A extends string = string>(
rawKeys: AllowArray<ICacherGetOptions<K, A>>
): Promise<Record<K, V | undefined> & Record<A, V | undefined>> {
const keys = arraify(rawKeys);

const rawValues = await this.adapter.get(
keys.map(item => this.getNamespaceKey(item.key))
);

return Object.fromEntries(
rawValues.map((rawValue, i) => {
const key = keys[i].alias ?? keys[i].key;

const value = rawValue !== undefined
? this.deserializer(rawValue)
: undefined;

return [key, value];
})
) as unknown as Record<K, V | undefined> & Record<A, V | undefined>;
}

public set(
rawKeys: AllowArray<ICacherSetOptions<V>>
): Promise<void> {
const keys = arraify(rawKeys);

return this.adapter.set(keys.map(item => ({
key: this.getNamespaceKey(item.key),
value: this.serializer(item.value),
ttl: item.ttl
})));
}

public async delete(rawKeys: AllowArray<string>): Promise<void> {
const keys = arraify(rawKeys);

return this.adapter.delete(keys.map(key => (
this.getNamespaceKey(key)
)));
}

public async touch(rawKeys: ICacherTouchOptions[]): Promise<void> {
const keys = arraify(rawKeys);

return this.adapter.touch(keys.map(item => ({
key: this.getNamespaceKey(item.key),
ttl: item.ttl
})));
}

public clear(): Promise<void> {
return this.adapter.clear(this.namespace);
}

protected getNamespaceKey(key: string): string {
return `${this.namespace}:${key}`;
}
}
5 changes: 5 additions & 0 deletions packages/cacher/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const arraify = <T>(value: T | T[]): T[] => (
Array.isArray(value)
? value
: [value]
);
5 changes: 5 additions & 0 deletions packages/cacher/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from './cacher';

export * from './adapters';

export * from './types';
Loading

0 comments on commit 4ad4d15

Please sign in to comment.