@levrbet/shared 0.2.81 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/config/urls.js +4 -4
- package/dist/core/config/urls.js.map +1 -1
- package/dist/core/utils/game.utils.d.ts +2 -0
- package/dist/core/utils/game.utils.js +69 -1
- package/dist/core/utils/game.utils.js.map +1 -1
- package/dist/server/oracle/config/game-periods/providers/lsports.periods.js +3 -3
- package/dist/server/oracle/config/game-periods/providers/lsports.periods.js.map +1 -1
- package/dist/server/oracle/config/game-periods/providers/optic-odds.periods.d.ts +4 -27
- package/dist/server/oracle/config/game-periods/providers/optic-odds.periods.js +4 -27
- package/dist/server/oracle/config/game-periods/providers/optic-odds.periods.js.map +1 -1
- package/dist/server/oracle/config/game-periods/sports.config.js +8 -65
- package/dist/server/oracle/config/game-periods/sports.config.js.map +1 -1
- package/dist/server/oracle/config/game-periods/types.d.ts +2 -5
- package/dist/server/oracle/config/game-periods/types.js +0 -1
- package/dist/server/oracle/config/game-periods/types.js.map +1 -1
- package/dist/server/oracle/redis-cache-manager/cache.keys.utils.d.ts +45 -74
- package/dist/server/oracle/redis-cache-manager/cache.keys.utils.js +65 -120
- package/dist/server/oracle/redis-cache-manager/cache.keys.utils.js.map +1 -1
- package/dist/server/oracle/redis-cache-manager/game.query.engine.d.ts +90 -0
- package/dist/server/oracle/redis-cache-manager/game.query.engine.js +436 -0
- package/dist/server/oracle/redis-cache-manager/game.query.engine.js.map +1 -0
- package/dist/server/oracle/redis-cache-manager/index.d.ts +2 -3
- package/dist/server/oracle/redis-cache-manager/index.js +2 -3
- package/dist/server/oracle/redis-cache-manager/index.js.map +1 -1
- package/dist/server/oracle/redis-cache-manager/market.query.engine.d.ts +50 -97
- package/dist/server/oracle/redis-cache-manager/market.query.engine.js +310 -467
- package/dist/server/oracle/redis-cache-manager/market.query.engine.js.map +1 -1
- package/dist/server/oracle/types/providers/game-clock/index.d.ts +1 -1
- package/dist/server/oracle/types/providers/game-clock/index.js +1 -1
- package/dist/server/oracle/types/providers/game-clock/index.js.map +1 -1
- package/dist/server/{utils/game_progress → oracle/types/providers/game-clock}/parser.d.ts +7 -1
- package/dist/server/{utils/game_progress → oracle/types/providers/game-clock}/parser.js +13 -2
- package/dist/server/oracle/types/providers/game-clock/parser.js.map +1 -0
- package/dist/server/utils/index.d.ts +0 -1
- package/dist/server/utils/index.js +0 -1
- package/dist/server/utils/index.js.map +1 -1
- package/package.json +5 -4
- package/scripts/setup-prisma.js +0 -0
- package/dist/server/oracle/redis-cache-manager/game.cache.service.d.ts +0 -185
- package/dist/server/oracle/redis-cache-manager/game.cache.service.js +0 -712
- package/dist/server/oracle/redis-cache-manager/game.cache.service.js.map +0 -1
- package/dist/server/oracle/redis-cache-manager/game.progress.d.ts +0 -4
- package/dist/server/oracle/redis-cache-manager/game.progress.js +0 -27
- package/dist/server/oracle/redis-cache-manager/game.progress.js.map +0 -1
- package/dist/server/oracle/redis-cache-manager/market.cache.service.d.ts +0 -87
- package/dist/server/oracle/redis-cache-manager/market.cache.service.js +0 -139
- package/dist/server/oracle/redis-cache-manager/market.cache.service.js.map +0 -1
- package/dist/server/utils/game_progress/caclulate.game.progress.d.ts +0 -6
- package/dist/server/utils/game_progress/caclulate.game.progress.js +0 -96
- package/dist/server/utils/game_progress/caclulate.game.progress.js.map +0 -1
- package/dist/server/utils/game_progress/game.utils.d.ts +0 -2
- package/dist/server/utils/game_progress/game.utils.js +0 -65
- package/dist/server/utils/game_progress/game.utils.js.map +0 -1
- package/dist/server/utils/game_progress/index.d.ts +0 -5
- package/dist/server/utils/game_progress/index.js +0 -84
- package/dist/server/utils/game_progress/index.js.map +0 -1
- package/dist/server/utils/game_progress/parser.js.map +0 -1
|
@@ -3,71 +3,153 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.getLatestOdds = exports.addOddsToOddsCache = exports.getOddsList = exports.getMarketDataCacheWithOdds = exports.getMultipleMarketsWithOdds = exports.getGameMarketsWithOdds = exports.getGameMarkets = exports.updateMarketCache = exports.dropMarketIndex = exports.createMarketIndex = void 0;
|
|
7
7
|
const winston_1 = __importDefault(require("../../config/winston"));
|
|
8
8
|
const cache_keys_utils_1 = require("./cache.keys.utils");
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param gameUniqueId - Unique game identifier
|
|
13
|
-
* @param marketType - Market type
|
|
14
|
-
* @param limit - Number of latest odds to return (from the end)
|
|
15
|
-
* @returns Array of Odds objects
|
|
10
|
+
* Redis Query Engine using RediSearch
|
|
11
|
+
* Provides advanced querying capabilities for markets and odds using Prisma types
|
|
16
12
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
13
|
+
// Schema versioning for index migration
|
|
14
|
+
const MARKET_INDEX_SCHEMA_VERSION = 1;
|
|
15
|
+
const MARKET_INDEX_SCHEMA = [
|
|
16
|
+
"objectId",
|
|
17
|
+
"TAG",
|
|
18
|
+
"chainId",
|
|
19
|
+
"NUMERIC",
|
|
20
|
+
"gameId",
|
|
21
|
+
"NUMERIC",
|
|
22
|
+
"levrMarketId",
|
|
23
|
+
"TAG",
|
|
24
|
+
"gameMarketId",
|
|
25
|
+
"TAG",
|
|
26
|
+
"isMatured",
|
|
27
|
+
"TAG",
|
|
28
|
+
"marketType",
|
|
29
|
+
"TAG",
|
|
30
|
+
"status",
|
|
31
|
+
"TAG",
|
|
32
|
+
"winner",
|
|
33
|
+
"TAG",
|
|
34
|
+
"levrGameObjectId",
|
|
35
|
+
"TAG",
|
|
36
|
+
];
|
|
37
|
+
// Pipeline batch size to prevent memory issues
|
|
38
|
+
const PIPELINE_BATCH_SIZE = 500;
|
|
39
|
+
/**
|
|
40
|
+
* Validate if existing index schema matches expected schema
|
|
41
|
+
*/
|
|
42
|
+
const validateIndexSchema = (indexInfo) => {
|
|
43
|
+
const attributesIndex = indexInfo.indexOf("attributes");
|
|
44
|
+
if (attributesIndex === -1)
|
|
45
|
+
return false;
|
|
46
|
+
const attributes = indexInfo[attributesIndex + 1];
|
|
47
|
+
if (!Array.isArray(attributes))
|
|
48
|
+
return false;
|
|
49
|
+
// Check if schema has expected number of fields
|
|
50
|
+
const expectedFieldCount = MARKET_INDEX_SCHEMA.length / 2;
|
|
51
|
+
if (attributes.length !== expectedFieldCount)
|
|
52
|
+
return false;
|
|
53
|
+
return true;
|
|
33
54
|
};
|
|
34
|
-
exports.getOddsList = getOddsList;
|
|
35
55
|
/**
|
|
36
|
-
*
|
|
37
|
-
* Uses simple hash operations instead of full-text search indexing
|
|
56
|
+
* Helper to safely get value from Record
|
|
38
57
|
*/
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const market = JSON.parse(marketJson || "");
|
|
47
|
-
return market;
|
|
48
|
-
}
|
|
49
|
-
catch (e) {
|
|
50
|
-
winston_1.default.warn("Failed to parse market from fallback search", e);
|
|
51
|
-
}
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
winston_1.default.error("Error in market fallback search", error);
|
|
58
|
+
const get = (obj, key) => obj[key] ?? "";
|
|
59
|
+
/**
|
|
60
|
+
* Reconstruct a Market object from Redis hash fields
|
|
61
|
+
*/
|
|
62
|
+
const reconstructMarketFromFields = (fields) => {
|
|
63
|
+
const objectId = get(fields, "objectId");
|
|
64
|
+
if (!objectId)
|
|
56
65
|
return null;
|
|
66
|
+
const marketDetailsJson = get(fields, "marketDetailsJson");
|
|
67
|
+
const marketRiskAllocationJson = get(fields, "marketRiskAllocationJson");
|
|
68
|
+
const providersJson = get(fields, "providersJson");
|
|
69
|
+
const activeProviderJson = get(fields, "activeProviderJson");
|
|
70
|
+
const winner = get(fields, "winner");
|
|
71
|
+
return {
|
|
72
|
+
objectId,
|
|
73
|
+
chainId: Number.parseInt(get(fields, "chainId"), 10) || 0,
|
|
74
|
+
gameId: Number.parseInt(get(fields, "gameId"), 10) || 0,
|
|
75
|
+
levrMarketId: get(fields, "levrMarketId"),
|
|
76
|
+
levrMarketContract: get(fields, "levrMarketContract"),
|
|
77
|
+
gameMarketId: get(fields, "gameMarketId"),
|
|
78
|
+
txHash: get(fields, "txHash"),
|
|
79
|
+
maturedAt: get(fields, "maturedAt") ? new Date(Number.parseInt(get(fields, "maturedAt"), 10)) : null,
|
|
80
|
+
leveraged: get(fields, "leveraged") === "1",
|
|
81
|
+
isMatured: get(fields, "isMatured") === "1",
|
|
82
|
+
normalizationFactor: Number.parseFloat(get(fields, "normalizationFactor")) || 0,
|
|
83
|
+
marketType: get(fields, "marketType"),
|
|
84
|
+
status: get(fields, "status"),
|
|
85
|
+
winner: winner || null,
|
|
86
|
+
levrGameObjectId: get(fields, "levrGameObjectId"),
|
|
87
|
+
createdAt: new Date(Number.parseInt(get(fields, "createdAt"), 10) || 0),
|
|
88
|
+
updatedAt: new Date(Number.parseInt(get(fields, "updatedAt"), 10) || 0),
|
|
89
|
+
marketDetails: marketDetailsJson ? JSON.parse(marketDetailsJson) : null,
|
|
90
|
+
marketRiskAllocation: marketRiskAllocationJson ? JSON.parse(marketRiskAllocationJson) : null,
|
|
91
|
+
providers: providersJson ? JSON.parse(providersJson) : [],
|
|
92
|
+
activeProvider: activeProviderJson ? JSON.parse(activeProviderJson) : null,
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
// ============================================================================
|
|
96
|
+
// INDEX MANAGEMENT
|
|
97
|
+
// ============================================================================
|
|
98
|
+
/**
|
|
99
|
+
* Create market index with proper schema and versioning
|
|
100
|
+
* Validates existing index schema and recreates if mismatched
|
|
101
|
+
*/
|
|
102
|
+
const createMarketIndex = async (redis) => {
|
|
103
|
+
const indexInfo = await redis.call("FT.INFO", cache_keys_utils_1.market_index_name).catch(() => null);
|
|
104
|
+
if (indexInfo && Array.isArray(indexInfo)) {
|
|
105
|
+
// Validate existing index schema
|
|
106
|
+
if (validateIndexSchema(indexInfo)) {
|
|
107
|
+
winston_1.default.info(`Index ${cache_keys_utils_1.market_index_name} already exists with correct schema (v${MARKET_INDEX_SCHEMA_VERSION})`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// Schema mismatch - drop and recreate
|
|
111
|
+
winston_1.default.warn(`Index ${cache_keys_utils_1.market_index_name} schema mismatch - recreating...`);
|
|
112
|
+
await redis.call("FT.DROPINDEX", cache_keys_utils_1.market_index_name).catch(() => null);
|
|
57
113
|
}
|
|
114
|
+
// Create new index with correct schema
|
|
115
|
+
await redis.call("FT.CREATE", cache_keys_utils_1.market_index_name, "ON", "HASH", "PREFIX", "1", cache_keys_utils_1.levrMarketsHashKey, "SCHEMA", ...MARKET_INDEX_SCHEMA);
|
|
116
|
+
winston_1.default.info(`Created index: ${cache_keys_utils_1.market_index_name} (v${MARKET_INDEX_SCHEMA_VERSION})`);
|
|
58
117
|
};
|
|
59
|
-
exports.
|
|
118
|
+
exports.createMarketIndex = createMarketIndex;
|
|
60
119
|
/**
|
|
61
|
-
*
|
|
120
|
+
* Drop market search index
|
|
62
121
|
* @param redis - Redis client instance
|
|
63
|
-
* @param market - Array of Market objects to cache
|
|
64
122
|
*/
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
123
|
+
const dropMarketIndex = async (redis) => {
|
|
124
|
+
const indices = [cache_keys_utils_1.market_index_name];
|
|
125
|
+
for (const idx of indices) {
|
|
126
|
+
await redis.call("FT.DROPINDEX", idx).catch(() => {
|
|
127
|
+
winston_1.default.warn(`Index ${idx} does not exist`);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
winston_1.default.info("Dropped market index");
|
|
131
|
+
};
|
|
132
|
+
exports.dropMarketIndex = dropMarketIndex;
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// CACHE MANAGEMENT
|
|
135
|
+
// ============================================================================
|
|
136
|
+
/**
|
|
137
|
+
* Add markets to cache with RediSearch indexing
|
|
138
|
+
* @param redis - Redis client instance
|
|
139
|
+
* @param markets - Array of Market objects to cache
|
|
140
|
+
* @returns Result object with success/failed counts
|
|
141
|
+
*/
|
|
142
|
+
const updateMarketCache = async (redis, markets) => {
|
|
143
|
+
if (markets.length === 0) {
|
|
144
|
+
return { success: 0, failed: 0, total: 0 };
|
|
145
|
+
}
|
|
146
|
+
let success = 0;
|
|
147
|
+
let failed = 0;
|
|
148
|
+
// Process in batches to prevent memory issues
|
|
149
|
+
for (let i = 0; i < markets.length; i += PIPELINE_BATCH_SIZE) {
|
|
150
|
+
const batch = markets.slice(i, i + PIPELINE_BATCH_SIZE);
|
|
68
151
|
const pipeline = redis.pipeline();
|
|
69
|
-
|
|
70
|
-
for (const m of market) {
|
|
152
|
+
for (const m of batch) {
|
|
71
153
|
const key = (0, cache_keys_utils_1.getMarketKeyWithGameUniqueIdMarketType)(m.levrGameObjectId, m.marketType);
|
|
72
154
|
pipeline.hset(key, {
|
|
73
155
|
objectId: m.objectId,
|
|
@@ -77,13 +159,13 @@ const updateMarketCache = async (redis, market) => {
|
|
|
77
159
|
levrMarketContract: m.levrMarketContract,
|
|
78
160
|
gameMarketId: m.gameMarketId,
|
|
79
161
|
txHash: m.txHash,
|
|
80
|
-
maturedAt: m.maturedAt ? m.maturedAt.getTime().toString() : "
|
|
162
|
+
maturedAt: m.maturedAt ? m.maturedAt.getTime().toString() : "",
|
|
81
163
|
leveraged: m.leveraged ? "1" : "0",
|
|
82
164
|
isMatured: m.isMatured ? "1" : "0",
|
|
83
165
|
normalizationFactor: m.normalizationFactor.toString(),
|
|
84
166
|
marketType: m.marketType,
|
|
85
167
|
status: m.status,
|
|
86
|
-
winner: m.winner
|
|
168
|
+
winner: m.winner ?? "",
|
|
87
169
|
levrGameObjectId: m.levrGameObjectId,
|
|
88
170
|
createdAt: m.createdAt.getTime().toString(),
|
|
89
171
|
updatedAt: m.updatedAt.getTime().toString(),
|
|
@@ -91,484 +173,245 @@ const updateMarketCache = async (redis, market) => {
|
|
|
91
173
|
marketRiskAllocationJson: typeof m.marketRiskAllocation === "string" ? m.marketRiskAllocation : JSON.stringify(m.marketRiskAllocation),
|
|
92
174
|
providersJson: typeof m.providers === "string" ? m.providers : JSON.stringify(m.providers),
|
|
93
175
|
activeProviderJson: typeof m.activeProvider === "string" ? m.activeProvider : JSON.stringify(m.activeProvider),
|
|
94
|
-
market_json: JSON.stringify(m),
|
|
95
176
|
});
|
|
96
177
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Create market index with proper schema
|
|
110
|
-
*/
|
|
111
|
-
const createMarketIndex = async (redis) => {
|
|
112
|
-
try {
|
|
113
|
-
// Check if index already exists
|
|
114
|
-
const indexExists = await redis.call("FT.INFO", cache_keys_utils_1.market_index_name).catch(() => null);
|
|
115
|
-
if (indexExists) {
|
|
116
|
-
winston_1.default.info(`Index ${cache_keys_utils_1.market_index_name} already exists`);
|
|
117
|
-
return;
|
|
178
|
+
const results = await pipeline.exec();
|
|
179
|
+
if (results) {
|
|
180
|
+
for (const [err] of results) {
|
|
181
|
+
if (err) {
|
|
182
|
+
failed++;
|
|
183
|
+
winston_1.default.error("Pipeline command failed", err);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
success++;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
118
189
|
}
|
|
119
|
-
// Create new index with correct prefix (only if doesn't exist)
|
|
120
|
-
await redis.call("FT.CREATE", cache_keys_utils_1.market_index_name, "ON", "HASH", "PREFIX", "1", "markets_unique_id:", "SCHEMA", "objectId", "TEXT", "chainId", "NUMERIC", "gameId", "NUMERIC", "levrMarketId", "TEXT", "levrMarketContract", "TEXT", "gameMarketId", "TEXT", "txHash", "TEXT", "maturedAt", "NUMERIC", "leveraged", "NUMERIC", "isMatured", "NUMERIC", "normalizationFactor", "NUMERIC", "marketType", "TAG", "status", "TAG", "winner", "TAG", "levrGameObjectId", "TEXT", "createdAt", "NUMERIC", "updatedAt", "NUMERIC");
|
|
121
|
-
winston_1.default.info(`Created index: ${cache_keys_utils_1.market_index_name}`);
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
winston_1.default.error(`Error creating market index`, error);
|
|
125
|
-
throw error;
|
|
126
190
|
}
|
|
191
|
+
winston_1.default.info(`Updated markets in cache: ${success} success, ${failed} failed`);
|
|
192
|
+
return { success, failed, total: markets.length };
|
|
127
193
|
};
|
|
128
|
-
exports.
|
|
194
|
+
exports.updateMarketCache = updateMarketCache;
|
|
129
195
|
/**
|
|
130
|
-
*
|
|
131
|
-
* @param redis - Redis client instance
|
|
196
|
+
* Escape special characters for RediSearch TAG field queries
|
|
132
197
|
*/
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const indexExists = await redis.call("FT.INFO", indexName).catch(() => null);
|
|
137
|
-
if (indexExists) {
|
|
138
|
-
winston_1.default.info("Odds list index already exists");
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
await redis.call("FT.CREATE", indexName, "ON", "HASH", "PREFIX", "1", "game_to_market_ids_of_odds_in_cache_", "SCHEMA", "gameMarketId", "TEXT", "marketType", "TAG", "levrGameObjectId", "TEXT");
|
|
142
|
-
winston_1.default.info(`Created odds list index: ${indexName}`);
|
|
143
|
-
}
|
|
144
|
-
catch (error) {
|
|
145
|
-
winston_1.default.error("Error creating odds list index", error);
|
|
146
|
-
}
|
|
198
|
+
const escapeTagValue = (value) => {
|
|
199
|
+
// Escape special chars: , . < > { } [ ] " ' : ; ! @ # $ % ^ & * ( ) - + = ~
|
|
200
|
+
return value.replace(/[,.<>{}[\]"':;!@#$%^&*()\-+=~|]/g, "\\$&");
|
|
147
201
|
};
|
|
148
|
-
exports.createOddsIndex = createOddsIndex;
|
|
149
202
|
/**
|
|
150
|
-
*
|
|
203
|
+
* Get markets using RediSearch query engine
|
|
151
204
|
* @param redis - Redis client instance
|
|
152
205
|
* @param params - Search parameters
|
|
153
|
-
* @returns
|
|
206
|
+
* @returns Search result with markets array and total count
|
|
154
207
|
*/
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
208
|
+
const getGameMarkets = async (redis, params) => {
|
|
209
|
+
const { gameId, levrGameObjectId, marketType, status, isMatured, chainId, limit, offset } = params;
|
|
210
|
+
const filters = [];
|
|
211
|
+
if (marketType) {
|
|
212
|
+
filters.push(`@marketType:{${escapeTagValue(marketType)}}`);
|
|
213
|
+
}
|
|
214
|
+
if (status) {
|
|
215
|
+
filters.push(`@status:{${escapeTagValue(status)}}`);
|
|
216
|
+
}
|
|
217
|
+
if (gameId !== undefined) {
|
|
218
|
+
filters.push(`@gameId:[${gameId} ${gameId}]`);
|
|
219
|
+
}
|
|
220
|
+
if (chainId !== undefined) {
|
|
221
|
+
filters.push(`@chainId:[${chainId} ${chainId}]`);
|
|
222
|
+
}
|
|
223
|
+
if (isMatured !== undefined) {
|
|
224
|
+
filters.push(`@isMatured:{${isMatured ? "1" : "0"}}`);
|
|
225
|
+
}
|
|
226
|
+
if (levrGameObjectId) {
|
|
227
|
+
filters.push(`@levrGameObjectId:{${escapeTagValue(levrGameObjectId)}}`);
|
|
228
|
+
}
|
|
229
|
+
const query = filters.length ? filters.join(" ") : "*";
|
|
230
|
+
// Only add LIMIT if limit is specified
|
|
231
|
+
let result;
|
|
232
|
+
if (limit !== undefined) {
|
|
233
|
+
const offset_ = offset ?? 0;
|
|
234
|
+
result = await redis.call("FT.SEARCH", cache_keys_utils_1.market_index_name, query, "LIMIT", offset_, limit);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
result = await redis.call("FT.SEARCH", cache_keys_utils_1.market_index_name, query);
|
|
238
|
+
}
|
|
239
|
+
if (!Array.isArray(result) || result.length === 0) {
|
|
240
|
+
return { markets: [], total: 0 };
|
|
241
|
+
}
|
|
242
|
+
const total = typeof result[0] === "number" ? result[0] : 0;
|
|
243
|
+
const items = result.slice(1);
|
|
244
|
+
const markets = [];
|
|
245
|
+
// Process results: [count, key1, [fields1], key2, [fields2], ...]
|
|
246
|
+
for (let i = 0; i < items.length; i += 2) {
|
|
247
|
+
const fieldsArray = items[i + 1];
|
|
248
|
+
if (!Array.isArray(fieldsArray))
|
|
249
|
+
continue;
|
|
250
|
+
// Convert fields array to object
|
|
251
|
+
const fields = {};
|
|
252
|
+
for (let j = 0; j < fieldsArray.length; j += 2) {
|
|
253
|
+
const key = fieldsArray[j];
|
|
254
|
+
const value = fieldsArray[j + 1];
|
|
255
|
+
fields[key] = value;
|
|
204
256
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return [];
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
exports.searchMarkets = searchMarkets;
|
|
213
|
-
/**
|
|
214
|
-
* Get market by game unique ID and market type directly from hash
|
|
215
|
-
* @param redis - Redis client instance
|
|
216
|
-
* @param gameUniqueId - Unique game identifier
|
|
217
|
-
* @param marketType - Market type
|
|
218
|
-
* @returns Market object or null if not found
|
|
219
|
-
*/
|
|
220
|
-
const getMarketByGameAndType = async (redis, gameUniqueId, marketType) => {
|
|
221
|
-
try {
|
|
222
|
-
const key = (0, cache_keys_utils_1.getMarketKeyWithGameUniqueIdMarketType)(gameUniqueId, marketType);
|
|
223
|
-
const marketJson = await redis.hget(key, "market_json");
|
|
224
|
-
if (!marketJson) {
|
|
225
|
-
return null;
|
|
257
|
+
// Reconstruct market from individual fields
|
|
258
|
+
const market = reconstructMarketFromFields(fields);
|
|
259
|
+
if (market) {
|
|
260
|
+
markets.push(market);
|
|
226
261
|
}
|
|
227
|
-
return JSON.parse(marketJson);
|
|
228
|
-
}
|
|
229
|
-
catch (error) {
|
|
230
|
-
winston_1.default.error("Error retrieving market from hash", error);
|
|
231
|
-
return null;
|
|
232
262
|
}
|
|
263
|
+
return { markets, total };
|
|
233
264
|
};
|
|
234
|
-
exports.
|
|
265
|
+
exports.getGameMarkets = getGameMarkets;
|
|
235
266
|
/**
|
|
236
|
-
*
|
|
237
|
-
* Uses simple hash operations when RediSearch is unavailable
|
|
267
|
+
* Get markets with their associated odds
|
|
238
268
|
* @param redis - Redis client instance
|
|
239
|
-
* @param
|
|
240
|
-
* @
|
|
241
|
-
* @returns Markets with their odds
|
|
269
|
+
* @param query - Search query parameters
|
|
270
|
+
* @returns Results with markets and their odds
|
|
242
271
|
*/
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const marketsWithOdds = {
|
|
272
|
+
const getGameMarketsWithOdds = async (redis, query) => {
|
|
273
|
+
const startTime = Date.now();
|
|
274
|
+
// Get markets from search
|
|
275
|
+
const { markets, total } = await (0, exports.getGameMarkets)(redis, query);
|
|
276
|
+
// Enrich each market with its odds
|
|
277
|
+
const marketsWithOdds = await Promise.all(markets.map(async (market) => {
|
|
278
|
+
const odds = await (0, exports.getOddsList)(redis, market.gameMarketId);
|
|
279
|
+
return {
|
|
252
280
|
...market,
|
|
253
281
|
odds,
|
|
254
282
|
};
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
283
|
+
}));
|
|
284
|
+
const duration = Date.now() - startTime;
|
|
285
|
+
return {
|
|
286
|
+
total,
|
|
287
|
+
results: marketsWithOdds,
|
|
288
|
+
duration,
|
|
289
|
+
};
|
|
261
290
|
};
|
|
262
|
-
exports.
|
|
291
|
+
exports.getGameMarketsWithOdds = getGameMarketsWithOdds;
|
|
263
292
|
/**
|
|
264
|
-
*
|
|
293
|
+
* Get multiple markets with their associated odds using multiple queries
|
|
265
294
|
* @param redis - Redis client instance
|
|
266
|
-
* @param
|
|
267
|
-
* @returns
|
|
295
|
+
* @param queries - Array of search query parameters
|
|
296
|
+
* @returns Combined results with markets and their odds
|
|
268
297
|
*/
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
298
|
+
const getMultipleMarketsWithOdds = async (redis, queries) => {
|
|
299
|
+
const startTime = Date.now();
|
|
300
|
+
const allResults = {};
|
|
301
|
+
let totalCount = 0;
|
|
302
|
+
// Execute each query and collect results
|
|
303
|
+
for (const query of queries) {
|
|
304
|
+
const { markets, total } = await (0, exports.getGameMarkets)(redis, query);
|
|
305
|
+
totalCount += total;
|
|
274
306
|
// Enrich each market with its odds
|
|
275
307
|
const marketsWithOdds = await Promise.all(markets.map(async (market) => {
|
|
276
|
-
const odds = await (0, exports.getOddsList)(redis, market.
|
|
308
|
+
const odds = await (0, exports.getOddsList)(redis, market.gameMarketId);
|
|
277
309
|
return {
|
|
278
310
|
...market,
|
|
279
311
|
odds,
|
|
280
312
|
};
|
|
281
313
|
}));
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
catch (error) {
|
|
290
|
-
winston_1.default.error("Error searching markets with odds", error);
|
|
291
|
-
// Fallback to direct hash lookup if RediSearch fails
|
|
292
|
-
return {
|
|
293
|
-
total: 0,
|
|
294
|
-
results: [],
|
|
295
|
-
duration: 0,
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
exports.searchMarketsWithOdds = searchMarketsWithOdds;
|
|
300
|
-
/**
|
|
301
|
-
* Search multiple markets with their associated odds - FALLBACK version
|
|
302
|
-
* Uses simple hash operations when RediSearch is unavailable
|
|
303
|
-
* @param redis - Redis client instance
|
|
304
|
-
* @param queries - Array of search query parameters with gameUniqueIdentifier and marketType
|
|
305
|
-
* @returns Combined search results with markets and their odds
|
|
306
|
-
*/
|
|
307
|
-
const searchMultipleMarketsWithOddsFallback = async (redis, queries) => {
|
|
308
|
-
// generate multiple market keys
|
|
309
|
-
const marketKeys = queries.map((q) => (0, cache_keys_utils_1.getMarketKeyWithGameUniqueIdMarketType)(q.gameUniqueIdentifier, q.marketType));
|
|
310
|
-
// hmget all of them with market json field
|
|
311
|
-
const pipeline = redis.pipeline();
|
|
312
|
-
for (const key of marketKeys) {
|
|
313
|
-
pipeline.hget(key, "market_json");
|
|
314
|
-
}
|
|
315
|
-
const responses = await pipeline.exec();
|
|
316
|
-
const results = {};
|
|
317
|
-
let totalCount = 0;
|
|
318
|
-
if (!responses) {
|
|
319
|
-
return {
|
|
320
|
-
total: 0,
|
|
321
|
-
results: {},
|
|
322
|
-
duration: 0,
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
for (let i = 0; i < responses.length; i++) {
|
|
326
|
-
console.log("Processing response for key:", marketKeys[i], "Response:", responses[i]);
|
|
327
|
-
const response = responses[i];
|
|
328
|
-
if (!response || !Array.isArray(response))
|
|
329
|
-
continue;
|
|
330
|
-
const [error, marketJson] = response;
|
|
331
|
-
if (error) {
|
|
332
|
-
winston_1.default.error("Error fetching market in fallback multiple search", error);
|
|
333
|
-
continue;
|
|
334
|
-
}
|
|
335
|
-
if (marketJson && typeof marketJson === "string") {
|
|
336
|
-
try {
|
|
337
|
-
const market = JSON.parse(marketJson);
|
|
338
|
-
const odds = await (0, exports.getOddsList)(redis, market.levrGameObjectId, market.marketType);
|
|
339
|
-
const marketWithRelations = {
|
|
340
|
-
...market,
|
|
341
|
-
odds,
|
|
342
|
-
};
|
|
343
|
-
if (!results[market.levrGameObjectId]) {
|
|
344
|
-
results[market.levrGameObjectId] = [];
|
|
314
|
+
// Group results by levrGameObjectId
|
|
315
|
+
for (const market of marketsWithOdds) {
|
|
316
|
+
if (market.levrGameObjectId) {
|
|
317
|
+
if (!allResults[market.levrGameObjectId]) {
|
|
318
|
+
allResults[market.levrGameObjectId] = [];
|
|
345
319
|
}
|
|
346
|
-
|
|
347
|
-
totalCount++;
|
|
348
|
-
}
|
|
349
|
-
catch (e) {
|
|
350
|
-
winston_1.default.warn("Failed to parse market in fallback multiple search", e);
|
|
320
|
+
allResults[market.levrGameObjectId]?.push(market);
|
|
351
321
|
}
|
|
352
322
|
}
|
|
353
323
|
}
|
|
324
|
+
const duration = Date.now() - startTime;
|
|
354
325
|
return {
|
|
355
326
|
total: totalCount,
|
|
356
|
-
results,
|
|
357
|
-
duration
|
|
327
|
+
results: allResults,
|
|
328
|
+
duration,
|
|
358
329
|
};
|
|
359
330
|
};
|
|
360
|
-
exports.
|
|
331
|
+
exports.getMultipleMarketsWithOdds = getMultipleMarketsWithOdds;
|
|
361
332
|
/**
|
|
362
|
-
*
|
|
333
|
+
* Get market data with associated odds for multiple games and market types
|
|
363
334
|
* @param redis - Redis client instance
|
|
364
|
-
* @param
|
|
365
|
-
* @returns
|
|
335
|
+
* @param query - Array of query objects with gameUniqueIdentifier and marketType
|
|
336
|
+
* @returns Map of game IDs to their markets with odds
|
|
366
337
|
*/
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
for (const query of queries) {
|
|
374
|
-
const markets = await (0, exports.searchMarkets)(redis, query);
|
|
375
|
-
totalCount += markets.length;
|
|
376
|
-
// Enrich each market with its odds
|
|
377
|
-
const marketsWithOdds = await Promise.all(markets.map(async (market) => {
|
|
378
|
-
const odds = await (0, exports.getOddsList)(redis, market.levrGameObjectId, market.marketType);
|
|
379
|
-
return {
|
|
380
|
-
...market,
|
|
381
|
-
odds,
|
|
382
|
-
};
|
|
383
|
-
}));
|
|
384
|
-
// Group results by levrGameObjectId
|
|
385
|
-
marketsWithOdds.forEach((market) => {
|
|
386
|
-
if (market.levrGameObjectId) {
|
|
387
|
-
if (!allResults[market.levrGameObjectId]) {
|
|
388
|
-
allResults[market.levrGameObjectId] = [];
|
|
389
|
-
}
|
|
390
|
-
allResults[market.levrGameObjectId]?.push(market);
|
|
391
|
-
}
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
const duration = Date.now() - startTime;
|
|
395
|
-
return {
|
|
396
|
-
total: totalCount,
|
|
397
|
-
results: allResults,
|
|
398
|
-
duration,
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
catch (error) {
|
|
402
|
-
winston_1.default.error("Error searching multiple markets with odds", error);
|
|
403
|
-
return {
|
|
404
|
-
total: 0,
|
|
405
|
-
results: {},
|
|
406
|
-
duration: 0,
|
|
407
|
-
};
|
|
408
|
-
}
|
|
338
|
+
const getMarketDataCacheWithOdds = async (redis, query) => {
|
|
339
|
+
const results = await (0, exports.getMultipleMarketsWithOdds)(redis, query.map((q) => ({
|
|
340
|
+
levrGameObjectId: q.gameUniqueIdentifier,
|
|
341
|
+
marketType: q.marketType,
|
|
342
|
+
})));
|
|
343
|
+
return results?.results || {};
|
|
409
344
|
};
|
|
410
|
-
exports.
|
|
345
|
+
exports.getMarketDataCacheWithOdds = getMarketDataCacheWithOdds;
|
|
346
|
+
// ============================================================================
|
|
347
|
+
// ODDS CACHE FUNCTIONS (Redis LIST operations)
|
|
348
|
+
// ============================================================================
|
|
411
349
|
/**
|
|
412
|
-
*
|
|
350
|
+
* Get odds for a specific gameMarketId with pagination using Redis LIST
|
|
413
351
|
* @param redis - Redis client instance
|
|
414
|
-
* @param
|
|
415
|
-
* @param
|
|
416
|
-
* @
|
|
352
|
+
* @param gameMarketId - The game market identifier (key suffix)
|
|
353
|
+
* @param limit - Number of latest odds to return (from the end). Use -1 for all.
|
|
354
|
+
* @returns Array of Odds objects (most recent last)
|
|
417
355
|
*/
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const allOdds = [...existingOdds, ...odds];
|
|
427
|
-
// Store the entire list as JSON and add indexable metadata
|
|
428
|
-
// const gameMarketId = odds[0]?.gameMarketId || ""
|
|
429
|
-
// Use pipeline to batch metadata updates
|
|
430
|
-
const pipeline = redis.pipeline();
|
|
431
|
-
pipeline.hset(key, field, JSON.stringify(allOdds));
|
|
432
|
-
// pipeline.hset(key, "gameMarketId", gameMarketId)
|
|
433
|
-
// pipeline.hset(key, "marketType", marketType)
|
|
434
|
-
// pipeline.hset(key, "levrGameObjectId", gameUniqueId)
|
|
435
|
-
await pipeline.exec();
|
|
436
|
-
// Create index separately (only if it doesn't exist)
|
|
437
|
-
// await createOddsIndex(redis)
|
|
438
|
-
winston_1.default.info(`Added ${odds.length} odds to cache: ${key}:${field}`);
|
|
439
|
-
}
|
|
440
|
-
catch (error) {
|
|
441
|
-
winston_1.default.error("Error adding odds to cache", error);
|
|
442
|
-
throw error;
|
|
356
|
+
const getOddsList = async (redis, gameMarketId, limit = 10) => {
|
|
357
|
+
const key = (0, cache_keys_utils_1.getOddsListKey)(gameMarketId);
|
|
358
|
+
// LRANGE with negative indices: -limit to -1 gets last N elements
|
|
359
|
+
// Use 0 to -1 for all elements
|
|
360
|
+
const start = limit === -1 ? 0 : -limit;
|
|
361
|
+
const rawOdds = await redis.lrange(key, start, -1);
|
|
362
|
+
if (!rawOdds || rawOdds.length === 0) {
|
|
363
|
+
return [];
|
|
443
364
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
* @param redis - Redis client instance
|
|
449
|
-
* @param gameMarketId - Game market ID to search
|
|
450
|
-
* @param marketType - Market type to search
|
|
451
|
-
* @param levrGameObjectId - Levr game object ID to search
|
|
452
|
-
* @returns Array of odds lists matching the query
|
|
453
|
-
*/
|
|
454
|
-
const searchOddsLists = async (redis, gameMarketId, marketType, levrGameObjectId) => {
|
|
455
|
-
try {
|
|
456
|
-
const indexName = "odds_list_idx";
|
|
457
|
-
const queryParts = [];
|
|
458
|
-
if (gameMarketId) {
|
|
459
|
-
queryParts.push(`@gameMarketId:${gameMarketId}`);
|
|
460
|
-
}
|
|
461
|
-
if (marketType) {
|
|
462
|
-
queryParts.push(`@marketType:{${marketType}}`);
|
|
463
|
-
}
|
|
464
|
-
if (levrGameObjectId) {
|
|
465
|
-
queryParts.push(`@levrGameObjectId:${levrGameObjectId}`);
|
|
365
|
+
const odds = [];
|
|
366
|
+
for (const raw of rawOdds) {
|
|
367
|
+
try {
|
|
368
|
+
odds.push(JSON.parse(raw));
|
|
466
369
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const [, ...items] = result;
|
|
470
|
-
const oddsList = [];
|
|
471
|
-
for (let i = 0; i < items.length; i += 2) {
|
|
472
|
-
const doc = items[i + 1];
|
|
473
|
-
if (Array.isArray(doc)) {
|
|
474
|
-
const obj = {};
|
|
475
|
-
for (let j = 0; j < doc.length; j += 2) {
|
|
476
|
-
obj[doc[j]] = doc[j + 1];
|
|
477
|
-
}
|
|
478
|
-
// Extract the odds list field
|
|
479
|
-
const field = Object.keys(obj).find((k) => k.includes(":"));
|
|
480
|
-
if (field && obj[field]) {
|
|
481
|
-
const parsed = JSON.parse(obj[field]);
|
|
482
|
-
oddsList.push(parsed);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
370
|
+
catch (e) {
|
|
371
|
+
winston_1.default.warn(`Failed to parse odds entry from list ${key}`, e);
|
|
485
372
|
}
|
|
486
|
-
return oddsList;
|
|
487
|
-
}
|
|
488
|
-
catch (error) {
|
|
489
|
-
winston_1.default.error("Error searching odds lists", error);
|
|
490
|
-
return [];
|
|
491
373
|
}
|
|
374
|
+
return odds;
|
|
492
375
|
};
|
|
493
|
-
exports.
|
|
376
|
+
exports.getOddsList = getOddsList;
|
|
494
377
|
/**
|
|
495
|
-
*
|
|
378
|
+
* Add odds to cache using Redis LIST (RPUSH)
|
|
496
379
|
* @param redis - Redis client instance
|
|
497
|
-
* @param
|
|
498
|
-
* @param
|
|
499
|
-
* @returns Latest Odds object or null if not found
|
|
380
|
+
* @param gameMarketId - The game market identifier (used as key suffix)
|
|
381
|
+
* @param odds - Array of Odds objects to append to the list
|
|
500
382
|
*/
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
return null;
|
|
512
|
-
}
|
|
513
|
-
// Return the last (most recent) odds entry
|
|
514
|
-
const lastOdds = oddsList[oddsList.length - 1];
|
|
515
|
-
return lastOdds ?? null;
|
|
516
|
-
}
|
|
517
|
-
catch (error) {
|
|
518
|
-
winston_1.default.error("Error getting latest odds", error);
|
|
519
|
-
return null;
|
|
520
|
-
}
|
|
383
|
+
const addOddsToOddsCache = async (redis, gameMarketId, odds) => {
|
|
384
|
+
if (odds.length === 0) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const key = (0, cache_keys_utils_1.getOddsListKey)(gameMarketId);
|
|
388
|
+
// Serialize each odds entry and push to list
|
|
389
|
+
const serializedOdds = odds.map((o) => JSON.stringify(o));
|
|
390
|
+
// RPUSH appends to the end of the list (newest at the end)
|
|
391
|
+
await redis.rpush(key, ...serializedOdds);
|
|
392
|
+
winston_1.default.info(`Added ${odds.length} odds to cache list: ${key}`);
|
|
521
393
|
};
|
|
522
|
-
exports.
|
|
394
|
+
exports.addOddsToOddsCache = addOddsToOddsCache;
|
|
523
395
|
/**
|
|
524
|
-
* Get the latest odds
|
|
396
|
+
* Get the latest odds for a specific gameMarketId
|
|
525
397
|
* @param redis - Redis client instance
|
|
526
|
-
* @param
|
|
527
|
-
* @
|
|
528
|
-
* @returns Odds with related market or null if not found
|
|
398
|
+
* @param gameMarketId - The game market identifier
|
|
399
|
+
* @returns Latest Odds object or null if not found
|
|
529
400
|
*/
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
return null;
|
|
536
|
-
}
|
|
537
|
-
// Get the related market
|
|
538
|
-
const key = (0, cache_keys_utils_1.getMarketKeyWithGameUniqueIdMarketType)(gameUniqueId, marketType);
|
|
539
|
-
const marketData = await redis.hget(key, "market_json");
|
|
540
|
-
if (!marketData) {
|
|
541
|
-
return latestOdds;
|
|
542
|
-
}
|
|
543
|
-
const market = JSON.parse(marketData);
|
|
544
|
-
return {
|
|
545
|
-
...latestOdds,
|
|
546
|
-
market,
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
catch (error) {
|
|
550
|
-
winston_1.default.error("Error getting latest odds with market", error);
|
|
401
|
+
const getLatestOdds = async (redis, gameMarketId) => {
|
|
402
|
+
const key = (0, cache_keys_utils_1.getOddsListKey)(gameMarketId);
|
|
403
|
+
// LINDEX -1 gets the last element (most recent)
|
|
404
|
+
const raw = await redis.lindex(key, -1);
|
|
405
|
+
if (!raw) {
|
|
551
406
|
return null;
|
|
552
407
|
}
|
|
553
|
-
};
|
|
554
|
-
exports.getLatestOddsWithMarket = getLatestOddsWithMarket;
|
|
555
|
-
/**
|
|
556
|
-
* Drop all search indices
|
|
557
|
-
* @param redis - Redis client instance
|
|
558
|
-
*/
|
|
559
|
-
const dropAllIndices = async (redis) => {
|
|
560
408
|
try {
|
|
561
|
-
|
|
562
|
-
for (const idx of indices) {
|
|
563
|
-
await redis.call("FT.DROPINDEX", idx).catch(() => {
|
|
564
|
-
winston_1.default.warn(`Index ${idx} does not exist`);
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
winston_1.default.info("Dropped search indices");
|
|
409
|
+
return JSON.parse(raw);
|
|
568
410
|
}
|
|
569
|
-
catch (
|
|
570
|
-
winston_1.default.
|
|
411
|
+
catch (e) {
|
|
412
|
+
winston_1.default.warn(`Failed to parse latest odds from ${key}`, e);
|
|
413
|
+
return null;
|
|
571
414
|
}
|
|
572
415
|
};
|
|
573
|
-
exports.
|
|
416
|
+
exports.getLatestOdds = getLatestOdds;
|
|
574
417
|
//# sourceMappingURL=market.query.engine.js.map
|