Socket
Socket
Sign inDemoInstall

redis-rank

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

redis-rank - npm Package Compare versions

Comparing version 1.2.1 to 1.3.0

dist/Common.d.ts

3

dist/Leaderboard.d.ts

@@ -72,4 +72,5 @@ import { Redis, KeyType, Pipeline } from 'ioredis';

* Retrieve the top entries
* This function is an alias for list(1, max)
* @param max max number of entries to return
*
* Note: This function is an alias for list(1, max)
*/

@@ -76,0 +77,0 @@ top(max?: number): Promise<Entry[]>;

@@ -39,2 +39,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var Common_1 = require("./Common");
var Leaderboard = /** @class */ (function () {

@@ -206,4 +207,5 @@ /**

* Retrieve the top entries
* This function is an alias for list(1, max)
* @param max max number of entries to return
*
* Note: This function is an alias for list(1, max)
*/

@@ -265,17 +267,3 @@ Leaderboard.prototype.top = function (max) {

return [2 /*return*/, []];
return [4 /*yield*/, this.client.eval("local r=redis.call('z" + (this.options.lowToHigh ? '' : 'rev') + "rank',KEYS[1],ARGV[1])" +
"if r==false then return{0,{}} end " +
"local c=redis.call('zcard',KEYS[1])" +
"local l=math.max(0, r-ARGV[2])" +
(fillBorders ?
"local h=l+2*ARGV[2]" +
"if h>c then " +
"h=math.min(c, r+ARGV[2])" +
"l=math.max(0,h-2*ARGV[2]-1)" +
"end "
:
"local h=math.min(c, r+ARGV[2])") +
("return{l,redis.call('z" + (this.options.lowToHigh ? '' : 'rev') + "range',KEYS[1],l,h,'WITHSCORES')}"),
// 289 bytes vs 20 bytes using EVALSHA should consider it
1, this.options.path, id, distance)];
return [4 /*yield*/, this.client.eval(Common_1.buildScript("\n local range = aroundRange(KEYS[1], ARGV[1], ARGV[2], ARGV[3], ARGV[4]);\n if range[1] == -1 then return { 0, {} } end\n return {\n range[1],\n redis.call(ARGV[1] and 'zrange' or 'zrevrange', KEYS[1], range[1], range[2], 'WITHSCORES')\n }\n "), 1, this.options.path, this.isLowToHigh(), id, distance, fillBorders)];
case 1:

@@ -282,0 +270,0 @@ result = _a.sent();

@@ -30,2 +30,10 @@ import { Redis } from 'ioredis';

};
export declare type MatrixEntry = {
/** identifier */
id: ID;
/** ranking */
rank: number;
/** feature scores */
[feature: string]: ID | number;
};
export declare class LeaderboardMatrix {

@@ -64,2 +72,38 @@ /** ioredis client */

}, dimensions?: string[]): Promise<void>;
/**
* Retrieve an entry from the leaderboard
*
* @param feature only provide feature if you need the entry to be ranked
*/
peek(id: ID, dimension: string, feature?: string): Promise<MatrixEntry | null>;
/**
* Retrieve the entries ranked between some boundaries (one-based)
*
* @param low lower bound to query (inclusive)
* @param high higher bound to query (inclusive)
*/
list(dimension: string, feature: string, low: number, high: number): Promise<MatrixEntry[]>;
/**
* Retrieve the top entries
* @param max max number of entries to return
*
* Note: This function is an alias for list(1, max)
*/
top(dimension: string, feature: string, max?: number): Promise<MatrixEntry[]>;
/**
* Retrieve the entries around an entry
*
* @param distance number of entries at each side of the queried entry
* @param fillBorders include entries at the other side if the entry is too close to one of the borders.
*
* @see Leaderboard.around for details
*/
around(dimension: string, feature: string, id: ID, distance: number, fillBorders?: boolean): Promise<MatrixEntry[]>;
/**
* Parses the result of the lua function 'retrieveEntries'
*
* @param data from retrieveEntries
* @param low rank of the first entry
*/
private parseEntries;
}
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var PeriodicLeaderboard_1 = require("./PeriodicLeaderboard");
var Common_1 = require("./Common");
var LeaderboardMatrix = /** @class */ (function () {

@@ -82,4 +119,118 @@ function LeaderboardMatrix(client, options) {

};
/**
* Retrieve an entry from the leaderboard
*
* @param feature only provide feature if you need the entry to be ranked
*/
LeaderboardMatrix.prototype.peek = function (id, dimension, feature) {
return __awaiter(this, void 0, void 0, function () {
var list, result, entry;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!feature) return [3 /*break*/, 2];
return [4 /*yield*/, this.around(dimension, feature, id, 1, false)];
case 1:
list = _a.sent();
return [2 /*return*/, list.length == 0 ? null : list[0]];
case 2:
// else, only query the features across the dimension
if (this.options.dimensions.find(function (dim) { return dim.name === dimension; }) === undefined)
return [2 /*return*/, null];
return [4 /*yield*/, this.client.eval(Common_1.buildScript("\n return retrieveEntry(ARGV[1], KEYS)\n "), this.options.features.length, this.options.features.map(function (f) { return _this.get(dimension, f.name).getPath(); }), id)];
case 3:
result = _a.sent();
if (result.every(function (e) { return e === null; }))
return [2 /*return*/, null];
entry = { id: id, rank: 0 };
this.options.features.map(function (f, f_i) {
entry[f.name] = parseInt(result[f_i], 10);
});
return [2 /*return*/, entry];
}
});
});
};
/**
* Retrieve the entries ranked between some boundaries (one-based)
*
* @param low lower bound to query (inclusive)
* @param high higher bound to query (inclusive)
*/
LeaderboardMatrix.prototype.list = function (dimension, feature, low, high) {
return __awaiter(this, void 0, void 0, function () {
var lb, result;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
lb = this.get(dimension, feature);
if (!lb)
return [2 /*return*/, []];
return [4 /*yield*/, this.client.eval(Common_1.buildScript("\n return retrieveEntries(KEYS[1], ARGV[1], slice(KEYS, 2, ARGV[2]+1), ARGV[3], ARGV[4])\n "), this.options.features.length + 1, lb.getPath(), this.options.features.map(function (f) { return _this.get(dimension, f.name).getPath(); }), lb.isLowToHigh(), this.options.features.length, low - 1, high - 1)];
case 1:
result = _a.sent();
return [2 /*return*/, this.parseEntries(result, low)];
}
});
});
};
/**
* Retrieve the top entries
* @param max max number of entries to return
*
* Note: This function is an alias for list(1, max)
*/
LeaderboardMatrix.prototype.top = function (dimension, feature, max) {
if (max === void 0) { max = 10; }
return this.list(dimension, feature, 1, max);
};
/**
* Retrieve the entries around an entry
*
* @param distance number of entries at each side of the queried entry
* @param fillBorders include entries at the other side if the entry is too close to one of the borders.
*
* @see Leaderboard.around for details
*/
LeaderboardMatrix.prototype.around = function (dimension, feature, id, distance, fillBorders) {
if (fillBorders === void 0) { fillBorders = false; }
return __awaiter(this, void 0, void 0, function () {
var lb, result;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
lb = this.get(dimension, feature);
if (!lb)
return [2 /*return*/, []];
if (distance < 0)
return [2 /*return*/, []];
return [4 /*yield*/, this.client.eval(Common_1.buildScript("\n local range = aroundRange(KEYS[1], ARGV[1], ARGV[2], ARGV[3], ARGV[4]);\n if range[1] == -1 then return { {}, { {},{} } } end\n return {\n range[1],\n retrieveEntries(KEYS[1], ARGV[1], slice(KEYS, 2, ARGV[5]+1), range[1], range[2])\n }\n "), this.options.features.length + 1, lb.getPath(), this.options.features.map(function (f) { return _this.get(dimension, f.name).getPath(); }), lb.isLowToHigh(), id, distance, fillBorders, this.options.features.length)];
case 1:
result = _a.sent();
return [2 /*return*/, this.parseEntries(result[1], parseInt(result[0], 10) + 1)];
}
});
});
};
/**
* Parses the result of the lua function 'retrieveEntries'
*
* @param data from retrieveEntries
* @param low rank of the first entry
*/
LeaderboardMatrix.prototype.parseEntries = function (result, low) {
var _this = this;
return result[0].map(function (id, index) {
var entry = { id: id, rank: low + index };
_this.options.features.map(function (f, f_i) {
entry[f.name] = parseInt(result[1][f_i][index], 10);
});
return entry;
});
};
return LeaderboardMatrix;
}());
exports.LeaderboardMatrix = LeaderboardMatrix;
{
"name": "redis-rank",
"version": "1.2.1",
"version": "1.3.0",
"description": "Back-end to generate and manage leaderboards using Redis. Written in TypeScript and Promise-based.",

@@ -28,3 +28,3 @@ "keywords": [

"scripts": {
"build": "tsc",
"build": "tsc && cpx src/common.lua dist",
"prepare": "npm run test && npm run build",

@@ -39,2 +39,3 @@ "test": "jest --coverage --verbose --runInBand",

"codecov": "^3.6.1",
"cpx": "^1.5.0",
"jest": "^24.9.0",

@@ -41,0 +42,0 @@ "nodemon": "^1.19.4",

@@ -221,2 +221,16 @@ # redis-rank

To list entries within the matrix, yo can use `top` and `around` based on a dimension like this:
```javascript
lm.top('weekly', 'kills', 3);
// example
[
{ id: 'pepe', rank: 1, kills: 36, coins: 92, time: 342 },
{ id: '....', rank: 2, kills: 27, coins: 123, time: 295 },
{ id: '....', rank: 3, kills: 16, coins: 77, time: 420 }
]
// also
lm.around('monthly', 'time', pepe, 15);
```
To access a single leaderboard you can use the `get` function:

@@ -223,0 +237,0 @@ ```javascript

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc