diff --git a/install.mjs b/install.mjs index e48e86dc..c2c899ee 100644 --- a/install.mjs +++ b/install.mjs @@ -4,7 +4,7 @@ import "ioredis"; import {default as inquirer} from "inquirer"; import {isModuleAvailable} from "./modules/utils.mjs"; -const moduleList = ["mysql2", "ioredis", "inquirer","express","redis-json"]; +const moduleList = ["mysql2", "ioredis", "inquirer","express"]; function install(){ console.log("******************************"); diff --git a/modules/init.mjs b/modules/init.mjs index 54a6ad7c..10b34564 100644 --- a/modules/init.mjs +++ b/modules/init.mjs @@ -3,13 +3,13 @@ import { fileURLToPath } from "url"; import { readFileSync } from "fs"; import { outputLogsColored, outputLogs } from "./utils.mjs"; import { default as mysql } from "mysql2"; -import { default as redis} from "ioredis"; +import { default as redis } from "ioredis"; import { promisifiedMysqlConnect, promisifiedRedisConnect } from "./utils.mjs"; function MysqlIntegrityCheck(mysqlConnection) { return new Promise((resolve, reject) => { - + resolve(); }); } @@ -63,12 +63,27 @@ function initializeBlorumServer() { }).then(function () { log("log", "INIT:db/redis", "Successfully connected to Redis Server"); }); - let mysqlPromise = promisifiedMysqlConnect(mysqlConnection); - mysqlPromise.catch(function (err) { - log("error", "INIT:db/mysql", "Failed to connect to MySQL Server"); - throw err; - }).then(function () { - log("log", "INIT:db/mysql", "Successfully connected to MySQL Server"); + let mysqlPromise = new Promise((resolve, reject) => { + promisifiedMysqlConnect(mysqlConnection).then(function (conn) { + log("log", "INIT:db/mysql", "Successfully connected to MySQL Server"); + MysqlIntegrityCheck(conn).then(function () { + conn.query("SELECT * FROM config;", function (err, result) { + if (err) { + throw err; + } + resolve({ + "mysql": mysqlConnection, + "site_config": result + }); + }); + }).catch(function (err) { + log("error", "INIT:db/mysql", "MySQL database integrity check failed."); + throw err; + }); + }).catch(function (err) { + log("error", "INIT:db/mysql", "Failed to connect to MySQL Server"); + throw err; + }); }); return { "bootConfig": bootConfig, diff --git a/modules/router.mjs b/modules/router.mjs index 71128fb4..85a5bc18 100644 --- a/modules/router.mjs +++ b/modules/router.mjs @@ -12,7 +12,8 @@ function initializeRouter(db,log,salt){ "X-Powered-By": "Blorum", "Access-Control-Allow-Origin": "*" }; - + blorumRouter.use(express.json()); + blorumRouter.get('/', function (req, res) { res.set("Content-Type","application/json"); res.set(commonHeader); @@ -27,14 +28,14 @@ function initializeRouter(db,log,salt){ }); blorumRouter.post('/user/register', function (req, res) { - console.log(req,res); + console.log(req.body); res.set("Content-Type","application/json"); res.set(commonHeader); res.status(200).send(); }); blorumRouter.post('/user/logout', function (req, res) { - console.log(req,res); + console.log(req); res.set("Content-Type","application/json"); res.set(commonHeader); res.status(200).send(); diff --git a/modules/utils.mjs b/modules/utils.mjs index 6f101afe..b97cf0e2 100644 --- a/modules/utils.mjs +++ b/modules/utils.mjs @@ -1,5 +1,5 @@ import "crypto"; -import {default as Redis} from "ioredis"; +import Redis from "ioredis"; const version = "1.0.0 in_dev (unf, debug) dv 10001"; diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 479de73c..1f29acea 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -1317,14 +1317,6 @@ "node": ">=4" } }, - "node_modules/redis-json": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/redis-json/-/redis-json-6.0.3.tgz", - "integrity": "sha512-m3F9WZ/LhESHEpagSyW4oqmfja0bdW6W52wQJm4FHj8gA0b+f5sdlp9BIa6q5+XGDqX6y6wS9WcsEJhhvyLeSg==", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/redis-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", diff --git a/node_modules/redis-json/CHANGELOG.md b/node_modules/redis-json/CHANGELOG.md deleted file mode 100644 index f1a8bb83..00000000 --- a/node_modules/redis-json/CHANGELOG.md +++ /dev/null @@ -1,72 +0,0 @@ -# v6.0.2 -* minor bug fixes and performance improvements - -# v6.0.1 -* adds function overload definition for `get` as `get(key: string): Promise` - -# v6.0.0 -* improves efficiency by combining multiple commands into one `multi` command -* fixes code smells -* replace the entire array when an array is present in the set command -* removes all `T` methods and integrates transaction within `` method itself - -# v5.0.0 -* supports empty string as pre-fixes - -# v4.3.0 -* adds `.incr()` & `.incrT()` methods to allow incrementing of values using `hincrbyfloat`. - -# v4.2.1 -* fixes #14, wherein when any prop was `set(id, {})` on an empty object, it wasn't reflected when `get()` was called on it - -# v4.2.0 -* adds support for transactions via `setT`, `delT` & `rewriteT` methods -* `rewrite` method now support expiry. Please check the API docs for more details - -# v4.1.0 -* adds `.del()` method - -# v4.0.1 -* `clearAll()` now scans the DB via `scan` command(with a COUNT 100), instead of getting all the prefixed keys via `keys` command which would block the DB if the list is huge -* Now allows fetching of internal fields as well -> `jsonCache.get('test', 'name', 'address', 'cars.0')` -* Improves documentation -* fixes a bug, if the key contains '/.' in it, then it was being misinterpreted during retrieval of data from DB -* adds more test cases for robustness -* seggregates test cases for better readability - -# v4.0.0 -* Total rewrite of the library for better maintenance and performance improvement -* Provides extension for custom types, which allows the users to defines how the custom object has to be stored in Redis and how to revive the same back from redis -* Now provide type support, which means that the type of data use save in jsonCache is exactly(===) the same that you get back - -# v3.2.1 -* Now supports [`redis`](https://www.npmjs.com/package/redis) client -* Improves efficiency by replacing `.call` with `.bind` while initializing internal redisClient -* fixes #7 -* removes the support for browsers (I know it was stupid for this library 😭) - -# v3.2.0 -* Now supports `.`(Dot) in object property (Ex. {'a.b': 'c'}) - -# v3.0.0 -* Usage of typescript -* Better seggregation of files -* Bug fix for handling empty object and empty array - -# v2.4.0 -* Support for querying only the required fields of the object - -# v2.3.0 -* Added `clearAll` method, which clears all the cached Json - -# v2.2.0 -* Support for redis prefix keys - -# v2.1.0 -* Support for key expiry - -# v2.0.0 -### Breaking Changes -* Changed callbacks to native Promises -* required node version > 7.0.0 -* `resave` has been renamed to `rewrite` diff --git a/node_modules/redis-json/LICENSE b/node_modules/redis-json/LICENSE deleted file mode 100644 index 67492ac8..00000000 --- a/node_modules/redis-json/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Akash Babu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/node_modules/redis-json/README.md b/node_modules/redis-json/README.md deleted file mode 100644 index ed56aaf8..00000000 --- a/node_modules/redis-json/README.md +++ /dev/null @@ -1,163 +0,0 @@ -# redis-json [![npm version](https://badge.fury.io/js/redis-json.svg)](https://badge.fury.io/js/redis-json) [![Build Status](https://travis-ci.com/AkashBabu/redis-json.svg?branch=master)](https://travis-ci.com/AkashBabu/redis-json) [![Coverage Status](https://coveralls.io/repos/github/AkashBabu/redis-json/badge.svg?branch=master)](https://coveralls.io/github/AkashBabu/redis-json?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/0015747bb31d085adae8/maintainability)](https://codeclimate.com/github/AkashBabu/redis-json/maintainability) - -Nodejs library to store/retrieve JSON Objects in RedisDB without loosing type information, i.e. WYSIWYG (What You Store Is What You Get) - -## Description -Every time `set` is called JSON object is flattened(embeded objects are converted to path keys) and then stored in Redis(just like a normal hashset), on `get` the hashset is unflattened and converted back to the original JSON object(with the same types as was in the original object). - -## What's new in v6.0.0? -- In response to issue: [#24](https://github.com/AkashBabu/redis-json/issues/24), we now replace the array in the cache when array is found in `set` object. - -If you are on V5 then please check this [Migration Guide to V6](docs/migrationV6.md) - -## API - -Please visit [this page](docs/api/README.md) for detailed API documentation. - -## Usage - -**Simple** -```typescript -import Redis from 'ioredis'; -import JSONCache from 'redis-json'; - -const redis = new Redis() as any; - -const user = { - name: 'redis-json', - age: 25, - address: { - doorNo: '12B', - locality: 'pentagon', - pincode: 123456 - }, - cars: ['BMW 520i', 'Audo A8'] -} - -const jsonCache = new JSONCache(redis, {prefix: 'cache:'}); - - -await jsonCache.set('123', user) - -await jsonCache.get('123') -// output -// { -// name: 'redis-json', -// age: 25, -// address: { -// doorNo: '12B', -// locality: 'pentagon', -// pincode: 123456 -// }, -// cars: ['BMW 520i', 'Audo A8'] -// } - -await jsonCache.set('123', {gender: 'male'}) -await jsonCache.get('123') -// output -// { -// name: 'redis-json', -// age: 25, -// address: { -// doorNo: '12B', -// locality: 'pentagon', -// pincode: 123456 -// }, -// cars: ['BMW 520i', 'Audo A8'] -// gender: 'male' -// } - -await jsonCache.get('123', 'name', 'age'); -// output -// { -// name: 'redis-json', -// age: 25, -// } - -await jsonCache.get('123', 'name', 'address.doorNo'); -// { -// name: 'redis-json', -// address: { -// doorNo: '12B' -// } -// } - -await jsonCache.clearAll(); - -await jsonCache.get('123'); -// undefined - - -await jsonCache.incr('123', {age: 1}) // increments age by 1 -``` - -**With custom stringifier and parser:** -```typescript -const jsonCache = new JSONCache(redis, { - stringifier: { - Date: (val: Date) => val.toISOString() - }, - parser: { - Date: (str: string) => new Date(str) - } -}) - -const date = new Date() -await jsonCache.set('test', { - date: date -}) - -// Redis hashset -> hgetall jc:test /// data -1) "date" -2) "2020-05-17T14:41:45.861Z" -> hgetall jc:test_t /// type info -1) "date" -2) "Date" - - -const result = await jsonCache.get('test') -result.date == date /// true -``` - -**With transactions:** -```typescript -const transaction = redisClient.multi(); - -transaction - .set('name', 'foo') - .set('bar', 'baz') - -await jsonCache.set('test', {name: 'testing'}, {transaction}) -await jsonCache.del('test1', {transaction}) -await jsonCache.rewrite('test2', {name: 'testing', age: 25}, {transaction}) - -transaction - .exec(function(err, replies) => { - /// your logic here after - }) -``` -Please note that only `set()`, `rewrite()`, `del()` & `incr()` supports transaction, where as `get()` & `clearAll()` do NOT support transaction because we process those results before returning it to the calling function. Moreover there is no real usecase in supporting transaction in `get()` & `clearAll()` methods! - - -## Changelogs - -Please refer to [this page](https://github.com/AkashBabu/redis-json/blob/master/CHANGELOG.md) - -## Coverage Report -> npm run coverage - -## Contributions -This is open-source, which makes it obvious for any PRs, but I would request you to add necessary test-cases for the same. - -### Pre-requisites: -Run your redis-server and then point the same client to the same. -An easier way to start redis-server, provided you've already installed `docker` (else visit [this page](https://docs.docker.com/get-docker/)) is by running this command: -> docker run --rm -it --name redis -p 6379:6379 redis - -We follow TDD approach, so write your test cases first and then run the same paralelly during development by running the following command: -> npm run test:dev - -## LICENCE - -MIT License diff --git a/node_modules/redis-json/docs/api/README.md b/node_modules/redis-json/docs/api/README.md deleted file mode 100644 index 49ad2aa6..00000000 --- a/node_modules/redis-json/docs/api/README.md +++ /dev/null @@ -1,103 +0,0 @@ -[redis-json](README.md) - -# redis-json - -## Index - -### Classes - -* [JSONCache](classes/jsoncache.md) - -### Interfaces - -* [IDelOptions](interfaces/ideloptions.md) -* [IOptions](interfaces/ioptions.md) -* [IParser](interfaces/iparser.md) -* [ISetOptions](interfaces/isetoptions.md) -* [IStringifier](interfaces/istringifier.md) - -### Type aliases - -* [IMulti](README.md#imulti) -* [IMultiCommands](README.md#imulticommands) -* [IPromisified](README.md#ipromisified) -* [IRedisClient](README.md#iredisclient) -* [IRedisMethods](README.md#iredismethods) -* [Methods](README.md#methods) -* [Transaction](README.md#transaction) - -## Type aliases - -### IMulti - -Ƭ **IMulti**: *function* - -Defined in src/lib/jsonCache.types.ts:7 - -#### Type declaration: - -▸ (`commands`: [IMultiCommands](README.md#imulticommands)): *Promise‹any›* - -**Parameters:** - -Name | Type | ------- | ------ | -`commands` | [IMultiCommands](README.md#imulticommands) | - -___ - -### IMultiCommands - -Ƭ **IMultiCommands**: *Array‹[string, string, any]›* - -Defined in src/lib/jsonCache.types.ts:6 - -___ - -### IPromisified - -Ƭ **IPromisified**: *function* - -Defined in src/lib/jsonCache.types.ts:2 - -#### Type declaration: - -▸ (...`args`: any[]): *Promise‹any›* - -**Parameters:** - -Name | Type | ------- | ------ | -`...args` | any[] | - -___ - -### IRedisClient - -Ƭ **IRedisClient**: *[IRedisMethods](README.md#iredismethods)* - -Defined in src/lib/jsonCache.types.ts:15 - -___ - -### IRedisMethods - -Ƭ **IRedisMethods**: *object & object* - -Defined in src/lib/jsonCache.types.ts:9 - -___ - -### Methods - -Ƭ **Methods**: *"hmset" | "hmget" | "hgetall" | "expire" | "del" | "scan" | "hincrbyfloat"* - -Defined in src/lib/jsonCache.types.ts:4 - -___ - -### Transaction - -Ƭ **Transaction**: *any* - -Defined in src/lib/jsonCache.types.ts:16 diff --git a/node_modules/redis-json/docs/api/classes/jsoncache.md b/node_modules/redis-json/docs/api/classes/jsoncache.md deleted file mode 100644 index 7efa41f3..00000000 --- a/node_modules/redis-json/docs/api/classes/jsoncache.md +++ /dev/null @@ -1,213 +0,0 @@ -[redis-json](../README.md) › [JSONCache](jsoncache.md) - -# Class: JSONCache ‹**T**› - -JSONCache eases the difficulties in storing a JSON in redis. - - It stores the JSON in hashset for simpler get and set of required -fields. It also allows you to override/set specific fields in -the JSON without rewriting the whole JSON tree. Which means that it -is literally possible to `Object.deepAssign()`. - - Everytime you store an object, JSONCache would store two hashset -in Redis, one for data and the other for type information. This helps -during retrieval of data, to restore the type of data which was originally -provided. All these workaround are needed because Redis DOES NOT support -any other data type apart from String. - -Well the easiest way is to store an object in Redis is -JSON.stringify(obj) and store the stringified result. -But this can cause issue when the obj is -too huge or when you would want to retrieve only specific fields -from the JSON but do not want to parse the whole JSON. - Also note that this method would end up in returing all the -fields as strings and you would have no clue to identify the type of -field. - -## Type parameters - -▪ **T** - -## Hierarchy - -* **JSONCache** - -## Implements - -* IJSONCache‹T› - -## Index - -### Constructors - -* [constructor](jsoncache.md#constructor) - -### Methods - -* [clearAll](jsoncache.md#clearall) -* [del](jsoncache.md#del) -* [get](jsoncache.md#get) -* [incr](jsoncache.md#incr) -* [rewrite](jsoncache.md#rewrite) -* [set](jsoncache.md#set) - -## Constructors - -### constructor - -\+ **new JSONCache**(`redisClient`: any, `options`: [IOptions](../interfaces/ioptions.md)): *[JSONCache](jsoncache.md)* - -Defined in src/lib/jsonCache.ts:47 - -Intializes JSONCache instance - -**Parameters:** - -Name | Type | Default | Description | ------- | ------ | ------ | ------ | -`redisClient` | any | - | RedisClient instance(Preferred ioredis - cient). It supports any redisClient instance that has `'hmset' | 'hmget' | 'hgetall' | 'expire' | 'del' | 'keys'` methods implemented | -`options` | [IOptions](../interfaces/ioptions.md) | {} | Options for controlling the prefix | - -**Returns:** *[JSONCache](jsoncache.md)* - -## Methods - -### clearAll - -▸ **clearAll**(): *Promise‹any›* - -Defined in src/lib/jsonCache.ts:177 - -Removes/deletes all the keys in the JSON Cache, -having the prefix. - -**Returns:** *Promise‹any›* - -___ - -### del - -▸ **del**(`key`: string, `options`: [IDelOptions](../interfaces/ideloptions.md)): *Promise‹any›* - -Defined in src/lib/jsonCache.ts:204 - -Removes the given key from Redis - -Please use this method instead of -directly using `redis.del` as this method -ensures that even the corresponding type info -is removed. It also ensures that prefix is -added to key, ensuring no other key is -removed unintentionally - -**Parameters:** - -Name | Type | Default | Description | ------- | ------ | ------ | ------ | -`key` | string | - | Redis key | -`options` | [IDelOptions](../interfaces/ideloptions.md) | {} | - | - -**Returns:** *Promise‹any›* - -___ - -### get - -▸ **get**(`key`: string): *Promise‹T | undefined›* - -Defined in src/lib/jsonCache.ts:110 - -Retrieves the hashset from redis and -unflattens it back to the original Object - -**Parameters:** - -Name | Type | Description | ------- | ------ | ------ | -`key` | string | Redis key | - -**Returns:** *Promise‹T | undefined›* - -request object from the cache - -▸ **get**(`key`: string, ...`fields`: string[]): *Promise‹Partial‹T› | undefined›* - -Defined in src/lib/jsonCache.ts:111 - -**Parameters:** - -Name | Type | ------- | ------ | -`key` | string | -`...fields` | string[] | - -**Returns:** *Promise‹Partial‹T› | undefined›* - -___ - -### incr - -▸ **incr**(`key`: string, `obj`: RecursivePartial‹T›, `options`: [IDelOptions](../interfaces/ideloptions.md)): *Promise‹any›* - -Defined in src/lib/jsonCache.ts:227 - -Increments the value of a variable in the JSON -Note: You can increment multiple variables in the -same command (Internally it will split it into multiple -commands on the RedisDB) - -**`example`** -```JS -await jsonCache.incr(key, {messages: 10, profile: {age: 1}}) -``` - -**Parameters:** - -Name | Type | Default | Description | ------- | ------ | ------ | ------ | -`key` | string | - | Redis Cache key | -`obj` | RecursivePartial‹T› | - | Partial object specifying the path to the required variable along with value | -`options` | [IDelOptions](../interfaces/ideloptions.md) | {} | - | - -**Returns:** *Promise‹any›* - -___ - -### rewrite - -▸ **rewrite**(`key`: string, `obj`: T, `options`: [ISetOptions](../interfaces/isetoptions.md)): *Promise‹any›* - -Defined in src/lib/jsonCache.ts:162 - -Replace the entire hashset for the given key - -**Parameters:** - -Name | Type | Default | Description | ------- | ------ | ------ | ------ | -`key` | string | - | Redis key | -`obj` | T | - | JSON Object of type T | -`options` | [ISetOptions](../interfaces/isetoptions.md) | {} | - | - -**Returns:** *Promise‹any›* - -___ - -### set - -▸ **set**(`key`: string, `obj`: T, `options`: [ISetOptions](../interfaces/isetoptions.md)): *Promise‹any›* - -Defined in src/lib/jsonCache.ts:90 - -Flattens the given json object and -stores it in Redis hashset - -**Parameters:** - -Name | Type | Default | Description | ------- | ------ | ------ | ------ | -`key` | string | - | Redis key | -`obj` | T | - | JSON object to be stored | -`options` | [ISetOptions](../interfaces/isetoptions.md) | {} | | - -**Returns:** *Promise‹any›* diff --git a/node_modules/redis-json/docs/api/interfaces/ideloptions.md b/node_modules/redis-json/docs/api/interfaces/ideloptions.md deleted file mode 100644 index a1278910..00000000 --- a/node_modules/redis-json/docs/api/interfaces/ideloptions.md +++ /dev/null @@ -1,21 +0,0 @@ -[redis-json](../README.md) › [IDelOptions](ideloptions.md) - -# Interface: IDelOptions - -## Hierarchy - -* **IDelOptions** - -## Index - -### Properties - -* [transaction](ideloptions.md#optional-transaction) - -## Properties - -### `Optional` transaction - -• **transaction**? : *[Transaction](../README.md#transaction)* - -Defined in src/lib/jsonCache.types.ts:19 diff --git a/node_modules/redis-json/docs/api/interfaces/ioptions.md b/node_modules/redis-json/docs/api/interfaces/ioptions.md deleted file mode 100644 index 6c322186..00000000 --- a/node_modules/redis-json/docs/api/interfaces/ioptions.md +++ /dev/null @@ -1,50 +0,0 @@ -[redis-json](../README.md) › [IOptions](ioptions.md) - -# Interface: IOptions - -JSONCache options - -## Hierarchy - -* **IOptions** - -## Index - -### Properties - -* [parser](ioptions.md#optional-parser) -* [prefix](ioptions.md#optional-prefix) -* [stringifier](ioptions.md#optional-stringifier) - -## Properties - -### `Optional` parser - -• **parser**? : *[IParser](iparser.md)* - -Defined in src/lib/jsonCache.types.ts:63 - -Parser will be used to convert the string -back to custom object when `get` is called - -___ - -### `Optional` prefix - -• **prefix**? : *undefined | string* - -Defined in src/lib/jsonCache.types.ts:51 - -Custom prefix to be used for storage -namespace separation - -___ - -### `Optional` stringifier - -• **stringifier**? : *[IStringifier](istringifier.md)* - -Defined in src/lib/jsonCache.types.ts:57 - -Stringifier will be used to convert a custom -object to a string when `set` is called diff --git a/node_modules/redis-json/docs/api/interfaces/iparser.md b/node_modules/redis-json/docs/api/interfaces/iparser.md deleted file mode 100644 index 4c42dc0c..00000000 --- a/node_modules/redis-json/docs/api/interfaces/iparser.md +++ /dev/null @@ -1,25 +0,0 @@ -[redis-json](../README.md) › [IParser](iparser.md) - -# Interface: IParser - -Parser will be used to convert the string -back to custom object when `get` is called - -## Hierarchy - -* **IParser** - -## Indexable - -* \[ **constructorName**: *string*\]: function - -Parser will be used to convert the string -back to custom object when `get` is called - -▸ (`val`: string): *any* - -**Parameters:** - -Name | Type | ------- | ------ | -`val` | string | diff --git a/node_modules/redis-json/docs/api/interfaces/isetoptions.md b/node_modules/redis-json/docs/api/interfaces/isetoptions.md deleted file mode 100644 index e5c8b5c9..00000000 --- a/node_modules/redis-json/docs/api/interfaces/isetoptions.md +++ /dev/null @@ -1,30 +0,0 @@ -[redis-json](../README.md) › [ISetOptions](isetoptions.md) - -# Interface: ISetOptions - -## Hierarchy - -* **ISetOptions** - -## Index - -### Properties - -* [expire](isetoptions.md#optional-expire) -* [transaction](isetoptions.md#optional-transaction) - -## Properties - -### `Optional` expire - -• **expire**? : *undefined | number* - -Defined in src/lib/jsonCache.types.ts:23 - -___ - -### `Optional` transaction - -• **transaction**? : *[Transaction](../README.md#transaction)* - -Defined in src/lib/jsonCache.types.ts:24 diff --git a/node_modules/redis-json/docs/api/interfaces/istringifier.md b/node_modules/redis-json/docs/api/interfaces/istringifier.md deleted file mode 100644 index 2b901bb5..00000000 --- a/node_modules/redis-json/docs/api/interfaces/istringifier.md +++ /dev/null @@ -1,25 +0,0 @@ -[redis-json](../README.md) › [IStringifier](istringifier.md) - -# Interface: IStringifier - -Stringifier will be used to convert a custom -object to a string when `set` is called - -## Hierarchy - -* **IStringifier** - -## Indexable - -* \[ **constructorName**: *string*\]: function - -Stringifier will be used to convert a custom -object to a string when `set` is called - -▸ (`val`: any): *string* - -**Parameters:** - -Name | Type | ------- | ------ | -`val` | any | diff --git a/node_modules/redis-json/docs/migrationV6.md b/node_modules/redis-json/docs/migrationV6.md deleted file mode 100644 index 6137c540..00000000 --- a/node_modules/redis-json/docs/migrationV6.md +++ /dev/null @@ -1,78 +0,0 @@ -# Migrating from V5 -> V6 - -## Move away from confusing methods - -Earlier `setT`, `delT`, `rewriteT` & `incrT` methods were introduced to handle queries on Transactions. Now this functionality is merged with their original methods `set`, `del`, `rewrite` & `incr` - -**Suggested Changes:** -* `setT(transaction, key, obj)` -> `set(key, obj, {transaction})` -* `rewriteT(transaction, key, obj)` -> `rewrite(key, obj, {transaction})` -* `delT(transaction, key, obj)` -> `del(key, {transaction})` -* `incrT(transaction, key, obj)` -> `incr(key, obj, {transaction})` - - -## Array would be replaced on set - -When you try to set data on an already existing JSON and if the data contains an array, then the array in the cached JSON would be replaced with the array in the data. - -**For example:** - -Cached JSON -```JSON -{ - "foo": [1,2,3], - "bar": "baz" -} -``` - -Data -```JSON -{ - "foo": [4,5] -} -``` - -Result (V5) -```JSON -{ - "foo": [4,5,3], - "bar": "baz" -} -``` - -Result (V6) -```JSON -{ - "foo": [4,5], - "bar": "baz" -} -``` - -Like you observed in the above example, starting with V6 we replace the stored array instead of replacing only the provided indices. -So if this applies to you, then you must make corrective changes in case you want to retain V5's behaivour - -**Suggested Changes:** -```TS -const jc = new JSONCache({...}) - -await jc.set('test', { - "foo": [1,2,3], - "bar": "baz" -}) - - -// if you want to retain the other -// elements in the array -const cachedData = await jc.get('test'); -cachedData.foo[0] = 4; -cachedData.foo[1] = 5; - -await jc.set('test', cachedData); - -/// Result -// { -// "foo": [4,5,3], -// "bar": "baz" -// } - -``` diff --git a/node_modules/redis-json/es/jsonCache.js b/node_modules/redis-json/es/jsonCache.js deleted file mode 100644 index 8a4860f9..00000000 --- a/node_modules/redis-json/es/jsonCache.js +++ /dev/null @@ -1,659 +0,0 @@ -import { promisify } from 'util'; - -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at http://www.apache.org/licenses/LICENSE-2.0 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. -***************************************************************************** */ -function __awaiter(thisArg, _arguments, P, generator) { - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { - try { - step(generator.next(value)); - } catch (e) { - reject(e); - } - } - - function rejected(value) { - try { - step(generator["throw"](value)); - } catch (e) { - reject(e); - } - } - - function step(result) { - result.done ? resolve(result.value) : new P(function (resolve) { - resolve(result.value); - }).then(fulfilled, rejected); - } - - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -} - -/** - * Return the given key if it's a string else - * parses it into number - * - * @param key - * - * @returns a string if it cannot be parsed to a number - * else returns the parsed number - */ -function parseKey(key) { - const numKey = Number(key); - return isNaN(numKey) || isHex(key) ? decodeKey(key) : numKey; -} -/** - * Encapsulate '.' in the given key, such - * that a '.' in the key is NOT misinterpreted - * during unflattening of the object - * - * @param key - */ -function encodeKey(key) { - return key.replace(/\./g, '/.'); -} -/** - * Recover the actual key which was encoded earlier. - * This is done to allow a '.' in the key - * - * @param key - */ -function decodeKey(key) { - return key ? key.replace(/\/\./g, '.') : key; -} -const splitKey = (() => { - const keySplitReg = /(? { - return key.split(keySplitReg); - }; -})(); -/** - * Checks the key is hex string or not. - * - * @param key - */ -function isHex(key) { - return key ? Boolean(key.match(/^0x[0-9a-f]+$/i)) : false; -} - -var TYPE; -(function (TYPE) { - TYPE["OBJECT"] = "0"; - TYPE["STRING"] = "1"; - TYPE["NUMBER"] = "2"; - TYPE["BOOLEAN"] = "3"; - TYPE["FUNCTION"] = "4"; - TYPE["UNDEFINED"] = "5"; - TYPE["SYMBOL"] = "6"; -})(TYPE || (TYPE = {})); -/** - * Returns true if the constructor name is known - * to us. Ex: Object, Array - */ -const isKnownContructor = (() => { - const knownConstructors = { - Object: true, - Array: true, - }; - return (constructorName) => knownConstructors[constructorName]; -})(); -/** - * Returns true if the given value's - * type need to be skipped during storage. - * For ex: Symbol -> Since symbols are private, - * we DO NOT encourage them to be stored, hence - * we are skipping from storing the same. - * - * In case you've forked this library and want to - * add more type, then this is the place for you 🙂 - */ -const isSkippedType = (() => { - const skippedType = { - symbol: true, - }; - return (val) => !!skippedType[typeof val]; -})(); -/** - * Returns a shorter form of the type of the - * value that can be stored in redis. - * This also handles custom Classes by using - * their constructor names directly. - * - * @param val Value whose type needs to be computed - */ -const getTypeOf = (() => { - const shortTypes = { - object: TYPE.OBJECT, - string: TYPE.STRING, - number: TYPE.NUMBER, - boolean: TYPE.BOOLEAN, - function: TYPE.FUNCTION, - undefined: TYPE.UNDEFINED, - symbol: TYPE.SYMBOL, - }; - return (val) => { - if (typeof val === 'object') { - // If the val is `null` - if (!val) { - return TYPE.OBJECT; - } - const constructorName = val.constructor.name; - return isKnownContructor(constructorName) - // if the val is {} or [] - ? TYPE.OBJECT - // if the val is Date or other custom classes / object - : constructorName; - } - return shortTypes[typeof val] || TYPE.STRING /** this is a fallback, just in case */; - }; -})(); -/** - * Returns the stringified version of the given value. - * However note that this method needs to take care, - * such that special values like undefined, null, false, true - * etc are also stringified correctly for storage. - * - * In case of a custom class / object, this method would - * call the provided stringifier (if any available), else - * would use `String(val)` - * - * @param val Value to be evaluated - * @param stringifier Custom stringifiers - * - * @returns Stringified value. If null is returned, then such a value must NOT - * be stored - */ -const getValueOf = (val, stringifier = {}) => { - var _a; - if (typeof val === 'object') { - // if the val is null - if (!val) { - return 'null'; - } - const constructorName = (_a = val === null || val === void 0 ? void 0 : val.constructor) === null || _a === void 0 ? void 0 : _a.name; - return isKnownContructor(constructorName) - // if the val is {} or [] - ? JSON.stringify(val) - // if the val is Date or other custom classes / object - : stringifier[constructorName] - ? stringifier[constructorName](val) - : String(val); - } - return String(val); -}; -/** - * Converts the given value to the specified type. - * Also note that, if a custom className type is - * detected, then the provided custom Parser will - * be called (if any available), else will return - * the value as is. - */ -const getTypedVal = (() => { - const internalParsers = { - [TYPE.STRING]: val => val, - [TYPE.NUMBER]: Number, - [TYPE.BOOLEAN]: (val) => val === 'true', - [TYPE.FUNCTION]: val => val, - [TYPE.UNDEFINED]: () => undefined, - [TYPE.SYMBOL]: (val) => val, - [TYPE.OBJECT]: (() => { - const valMap = { - '{}': () => ({}), - '[]': () => [], - 'null': () => null, - }; - return (val) => valMap[val](); - })(), - }; - return (type, val, parser = {}) => { - return internalParsers[type] - ? internalParsers[type](val) - : parser[type] - ? parser[type](val) - : val; - }; -})(); - -const getDefaultResult = () => ({ - data: {}, - typeInfo: {}, - arrayInfo: {}, -}); -/** - * @internal - * - * Class for flattening and unflattening an object / array - * - * This could've been a simple function but is rather a class - * because we are instantiating it during the constructor phase of - * JSONCache class by calling it with stringifier & parser options. - */ -class Flattener { - constructor(stringifier = {}, parser = {}) { - this.stringifier = stringifier; - this.parser = parser; - } - /** - * Flattens the given object and converts it - * to a dept of 1 - * - * @param obj Object to be flattened - */ - flatten(obj) { - return this.traverse(obj, '', getDefaultResult()); - } - /** - * Unflattens the given object to its original - * format and also applies the necessary types - * that it originally had - * - * @param flattened Flattened object - */ - unflatten(flattened) { - const typedData = this.mergeTypes(flattened); - let result; - Object.entries(typedData).some(([key, val]) => { - // if the key is '', it means that - // the flattened object / array is empty - if (!key) { - if (Object.keys(typedData).length <= 1) { - result = val; - return true; - } - else { - // when the initial data is {'': {}} and - // later a prop is added to the same, then - // the data would be {'': {}, prop: {...}} - // hence we need to continue the loop when - // the keys.length > 1 - return false; - } - } - const splittedKeys = splitKey(key); - if (!result) { - result = typeof parseKey(splittedKeys[0]) === 'number' ? [] : {}; - } - this.scaffoldStructure(result, splittedKeys, val); - return false; - }); - return result; - } - /*********************************** - * PRIVATE METHODS - Flatten helpers - **********************************/ - traverse(target, basePath, result) { - if (!(target instanceof Object)) - return result; - if (Array.isArray(target)) { - result.arrayInfo[basePath] = true; - } - const entries = Object.entries(target); - if (entries.length > 0) { - entries.forEach(([key, val]) => { - const encodedKey = encodeKey(key); - const path = appendPath(basePath, encodedKey); - if (val instanceof Object) { - this.traverse(val, path, result); - } - else { - this.assignResult(result, path, val); - } - }); - } - else { - this.assignResult(result, basePath, target); - } - return result; - } - assignResult(result, path, val) { - if (!isSkippedType(val)) { - result.data[path] = getValueOf(val, this.stringifier); - result.typeInfo[path] = getTypeOf(val); - } - } - /************************************* - * PRIVATE METHODS - Unflatten helpers - *************************************/ - mergeTypes(result) { - const { data, typeInfo } = result; - return Object.entries(data).reduce((merged, [path, val]) => { - merged[path] = getTypedVal(typeInfo[path], val, this.parser); - return merged; - }, {}); - } - scaffoldStructure(tree, splittedKeys, val) { - // Loop until k1 has reached end of split - for (let i = 0, len = splittedKeys.length; i < len; i++) { - const k1 = parseKey(splittedKeys[i]); - const k2 = parseKey(splittedKeys[i + 1]); - if (typeof k2 === 'undefined') { - tree[k1] = val; - } - else { - const isObj = typeof tree[k1] === 'object'; - if (!isObj) - tree[k1] = typeof k2 === 'number' ? [] : {}; - tree = tree[k1]; - } - } - } -} -function appendPath(basePath, key) { - return basePath ? `${basePath}.${key}` : key; -} - -const Config = { - SCAN_COUNT: 100, -}; - -/** - * JSONCache eases the difficulties in storing a JSON in redis. - * - * It stores the JSON in hashset for simpler get and set of required - * fields. It also allows you to override/set specific fields in - * the JSON without rewriting the whole JSON tree. Which means that it - * is literally possible to `Object.deepAssign()`. - * - * Everytime you store an object, JSONCache would store two hashset - * in Redis, one for data and the other for type information. This helps - * during retrieval of data, to restore the type of data which was originally - * provided. All these workaround are needed because Redis DOES NOT support - * any other data type apart from String. - * - * Well the easiest way is to store an object in Redis is - * JSON.stringify(obj) and store the stringified result. - * But this can cause issue when the obj is - * too huge or when you would want to retrieve only specific fields - * from the JSON but do not want to parse the whole JSON. - * Also note that this method would end up in returing all the - * fields as strings and you would have no clue to identify the type of - * field. - */ -class JSONCache { - /** - * Intializes JSONCache instance - * @param redisClient RedisClient instance(Preferred ioredis - cient). - * It supports any redisClient instance that has - * `'hmset' | 'hmget' | 'hgetall' | 'expire' | 'del' | 'keys'` - * methods implemented - * @param options Options for controlling the prefix - */ - constructor(redisClient, options = {}) { - this.options = options; - this.options.prefix = typeof options.prefix === 'string' ? options.prefix : 'jc:'; - this.redisClientInt = { - hmset: promisify(redisClient.hmset).bind(redisClient), - hmget: promisify(redisClient.hmget).bind(redisClient), - hgetall: promisify(redisClient.hgetall).bind(redisClient), - expire: promisify(redisClient.expire).bind(redisClient), - del: promisify(redisClient.del).bind(redisClient), - scan: promisify(redisClient.scan).bind(redisClient), - hincrbyfloat: promisify(redisClient.hincrbyfloat).bind(redisClient), - multi: (commands) => { - return new Promise((resolve, reject) => { - redisClient.multi(commands).exec((err, results) => { - if (err) - reject(err); - else - resolve(results); - }); - }); - }, - }; - this.flattener = new Flattener(options.stringifier, options.parser); - } - /** - * Flattens the given json object and - * stores it in Redis hashset - * - * @param key Redis key - * @param obj JSON object to be stored - * @param options - */ - set(key, obj, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - const flattened = this.flattener.flatten(obj); - const commands = yield this.getKeysToBeRemoved(key, flattened); - this.addSetCommands(key, flattened, commands, options.expire); - yield this.execCommand(commands, options.transaction); - }); - } - get(key, ...fields) { - return __awaiter(this, void 0, void 0, function* () { - const [data, typeInfo] = yield Promise.all([ - this.redisClientInt.hgetall(this.getKey(key)), - this.redisClientInt.hgetall(this.getTypeKey(key)), - ]); - // Empty object is returned when - // the given key is not present - // in the cache - if (!(data && typeInfo)) { - return undefined; - } - const dataKeysLen = Object.keys(data).length; - const typeInfoKeysLen = Object.keys(typeInfo).length; - if (dataKeysLen !== typeInfoKeysLen || dataKeysLen === 0) - return undefined; - let result; - if (fields.length > 0) { - let dataKeys; - result = fields.reduce((res, field) => { - if (field in data) { - res.data[field] = data[field]; - res.typeInfo[field] = typeInfo[field]; - } - else { - const searchKey = `${field}.`; - (dataKeys || (dataKeys = Object.keys(data))).forEach(flattenedKey => { - if (flattenedKey.startsWith(searchKey)) { - res.data[flattenedKey] = data[flattenedKey]; - res.typeInfo[flattenedKey] = typeInfo[flattenedKey]; - } - }); - } - return res; - }, { data: {}, typeInfo: {} }); - } - else { - result = { data, typeInfo, arrayInfo: {} }; - } - return this.flattener.unflatten(result); - }); - } - /** - * Replace the entire hashset for the given key - * - * @param key Redis key - * @param obj JSON Object of type T - */ - rewrite(key, obj, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - const commands = [ - ['del', this.getKey(key)], - ['del', this.getTypeKey(key)], - ]; - const flattened = this.flattener.flatten(obj); - this.addSetCommands(key, flattened, commands, options.expire); - yield this.execCommand(commands, options.transaction); - }); - } - /** - * Removes/deletes all the keys in the JSON Cache, - * having the prefix. - */ - clearAll() { - return __awaiter(this, void 0, void 0, function* () { - let cursor = '0'; - let keys; - do { - [cursor, keys] = yield this.redisClientInt.scan(cursor, 'MATCH', `${this.options.prefix}*`, 'COUNT', Config.SCAN_COUNT); - if (keys.length > 0) { - yield this.redisClientInt.del(...keys); - } - } while (cursor !== '0'); - }); - } - /** - * Removes the given key from Redis - * - * Please use this method instead of - * directly using `redis.del` as this method - * ensures that even the corresponding type info - * is removed. It also ensures that prefix is - * added to key, ensuring no other key is - * removed unintentionally - * - * @param key Redis key - */ - del(key, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - const commands = [ - ['del', this.getKey(key)], - ['del', this.getTypeKey(key)], - ]; - yield this.execCommand(commands, options.transaction); - }); - } - /** - * Increments the value of a variable in the JSON - * Note: You can increment multiple variables in the - * same command (Internally it will split it into multiple - * commands on the RedisDB) - * - * @example - * ```JS - * await jsonCache.incr(key, {messages: 10, profile: {age: 1}}) - * ``` - * - * @param key Redis Cache key - * @param obj Partial object specifying the path to the required - * variable along with value - */ - incr(key, obj, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - const flattened = this.flattener.flatten(obj); - const commands = []; - Object.entries(flattened.data).forEach(([path, incrVal]) => { - // This check is needed to avoid redis errors. - // It also helps while the user wants to increment the value - // within an array. - // Ex: rand: [null, null, 1] => this will increment the 3rd index by 1 - if (flattened.typeInfo[path] !== TYPE.NUMBER) { - return; - } - commands.push(['hincrbyfloat', this.getKey(key), path, incrVal]); - }); - yield this.execCommand(commands, options.transaction); - }); - } - /****************** - * PRIVATE METHODS - ******************/ - getKeysToBeRemoved(key, flattened) { - return __awaiter(this, void 0, void 0, function* () { - const commands = []; - // Check if the given obj has arrays and if it does - // then we must remove the current array stored in - // Cache and then set this array in the Cache - if (Object.keys(flattened.arrayInfo).length > 0) { - const currentObj = yield this.get(key); - if (currentObj) { - const currrentObjFlattened = this.flattener.flatten(currentObj).data; - const keysToBeRemoved = []; - // Get all paths matching the parent array path - Object.keys(flattened.arrayInfo).forEach(path => { - Object.keys(currrentObjFlattened).forEach(objPath => { - if (objPath.startsWith(path)) { - keysToBeRemoved.push(objPath); - } - }); - }); - if (keysToBeRemoved.length > 0) { - commands.push(['hdel', this.getKey(key), ...keysToBeRemoved]); - commands.push(['hdel', this.getTypeKey(key), ...keysToBeRemoved]); - } - } - } - return commands; - }); - } - /** - * Returns the redis storage key for storing data - * by prefixing custom string, such that it - * doesn't collide with other keys in usage - * - * @param key Storage key - */ - getKey(key) { - return `${this.options.prefix}${key}`; - } - /** - * Returns the redis storage key for storing - * corresponding types by prefixing custom string, - * such that it doesn't collide with other keys - * in usage - * - * @param key Storage key - */ - getTypeKey(key) { - return `${this.options.prefix}${key}_t`; - } - /** - * Will add Set commands to the given array - * This logic was separated to remove code duplication - * in set & rewrite methods - * - * @param key Storage key - * @param flattened Flattened object containing data & typeInfo - * @param commands List of commands to which set commands has to be appended - * @param expire Redis Key expiry - */ - addSetCommands(key, flattened, commands, expire) { - commands.push(['hmset', this.getKey(key), flattened.data]); - commands.push(['hmset', this.getTypeKey(key), flattened.typeInfo]); - if (expire) { - commands.push(['expire', this.getKey(key), expire]); - commands.push(['expire', this.getTypeKey(key), expire]); - } - return commands; - } - execTransactionCommands(commands, transaction) { - commands.forEach(command => { - const [action, ...args] = command; - transaction[action](...args); - }); - } - execCommand(commands, transaction) { - return __awaiter(this, void 0, void 0, function* () { - if (transaction) { - this.execTransactionCommands(commands, transaction); - return transaction; - } - else { - const result = yield this.redisClientInt.multi(commands); - return result; - } - }); - } -} - -export default JSONCache; diff --git a/node_modules/redis-json/lib/jsonCache.js b/node_modules/redis-json/lib/jsonCache.js deleted file mode 100644 index 1f2f3f24..00000000 --- a/node_modules/redis-json/lib/jsonCache.js +++ /dev/null @@ -1,661 +0,0 @@ -'use strict'; - -var util = require('util'); - -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at http://www.apache.org/licenses/LICENSE-2.0 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. -***************************************************************************** */ -function __awaiter(thisArg, _arguments, P, generator) { - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { - try { - step(generator.next(value)); - } catch (e) { - reject(e); - } - } - - function rejected(value) { - try { - step(generator["throw"](value)); - } catch (e) { - reject(e); - } - } - - function step(result) { - result.done ? resolve(result.value) : new P(function (resolve) { - resolve(result.value); - }).then(fulfilled, rejected); - } - - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -} - -/** - * Return the given key if it's a string else - * parses it into number - * - * @param key - * - * @returns a string if it cannot be parsed to a number - * else returns the parsed number - */ -function parseKey(key) { - const numKey = Number(key); - return isNaN(numKey) || isHex(key) ? decodeKey(key) : numKey; -} -/** - * Encapsulate '.' in the given key, such - * that a '.' in the key is NOT misinterpreted - * during unflattening of the object - * - * @param key - */ -function encodeKey(key) { - return key.replace(/\./g, '/.'); -} -/** - * Recover the actual key which was encoded earlier. - * This is done to allow a '.' in the key - * - * @param key - */ -function decodeKey(key) { - return key ? key.replace(/\/\./g, '.') : key; -} -const splitKey = (() => { - const keySplitReg = /(? { - return key.split(keySplitReg); - }; -})(); -/** - * Checks the key is hex string or not. - * - * @param key - */ -function isHex(key) { - return key ? Boolean(key.match(/^0x[0-9a-f]+$/i)) : false; -} - -var TYPE; -(function (TYPE) { - TYPE["OBJECT"] = "0"; - TYPE["STRING"] = "1"; - TYPE["NUMBER"] = "2"; - TYPE["BOOLEAN"] = "3"; - TYPE["FUNCTION"] = "4"; - TYPE["UNDEFINED"] = "5"; - TYPE["SYMBOL"] = "6"; -})(TYPE || (TYPE = {})); -/** - * Returns true if the constructor name is known - * to us. Ex: Object, Array - */ -const isKnownContructor = (() => { - const knownConstructors = { - Object: true, - Array: true, - }; - return (constructorName) => knownConstructors[constructorName]; -})(); -/** - * Returns true if the given value's - * type need to be skipped during storage. - * For ex: Symbol -> Since symbols are private, - * we DO NOT encourage them to be stored, hence - * we are skipping from storing the same. - * - * In case you've forked this library and want to - * add more type, then this is the place for you 🙂 - */ -const isSkippedType = (() => { - const skippedType = { - symbol: true, - }; - return (val) => !!skippedType[typeof val]; -})(); -/** - * Returns a shorter form of the type of the - * value that can be stored in redis. - * This also handles custom Classes by using - * their constructor names directly. - * - * @param val Value whose type needs to be computed - */ -const getTypeOf = (() => { - const shortTypes = { - object: TYPE.OBJECT, - string: TYPE.STRING, - number: TYPE.NUMBER, - boolean: TYPE.BOOLEAN, - function: TYPE.FUNCTION, - undefined: TYPE.UNDEFINED, - symbol: TYPE.SYMBOL, - }; - return (val) => { - if (typeof val === 'object') { - // If the val is `null` - if (!val) { - return TYPE.OBJECT; - } - const constructorName = val.constructor.name; - return isKnownContructor(constructorName) - // if the val is {} or [] - ? TYPE.OBJECT - // if the val is Date or other custom classes / object - : constructorName; - } - return shortTypes[typeof val] || TYPE.STRING /** this is a fallback, just in case */; - }; -})(); -/** - * Returns the stringified version of the given value. - * However note that this method needs to take care, - * such that special values like undefined, null, false, true - * etc are also stringified correctly for storage. - * - * In case of a custom class / object, this method would - * call the provided stringifier (if any available), else - * would use `String(val)` - * - * @param val Value to be evaluated - * @param stringifier Custom stringifiers - * - * @returns Stringified value. If null is returned, then such a value must NOT - * be stored - */ -const getValueOf = (val, stringifier = {}) => { - var _a; - if (typeof val === 'object') { - // if the val is null - if (!val) { - return 'null'; - } - const constructorName = (_a = val === null || val === void 0 ? void 0 : val.constructor) === null || _a === void 0 ? void 0 : _a.name; - return isKnownContructor(constructorName) - // if the val is {} or [] - ? JSON.stringify(val) - // if the val is Date or other custom classes / object - : stringifier[constructorName] - ? stringifier[constructorName](val) - : String(val); - } - return String(val); -}; -/** - * Converts the given value to the specified type. - * Also note that, if a custom className type is - * detected, then the provided custom Parser will - * be called (if any available), else will return - * the value as is. - */ -const getTypedVal = (() => { - const internalParsers = { - [TYPE.STRING]: val => val, - [TYPE.NUMBER]: Number, - [TYPE.BOOLEAN]: (val) => val === 'true', - [TYPE.FUNCTION]: val => val, - [TYPE.UNDEFINED]: () => undefined, - [TYPE.SYMBOL]: (val) => val, - [TYPE.OBJECT]: (() => { - const valMap = { - '{}': () => ({}), - '[]': () => [], - 'null': () => null, - }; - return (val) => valMap[val](); - })(), - }; - return (type, val, parser = {}) => { - return internalParsers[type] - ? internalParsers[type](val) - : parser[type] - ? parser[type](val) - : val; - }; -})(); - -const getDefaultResult = () => ({ - data: {}, - typeInfo: {}, - arrayInfo: {}, -}); -/** - * @internal - * - * Class for flattening and unflattening an object / array - * - * This could've been a simple function but is rather a class - * because we are instantiating it during the constructor phase of - * JSONCache class by calling it with stringifier & parser options. - */ -class Flattener { - constructor(stringifier = {}, parser = {}) { - this.stringifier = stringifier; - this.parser = parser; - } - /** - * Flattens the given object and converts it - * to a dept of 1 - * - * @param obj Object to be flattened - */ - flatten(obj) { - return this.traverse(obj, '', getDefaultResult()); - } - /** - * Unflattens the given object to its original - * format and also applies the necessary types - * that it originally had - * - * @param flattened Flattened object - */ - unflatten(flattened) { - const typedData = this.mergeTypes(flattened); - let result; - Object.entries(typedData).some(([key, val]) => { - // if the key is '', it means that - // the flattened object / array is empty - if (!key) { - if (Object.keys(typedData).length <= 1) { - result = val; - return true; - } - else { - // when the initial data is {'': {}} and - // later a prop is added to the same, then - // the data would be {'': {}, prop: {...}} - // hence we need to continue the loop when - // the keys.length > 1 - return false; - } - } - const splittedKeys = splitKey(key); - if (!result) { - result = typeof parseKey(splittedKeys[0]) === 'number' ? [] : {}; - } - this.scaffoldStructure(result, splittedKeys, val); - return false; - }); - return result; - } - /*********************************** - * PRIVATE METHODS - Flatten helpers - **********************************/ - traverse(target, basePath, result) { - if (!(target instanceof Object)) - return result; - if (Array.isArray(target)) { - result.arrayInfo[basePath] = true; - } - const entries = Object.entries(target); - if (entries.length > 0) { - entries.forEach(([key, val]) => { - const encodedKey = encodeKey(key); - const path = appendPath(basePath, encodedKey); - if (val instanceof Object) { - this.traverse(val, path, result); - } - else { - this.assignResult(result, path, val); - } - }); - } - else { - this.assignResult(result, basePath, target); - } - return result; - } - assignResult(result, path, val) { - if (!isSkippedType(val)) { - result.data[path] = getValueOf(val, this.stringifier); - result.typeInfo[path] = getTypeOf(val); - } - } - /************************************* - * PRIVATE METHODS - Unflatten helpers - *************************************/ - mergeTypes(result) { - const { data, typeInfo } = result; - return Object.entries(data).reduce((merged, [path, val]) => { - merged[path] = getTypedVal(typeInfo[path], val, this.parser); - return merged; - }, {}); - } - scaffoldStructure(tree, splittedKeys, val) { - // Loop until k1 has reached end of split - for (let i = 0, len = splittedKeys.length; i < len; i++) { - const k1 = parseKey(splittedKeys[i]); - const k2 = parseKey(splittedKeys[i + 1]); - if (typeof k2 === 'undefined') { - tree[k1] = val; - } - else { - const isObj = typeof tree[k1] === 'object'; - if (!isObj) - tree[k1] = typeof k2 === 'number' ? [] : {}; - tree = tree[k1]; - } - } - } -} -function appendPath(basePath, key) { - return basePath ? `${basePath}.${key}` : key; -} - -const Config = { - SCAN_COUNT: 100, -}; - -/** - * JSONCache eases the difficulties in storing a JSON in redis. - * - * It stores the JSON in hashset for simpler get and set of required - * fields. It also allows you to override/set specific fields in - * the JSON without rewriting the whole JSON tree. Which means that it - * is literally possible to `Object.deepAssign()`. - * - * Everytime you store an object, JSONCache would store two hashset - * in Redis, one for data and the other for type information. This helps - * during retrieval of data, to restore the type of data which was originally - * provided. All these workaround are needed because Redis DOES NOT support - * any other data type apart from String. - * - * Well the easiest way is to store an object in Redis is - * JSON.stringify(obj) and store the stringified result. - * But this can cause issue when the obj is - * too huge or when you would want to retrieve only specific fields - * from the JSON but do not want to parse the whole JSON. - * Also note that this method would end up in returing all the - * fields as strings and you would have no clue to identify the type of - * field. - */ -class JSONCache { - /** - * Intializes JSONCache instance - * @param redisClient RedisClient instance(Preferred ioredis - cient). - * It supports any redisClient instance that has - * `'hmset' | 'hmget' | 'hgetall' | 'expire' | 'del' | 'keys'` - * methods implemented - * @param options Options for controlling the prefix - */ - constructor(redisClient, options = {}) { - this.options = options; - this.options.prefix = typeof options.prefix === 'string' ? options.prefix : 'jc:'; - this.redisClientInt = { - hmset: util.promisify(redisClient.hmset).bind(redisClient), - hmget: util.promisify(redisClient.hmget).bind(redisClient), - hgetall: util.promisify(redisClient.hgetall).bind(redisClient), - expire: util.promisify(redisClient.expire).bind(redisClient), - del: util.promisify(redisClient.del).bind(redisClient), - scan: util.promisify(redisClient.scan).bind(redisClient), - hincrbyfloat: util.promisify(redisClient.hincrbyfloat).bind(redisClient), - multi: (commands) => { - return new Promise((resolve, reject) => { - redisClient.multi(commands).exec((err, results) => { - if (err) - reject(err); - else - resolve(results); - }); - }); - }, - }; - this.flattener = new Flattener(options.stringifier, options.parser); - } - /** - * Flattens the given json object and - * stores it in Redis hashset - * - * @param key Redis key - * @param obj JSON object to be stored - * @param options - */ - set(key, obj, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - const flattened = this.flattener.flatten(obj); - const commands = yield this.getKeysToBeRemoved(key, flattened); - this.addSetCommands(key, flattened, commands, options.expire); - yield this.execCommand(commands, options.transaction); - }); - } - get(key, ...fields) { - return __awaiter(this, void 0, void 0, function* () { - const [data, typeInfo] = yield Promise.all([ - this.redisClientInt.hgetall(this.getKey(key)), - this.redisClientInt.hgetall(this.getTypeKey(key)), - ]); - // Empty object is returned when - // the given key is not present - // in the cache - if (!(data && typeInfo)) { - return undefined; - } - const dataKeysLen = Object.keys(data).length; - const typeInfoKeysLen = Object.keys(typeInfo).length; - if (dataKeysLen !== typeInfoKeysLen || dataKeysLen === 0) - return undefined; - let result; - if (fields.length > 0) { - let dataKeys; - result = fields.reduce((res, field) => { - if (field in data) { - res.data[field] = data[field]; - res.typeInfo[field] = typeInfo[field]; - } - else { - const searchKey = `${field}.`; - (dataKeys || (dataKeys = Object.keys(data))).forEach(flattenedKey => { - if (flattenedKey.startsWith(searchKey)) { - res.data[flattenedKey] = data[flattenedKey]; - res.typeInfo[flattenedKey] = typeInfo[flattenedKey]; - } - }); - } - return res; - }, { data: {}, typeInfo: {} }); - } - else { - result = { data, typeInfo, arrayInfo: {} }; - } - return this.flattener.unflatten(result); - }); - } - /** - * Replace the entire hashset for the given key - * - * @param key Redis key - * @param obj JSON Object of type T - */ - rewrite(key, obj, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - const commands = [ - ['del', this.getKey(key)], - ['del', this.getTypeKey(key)], - ]; - const flattened = this.flattener.flatten(obj); - this.addSetCommands(key, flattened, commands, options.expire); - yield this.execCommand(commands, options.transaction); - }); - } - /** - * Removes/deletes all the keys in the JSON Cache, - * having the prefix. - */ - clearAll() { - return __awaiter(this, void 0, void 0, function* () { - let cursor = '0'; - let keys; - do { - [cursor, keys] = yield this.redisClientInt.scan(cursor, 'MATCH', `${this.options.prefix}*`, 'COUNT', Config.SCAN_COUNT); - if (keys.length > 0) { - yield this.redisClientInt.del(...keys); - } - } while (cursor !== '0'); - }); - } - /** - * Removes the given key from Redis - * - * Please use this method instead of - * directly using `redis.del` as this method - * ensures that even the corresponding type info - * is removed. It also ensures that prefix is - * added to key, ensuring no other key is - * removed unintentionally - * - * @param key Redis key - */ - del(key, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - const commands = [ - ['del', this.getKey(key)], - ['del', this.getTypeKey(key)], - ]; - yield this.execCommand(commands, options.transaction); - }); - } - /** - * Increments the value of a variable in the JSON - * Note: You can increment multiple variables in the - * same command (Internally it will split it into multiple - * commands on the RedisDB) - * - * @example - * ```JS - * await jsonCache.incr(key, {messages: 10, profile: {age: 1}}) - * ``` - * - * @param key Redis Cache key - * @param obj Partial object specifying the path to the required - * variable along with value - */ - incr(key, obj, options = {}) { - return __awaiter(this, void 0, void 0, function* () { - const flattened = this.flattener.flatten(obj); - const commands = []; - Object.entries(flattened.data).forEach(([path, incrVal]) => { - // This check is needed to avoid redis errors. - // It also helps while the user wants to increment the value - // within an array. - // Ex: rand: [null, null, 1] => this will increment the 3rd index by 1 - if (flattened.typeInfo[path] !== TYPE.NUMBER) { - return; - } - commands.push(['hincrbyfloat', this.getKey(key), path, incrVal]); - }); - yield this.execCommand(commands, options.transaction); - }); - } - /****************** - * PRIVATE METHODS - ******************/ - getKeysToBeRemoved(key, flattened) { - return __awaiter(this, void 0, void 0, function* () { - const commands = []; - // Check if the given obj has arrays and if it does - // then we must remove the current array stored in - // Cache and then set this array in the Cache - if (Object.keys(flattened.arrayInfo).length > 0) { - const currentObj = yield this.get(key); - if (currentObj) { - const currrentObjFlattened = this.flattener.flatten(currentObj).data; - const keysToBeRemoved = []; - // Get all paths matching the parent array path - Object.keys(flattened.arrayInfo).forEach(path => { - Object.keys(currrentObjFlattened).forEach(objPath => { - if (objPath.startsWith(path)) { - keysToBeRemoved.push(objPath); - } - }); - }); - if (keysToBeRemoved.length > 0) { - commands.push(['hdel', this.getKey(key), ...keysToBeRemoved]); - commands.push(['hdel', this.getTypeKey(key), ...keysToBeRemoved]); - } - } - } - return commands; - }); - } - /** - * Returns the redis storage key for storing data - * by prefixing custom string, such that it - * doesn't collide with other keys in usage - * - * @param key Storage key - */ - getKey(key) { - return `${this.options.prefix}${key}`; - } - /** - * Returns the redis storage key for storing - * corresponding types by prefixing custom string, - * such that it doesn't collide with other keys - * in usage - * - * @param key Storage key - */ - getTypeKey(key) { - return `${this.options.prefix}${key}_t`; - } - /** - * Will add Set commands to the given array - * This logic was separated to remove code duplication - * in set & rewrite methods - * - * @param key Storage key - * @param flattened Flattened object containing data & typeInfo - * @param commands List of commands to which set commands has to be appended - * @param expire Redis Key expiry - */ - addSetCommands(key, flattened, commands, expire) { - commands.push(['hmset', this.getKey(key), flattened.data]); - commands.push(['hmset', this.getTypeKey(key), flattened.typeInfo]); - if (expire) { - commands.push(['expire', this.getKey(key), expire]); - commands.push(['expire', this.getTypeKey(key), expire]); - } - return commands; - } - execTransactionCommands(commands, transaction) { - commands.forEach(command => { - const [action, ...args] = command; - transaction[action](...args); - }); - } - execCommand(commands, transaction) { - return __awaiter(this, void 0, void 0, function* () { - if (transaction) { - this.execTransactionCommands(commands, transaction); - return transaction; - } - else { - const result = yield this.redisClientInt.multi(commands); - return result; - } - }); - } -} - -module.exports = JSONCache; diff --git a/node_modules/redis-json/package.json b/node_modules/redis-json/package.json deleted file mode 100644 index ccd1387e..00000000 --- a/node_modules/redis-json/package.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "name": "redis-json", - "version": "6.0.3", - "description": "A wrapper library to store JSON Objects in redis-hashsets and retrieve it back as JSON objects", - "sideEffects": false, - "main": "lib/jsonCache.js", - "module": "es/jsonCache.js", - "typings": "types/src/index.d.ts", - "scripts": { - "_test": "cross-env TS_NODE_FILES=true mocha --require ts-node/register test/**/*.spec.ts", - "_test:exit": "npm run _test -- --exit", - "test": "cross-env NODE_ENV=test npm run _test:exit", - "test:dev": "cross-env NODE_ENV=test npm run _test -- --watch --watch-extensions ts", - "test:grep": "cross-env NODE_ENV=test npm run _test:exit -- -g ", - "coverage": "nyc npm run test", - "lint:fix": "tslint --fix --config tslint.json src/index.ts", - "lint": "tslint --config tslint.json src/index.ts", - "tsc:build": "tsc", - "rollup:build": "rollup -c", - "tsdoc": "typedoc", - "tsdoc:dev": "nodemon --watch src/ -e ts --exec 'npm run tsdoc'", - "build": "npm run tsc:build && npm run rollup:build && npm run tsdoc", - "pack": "npm run build && npm pack", - "status": "git status", - "coveralls": "npm run coverage && nyc report --reporter=text-lcov | coveralls" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/AkashBabu/redis-json.git" - }, - "engines": { - "node": ">=8.0.0" - }, - "keywords": [ - "redis", - "json", - "store", - "retrieve", - "save", - "insert", - "hashset" - ], - "precommit": [ - "lint:fix", - "coverage", - "build", - "status" - ], - "nyc": { - "extension": [ - ".ts" - ], - "exclude": [ - "**/*.d.ts" - ], - "include": [ - "src/**/*" - ] - }, - "author": "Akash Babu <001akashbabu@gmail.com>", - "license": "MIT", - "bugs": { - "url": "https://github.com/AkashBabu/redis-json/issues" - }, - "homepage": "https://github.com/AkashBabu/redis-json#readme", - "devDependencies": { - "@babel/core": "^7.7.2", - "@babel/preset-env": "^7.7.1", - "@babel/preset-typescript": "^7.7.2", - "@rollup/plugin-replace": "^2.2.1", - "@types/chai": "^4.2.3", - "@types/ioredis": "^4.17.4", - "@types/mocha": "^5.2.7", - "@types/node": "^12.7.12", - "@types/redis": "^2.8.27", - "chai": "^4.1.2", - "cli-progress": "^3.3.1", - "coveralls": "^3.0.6", - "cross-env": "^6.0.0", - "deep-equal": "^2.0.1", - "delay": "^4.3.0", - "gitbook-cli": "^2.3.2", - "ioredis": "^4.14.1", - "mocha": "^6.2.2", - "mocha-each": "^2.0.1", - "nodemon": "^2.0.4", - "nyc": "^15.0.0-beta.0", - "pre-commit": "^1.2.2", - "radargun": "^1.0.1", - "redis": "^3.0.2", - "rimraf": "^3.0.0", - "rollup": "^1.26.5", - "rollup-plugin-babel": "^4.3.3", - "rollup-plugin-commonjs": "^10.1.0", - "rollup-plugin-node-builtins": "^2.1.2", - "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-terser": "^5.1.2", - "rollup-plugin-typescript2": "^0.25.2", - "source-map-support": "^0.5.13", - "ts-node": "^8.0.2", - "tslint": "^5.20.0", - "typedoc": "^0.15.8", - "typedoc-plugin-markdown": "^2.2.17", - "typescript": "^3.6.4", - "wide-align": "^1.1.3" - } -} diff --git a/node_modules/redis-json/typedoc.js b/node_modules/redis-json/typedoc.js deleted file mode 100644 index eed08614..00000000 --- a/node_modules/redis-json/typedoc.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - "name": "redis-json", - "mode": "file", - "out": "docs/api", - "excludePrivate": true, - "excludeProtected": true, - excludeNotExported: true, - stripInternal: true, - "readme": "none", - "entryPoint": "./src/index.ts", - "exclude": [ - "./src/utils/type.ts", - "./src/utils/key.ts", - "./src/lib/Flattener.ts", - ], - ignoreCompilerErrors: true, -} \ No newline at end of file diff --git a/node_modules/redis-json/types/src/index.d.ts b/node_modules/redis-json/types/src/index.d.ts deleted file mode 100644 index 59bd337f..00000000 --- a/node_modules/redis-json/types/src/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import JSONCache from './lib/jsonCache'; -export default JSONCache; diff --git a/node_modules/redis-json/types/src/interfaces.d.ts b/node_modules/redis-json/types/src/interfaces.d.ts deleted file mode 100644 index 5cbf8ac5..00000000 --- a/node_modules/redis-json/types/src/interfaces.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @hidden - */ -export interface IObj { - [anyProp: string]: T; -} -/** - * @hidden - */ -export interface IResult { - data: IObj; - typeInfo: IObj; - arrayInfo: IObj; -} -/** - * @hidden - */ -export declare type RecursivePartial = { - [P in keyof T]?: T[P] extends any[] ? Array> : T[P] extends any ? RecursivePartial : T[P]; -}; diff --git a/node_modules/redis-json/types/src/lib/config.d.ts b/node_modules/redis-json/types/src/lib/config.d.ts deleted file mode 100644 index 8e0a238d..00000000 --- a/node_modules/redis-json/types/src/lib/config.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare const Config: { - SCAN_COUNT: number; -}; -export default Config; diff --git a/node_modules/redis-json/types/src/lib/flattener.d.ts b/node_modules/redis-json/types/src/lib/flattener.d.ts deleted file mode 100644 index 2a5cc82a..00000000 --- a/node_modules/redis-json/types/src/lib/flattener.d.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { IObj, IResult } from '../interfaces'; -import type { IStringifier, IParser } from './jsonCache.types'; -/** - * @internal - */ -export interface IFlattener { - flatten(obj: IObj): IResult; - unflatten(result: IResult): IObj; -} -/** - * @internal - * - * Class for flattening and unflattening an object / array - * - * This could've been a simple function but is rather a class - * because we are instantiating it during the constructor phase of - * JSONCache class by calling it with stringifier & parser options. - */ -export declare class Flattener implements IFlattener { - private stringifier; - private parser; - constructor(stringifier?: IStringifier, parser?: IParser); - /** - * Flattens the given object and converts it - * to a dept of 1 - * - * @param obj Object to be flattened - */ - flatten(obj: IObj): IResult; - /** - * Unflattens the given object to its original - * format and also applies the necessary types - * that it originally had - * - * @param flattened Flattened object - */ - unflatten(flattened: IResult): IObj; - /*********************************** - * PRIVATE METHODS - Flatten helpers - **********************************/ - private traverse; - private assignResult; - /************************************* - * PRIVATE METHODS - Unflatten helpers - *************************************/ - private mergeTypes; - private scaffoldStructure; -} diff --git a/node_modules/redis-json/types/src/lib/jsonCache.d.ts b/node_modules/redis-json/types/src/lib/jsonCache.d.ts deleted file mode 100644 index 7584fa26..00000000 --- a/node_modules/redis-json/types/src/lib/jsonCache.d.ts +++ /dev/null @@ -1,146 +0,0 @@ -import type { RecursivePartial } from '../interfaces'; -import type { IOptions, ISetOptions, IDelOptions } from './jsonCache.types'; -interface IJSONCache { - set(key: string, obj: T, options: ISetOptions): Promise; - get(key: string): Promise; - get(key: string, ...fields: string[]): Promise | undefined>; - rewrite(key: string, obj: T, options?: ISetOptions): Promise; - clearAll(): Promise; - del(key: string, options?: IDelOptions): Promise; - incr(key: string, obj: RecursivePartial, options?: IDelOptions): Promise; -} -/** - * JSONCache eases the difficulties in storing a JSON in redis. - * - * It stores the JSON in hashset for simpler get and set of required - * fields. It also allows you to override/set specific fields in - * the JSON without rewriting the whole JSON tree. Which means that it - * is literally possible to `Object.deepAssign()`. - * - * Everytime you store an object, JSONCache would store two hashset - * in Redis, one for data and the other for type information. This helps - * during retrieval of data, to restore the type of data which was originally - * provided. All these workaround are needed because Redis DOES NOT support - * any other data type apart from String. - * - * Well the easiest way is to store an object in Redis is - * JSON.stringify(obj) and store the stringified result. - * But this can cause issue when the obj is - * too huge or when you would want to retrieve only specific fields - * from the JSON but do not want to parse the whole JSON. - * Also note that this method would end up in returing all the - * fields as strings and you would have no clue to identify the type of - * field. - */ -export default class JSONCache implements IJSONCache { - private options; - private redisClientInt; - private flattener; - /** - * Intializes JSONCache instance - * @param redisClient RedisClient instance(Preferred ioredis - cient). - * It supports any redisClient instance that has - * `'hmset' | 'hmget' | 'hgetall' | 'expire' | 'del' | 'keys'` - * methods implemented - * @param options Options for controlling the prefix - */ - constructor(redisClient: any, options?: IOptions); - /** - * Flattens the given json object and - * stores it in Redis hashset - * - * @param key Redis key - * @param obj JSON object to be stored - * @param options - */ - set(key: string, obj: T, options?: ISetOptions): Promise; - /** - * Retrieves the hashset from redis and - * unflattens it back to the original Object - * - * @param key Redis key - * @param fields List of fields to be retreived from redis. - * This helps reduce network latency incase only a few fields are - * needed. - * - * @returns request object from the cache - */ - get(key: string): Promise; - get(key: string, ...fields: string[]): Promise | undefined>; - /** - * Replace the entire hashset for the given key - * - * @param key Redis key - * @param obj JSON Object of type T - */ - rewrite(key: string, obj: T, options?: ISetOptions): Promise; - /** - * Removes/deletes all the keys in the JSON Cache, - * having the prefix. - */ - clearAll(): Promise; - /** - * Removes the given key from Redis - * - * Please use this method instead of - * directly using `redis.del` as this method - * ensures that even the corresponding type info - * is removed. It also ensures that prefix is - * added to key, ensuring no other key is - * removed unintentionally - * - * @param key Redis key - */ - del(key: string, options?: IDelOptions): Promise; - /** - * Increments the value of a variable in the JSON - * Note: You can increment multiple variables in the - * same command (Internally it will split it into multiple - * commands on the RedisDB) - * - * @example - * ```JS - * await jsonCache.incr(key, {messages: 10, profile: {age: 1}}) - * ``` - * - * @param key Redis Cache key - * @param obj Partial object specifying the path to the required - * variable along with value - */ - incr(key: string, obj: RecursivePartial, options?: IDelOptions): Promise; - /****************** - * PRIVATE METHODS - ******************/ - private getKeysToBeRemoved; - /** - * Returns the redis storage key for storing data - * by prefixing custom string, such that it - * doesn't collide with other keys in usage - * - * @param key Storage key - */ - private getKey; - /** - * Returns the redis storage key for storing - * corresponding types by prefixing custom string, - * such that it doesn't collide with other keys - * in usage - * - * @param key Storage key - */ - private getTypeKey; - /** - * Will add Set commands to the given array - * This logic was separated to remove code duplication - * in set & rewrite methods - * - * @param key Storage key - * @param flattened Flattened object containing data & typeInfo - * @param commands List of commands to which set commands has to be appended - * @param expire Redis Key expiry - */ - private addSetCommands; - private execTransactionCommands; - private execCommand; -} -export {}; diff --git a/node_modules/redis-json/types/src/lib/jsonCache.types.d.ts b/node_modules/redis-json/types/src/lib/jsonCache.types.d.ts deleted file mode 100644 index c8b60eb2..00000000 --- a/node_modules/redis-json/types/src/lib/jsonCache.types.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -export declare type IPromisified = (...args: any[]) => Promise; -export declare type Methods = 'hmset' | 'hmget' | 'hgetall' | 'expire' | 'del' | 'scan' | 'hincrbyfloat'; -export declare type IMultiCommands = Array<[string, string, ...any[]]>; -export declare type IMulti = (commands: IMultiCommands) => Promise; -export declare type IRedisMethods = { - [K in Methods]: IPromisified; -} & { - multi: IMulti; -}; -export declare type IRedisClient = IRedisMethods; -export declare type Transaction = any; -export interface IDelOptions { - transaction?: Transaction; -} -export interface ISetOptions { - expire?: number; - transaction?: Transaction; -} -/** - * Stringifier will be used to convert a custom - * object to a string when `set` is called - */ -export interface IStringifier { - [constructorName: string]: (val: any) => string; -} -/** - * Parser will be used to convert the string - * back to custom object when `get` is called - */ -export interface IParser { - [constructorName: string]: (val: string) => any; -} -/** - * JSONCache options - */ -export interface IOptions { - /** - * Custom prefix to be used for storage - * namespace separation - */ - prefix?: string; - /** - * Stringifier will be used to convert a custom - * object to a string when `set` is called - */ - stringifier?: IStringifier; - /** - * Parser will be used to convert the string - * back to custom object when `get` is called - */ - parser?: IParser; -} diff --git a/node_modules/redis-json/types/src/utils/key.d.ts b/node_modules/redis-json/types/src/utils/key.d.ts deleted file mode 100644 index 5081d81b..00000000 --- a/node_modules/redis-json/types/src/utils/key.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Return the given key if it's a string else - * parses it into number - * - * @param key - * - * @returns a string if it cannot be parsed to a number - * else returns the parsed number - */ -export declare function parseKey(key: string): string | number; -/** - * Encapsulate '.' in the given key, such - * that a '.' in the key is NOT misinterpreted - * during unflattening of the object - * - * @param key - */ -export declare function encodeKey(key: string): string; -export declare const splitKey: (key: string) => string[]; diff --git a/node_modules/redis-json/types/src/utils/type.d.ts b/node_modules/redis-json/types/src/utils/type.d.ts deleted file mode 100644 index 87fe8b23..00000000 --- a/node_modules/redis-json/types/src/utils/type.d.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { IStringifier, IParser } from '../lib/jsonCache.types'; -export declare enum TYPE { - OBJECT = "0", - STRING = "1", - NUMBER = "2", - BOOLEAN = "3", - FUNCTION = "4", - UNDEFINED = "5", - SYMBOL = "6" -} -/** - * Returns true if the given value's - * type need to be skipped during storage. - * For ex: Symbol -> Since symbols are private, - * we DO NOT encourage them to be stored, hence - * we are skipping from storing the same. - * - * In case you've forked this library and want to - * add more type, then this is the place for you 🙂 - */ -export declare const isSkippedType: (val: any) => boolean; -/** - * Returns a shorter form of the type of the - * value that can be stored in redis. - * This also handles custom Classes by using - * their constructor names directly. - * - * @param val Value whose type needs to be computed - */ -export declare const getTypeOf: (val: any) => (TYPE | string); -/** - * Returns the stringified version of the given value. - * However note that this method needs to take care, - * such that special values like undefined, null, false, true - * etc are also stringified correctly for storage. - * - * In case of a custom class / object, this method would - * call the provided stringifier (if any available), else - * would use `String(val)` - * - * @param val Value to be evaluated - * @param stringifier Custom stringifiers - * - * @returns Stringified value. If null is returned, then such a value must NOT - * be stored - */ -export declare const getValueOf: (val: any, stringifier?: IStringifier) => string; -/** - * Converts the given value to the specified type. - * Also note that, if a custom className type is - * detected, then the provided custom Parser will - * be called (if any available), else will return - * the value as is. - */ -export declare const getTypedVal: (type: TYPE | string, val: string, parser?: IParser) => any; diff --git a/package-lock.json b/package-lock.json index 4c1b5a71..d9f934d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,8 +15,7 @@ "express": "^4.18.1", "inquirer": "^9.0.0", "ioredis": "^5.1.0", - "mysql2": "^2.3.3", - "redis-json": "^6.0.3" + "mysql2": "^2.3.3" } }, "node_modules/@ioredis/commands": { @@ -1332,14 +1331,6 @@ "node": ">=4" } }, - "node_modules/redis-json": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/redis-json/-/redis-json-6.0.3.tgz", - "integrity": "sha512-m3F9WZ/LhESHEpagSyW4oqmfja0bdW6W52wQJm4FHj8gA0b+f5sdlp9BIa6q5+XGDqX6y6wS9WcsEJhhvyLeSg==", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/redis-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", @@ -2672,11 +2663,6 @@ "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==" }, - "redis-json": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/redis-json/-/redis-json-6.0.3.tgz", - "integrity": "sha512-m3F9WZ/LhESHEpagSyW4oqmfja0bdW6W52wQJm4FHj8gA0b+f5sdlp9BIa6q5+XGDqX6y6wS9WcsEJhhvyLeSg==" - }, "redis-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", diff --git a/package.json b/package.json index 2b592ca2..5ff2bdcb 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "express": "^4.18.1", "inquirer": "^9.0.0", "ioredis": "^5.1.0", - "mysql2": "^2.3.3", - "redis-json": "^6.0.3" + "mysql2": "^2.3.3" } } diff --git a/site_config.sql b/site_config.sql index b9979b54..eeceb034 100644 --- a/site_config.sql +++ b/site_config.sql @@ -5,34 +5,43 @@ INSERT INTO `config`(`flag`, `value`) VALUES ("allowed_register","true"); INSERT INTO `config`(`flag`, `value`) VALUES ("allowed_login","true"); /*Variable Flags*/ -INSERT INTO `config`(`flag`, `value`) VALUES ("site_url",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("site_title",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("site_excerpt",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("site_logo",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_detect_method",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_detect_header",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("user_cookie_expire_after",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("admin_cookie_expire_after",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("mod_cookie_expire_after",""); +INSERT INTO `config`(`flag`, `value`) VALUES ("site_url","127.0.0.1"); +INSERT INTO `config`(`flag`, `value`) VALUES ("site_title","Yet another Blorum site."); +INSERT INTO `config`(`flag`, `value`) VALUES ("site_excerpt","This is a Blorum site, where you could publish blogs and chat."); +INSERT INTO `config`(`flag`, `value`) VALUES ("site_logo","/favicon.ico"); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_detect_method","raw_ip"); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_detect_header","X-Forwarded-From"); +INSERT INTO `config`(`flag`, `value`) VALUES ("user_cookie_expire_after","2630000"); +INSERT INTO `config`(`flag`, `value`) VALUES ("admin_cookie_expire_after","1315000"); +INSERT INTO `config`(`flag`, `value`) VALUES ("mod_cookie_expire_after","1315000"); -INSERT INTO `config`(`flag`, `value`) VALUES ("max_user_sessions",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("max_admin_sessions",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("max_mod_sessions",""); +INSERT INTO `config`(`flag`, `value`) VALUES ("max_user_sessions","8"); +INSERT INTO `config`(`flag`, `value`) VALUES ("max_admin_sessions","4"); +INSERT INTO `config`(`flag`, `value`) VALUES ("max_mod_sessions","6"); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_posts",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_register",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_react",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_comment",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_remove",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_articles",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_login",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_bypass_whitelist",""); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_posts","12"); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_register","1"); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_react","64"); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_comment","60"); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_remove",' +{ + "article": 12, + "posts": 12, + "react": 128, + "comment": 60 +}'); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_articles","12"); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_login","30"); +INSERT INTO `config`(`flag`, `value`) VALUES ("ip_rate_limit_bypass_whitelist","[127.0.0.1]"); -INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_posts",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_react",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_comment",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_remove",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_articles",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_remove",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_articles",""); -INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_login",""); \ No newline at end of file +INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_posts","12"); +INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_react","64"); +INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_comment","60"); +INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_remove",'{ + "article": 12, + "posts": 12, + "react": 128, + "comment": 60 +}'); +INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_articles","12"); +INSERT INTO `config`(`flag`, `value`) VALUES ("user_rate_limit_login","30"); \ No newline at end of file