@voyantjs/markets 0.1.0

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.
@@ -0,0 +1,403 @@
1
+ import { and, asc, desc, eq, ilike, or, sql } from "drizzle-orm";
2
+ import { exchangeRates, fxRateSets, marketChannelRules, marketCurrencies, marketLocales, marketPriceCatalogs, marketProductRules, markets, } from "./schema.js";
3
+ async function paginate(rowsQuery, countQuery, limit, offset) {
4
+ const [data, countResult] = await Promise.all([rowsQuery, countQuery]);
5
+ return { data, total: countResult[0]?.count ?? 0, limit, offset };
6
+ }
7
+ function toTimestamp(value) {
8
+ return value ? new Date(value) : null;
9
+ }
10
+ export const marketsService = {
11
+ async listMarkets(db, query) {
12
+ const conditions = [];
13
+ if (query.status)
14
+ conditions.push(eq(markets.status, query.status));
15
+ if (query.countryCode)
16
+ conditions.push(eq(markets.countryCode, query.countryCode));
17
+ if (query.search) {
18
+ const term = `%${query.search}%`;
19
+ conditions.push(or(ilike(markets.name, term), ilike(markets.code, term)));
20
+ }
21
+ const where = conditions.length > 0 ? and(...conditions) : undefined;
22
+ return paginate(db
23
+ .select()
24
+ .from(markets)
25
+ .where(where)
26
+ .limit(query.limit)
27
+ .offset(query.offset)
28
+ .orderBy(desc(markets.updatedAt)), db.select({ count: sql `count(*)::int` }).from(markets).where(where), query.limit, query.offset);
29
+ },
30
+ async getMarketById(db, id) {
31
+ const [row] = await db.select().from(markets).where(eq(markets.id, id)).limit(1);
32
+ return row ?? null;
33
+ },
34
+ async createMarket(db, data) {
35
+ const [row] = await db.insert(markets).values(data).returning();
36
+ return row ?? null;
37
+ },
38
+ async updateMarket(db, id, data) {
39
+ const [row] = await db
40
+ .update(markets)
41
+ .set({ ...data, updatedAt: new Date() })
42
+ .where(eq(markets.id, id))
43
+ .returning();
44
+ return row ?? null;
45
+ },
46
+ async deleteMarket(db, id) {
47
+ const [row] = await db.delete(markets).where(eq(markets.id, id)).returning({ id: markets.id });
48
+ return row ?? null;
49
+ },
50
+ async listMarketLocales(db, query) {
51
+ const conditions = [];
52
+ if (query.marketId)
53
+ conditions.push(eq(marketLocales.marketId, query.marketId));
54
+ if (query.languageTag)
55
+ conditions.push(eq(marketLocales.languageTag, query.languageTag));
56
+ if (query.active !== undefined)
57
+ conditions.push(eq(marketLocales.active, query.active));
58
+ const where = conditions.length > 0 ? and(...conditions) : undefined;
59
+ return paginate(db
60
+ .select()
61
+ .from(marketLocales)
62
+ .where(where)
63
+ .limit(query.limit)
64
+ .offset(query.offset)
65
+ .orderBy(asc(marketLocales.sortOrder), asc(marketLocales.createdAt)), db.select({ count: sql `count(*)::int` }).from(marketLocales).where(where), query.limit, query.offset);
66
+ },
67
+ async createMarketLocale(db, marketId, data) {
68
+ const [market] = await db
69
+ .select({ id: markets.id })
70
+ .from(markets)
71
+ .where(eq(markets.id, marketId))
72
+ .limit(1);
73
+ if (!market)
74
+ return null;
75
+ const [row] = await db
76
+ .insert(marketLocales)
77
+ .values({ ...data, marketId })
78
+ .returning();
79
+ return row ?? null;
80
+ },
81
+ async updateMarketLocale(db, id, data) {
82
+ const [row] = await db
83
+ .update(marketLocales)
84
+ .set({ ...data, updatedAt: new Date() })
85
+ .where(eq(marketLocales.id, id))
86
+ .returning();
87
+ return row ?? null;
88
+ },
89
+ async deleteMarketLocale(db, id) {
90
+ const [row] = await db
91
+ .delete(marketLocales)
92
+ .where(eq(marketLocales.id, id))
93
+ .returning({ id: marketLocales.id });
94
+ return row ?? null;
95
+ },
96
+ async listMarketCurrencies(db, query) {
97
+ const conditions = [];
98
+ if (query.marketId)
99
+ conditions.push(eq(marketCurrencies.marketId, query.marketId));
100
+ if (query.currencyCode)
101
+ conditions.push(eq(marketCurrencies.currencyCode, query.currencyCode));
102
+ if (query.active !== undefined)
103
+ conditions.push(eq(marketCurrencies.active, query.active));
104
+ const where = conditions.length > 0 ? and(...conditions) : undefined;
105
+ return paginate(db
106
+ .select()
107
+ .from(marketCurrencies)
108
+ .where(where)
109
+ .limit(query.limit)
110
+ .offset(query.offset)
111
+ .orderBy(asc(marketCurrencies.sortOrder), asc(marketCurrencies.createdAt)), db.select({ count: sql `count(*)::int` }).from(marketCurrencies).where(where), query.limit, query.offset);
112
+ },
113
+ async createMarketCurrency(db, marketId, data) {
114
+ const [market] = await db
115
+ .select({ id: markets.id })
116
+ .from(markets)
117
+ .where(eq(markets.id, marketId))
118
+ .limit(1);
119
+ if (!market)
120
+ return null;
121
+ const [row] = await db
122
+ .insert(marketCurrencies)
123
+ .values({ ...data, marketId })
124
+ .returning();
125
+ return row ?? null;
126
+ },
127
+ async updateMarketCurrency(db, id, data) {
128
+ const [row] = await db
129
+ .update(marketCurrencies)
130
+ .set({ ...data, updatedAt: new Date() })
131
+ .where(eq(marketCurrencies.id, id))
132
+ .returning();
133
+ return row ?? null;
134
+ },
135
+ async deleteMarketCurrency(db, id) {
136
+ const [row] = await db
137
+ .delete(marketCurrencies)
138
+ .where(eq(marketCurrencies.id, id))
139
+ .returning({ id: marketCurrencies.id });
140
+ return row ?? null;
141
+ },
142
+ async listFxRateSets(db, query) {
143
+ const conditions = [];
144
+ if (query.source)
145
+ conditions.push(eq(fxRateSets.source, query.source));
146
+ if (query.baseCurrency)
147
+ conditions.push(eq(fxRateSets.baseCurrency, query.baseCurrency));
148
+ const where = conditions.length > 0 ? and(...conditions) : undefined;
149
+ return paginate(db
150
+ .select()
151
+ .from(fxRateSets)
152
+ .where(where)
153
+ .limit(query.limit)
154
+ .offset(query.offset)
155
+ .orderBy(desc(fxRateSets.effectiveAt)), db.select({ count: sql `count(*)::int` }).from(fxRateSets).where(where), query.limit, query.offset);
156
+ },
157
+ async getFxRateSetById(db, id) {
158
+ const [row] = await db.select().from(fxRateSets).where(eq(fxRateSets.id, id)).limit(1);
159
+ return row ?? null;
160
+ },
161
+ async createFxRateSet(db, data) {
162
+ const [row] = await db
163
+ .insert(fxRateSets)
164
+ .values({
165
+ ...data,
166
+ effectiveAt: new Date(data.effectiveAt),
167
+ observedAt: toTimestamp(data.observedAt),
168
+ })
169
+ .returning();
170
+ return row ?? null;
171
+ },
172
+ async updateFxRateSet(db, id, data) {
173
+ const [row] = await db
174
+ .update(fxRateSets)
175
+ .set({
176
+ ...data,
177
+ effectiveAt: data.effectiveAt === undefined ? undefined : new Date(data.effectiveAt),
178
+ observedAt: data.observedAt === undefined ? undefined : toTimestamp(data.observedAt),
179
+ })
180
+ .where(eq(fxRateSets.id, id))
181
+ .returning();
182
+ return row ?? null;
183
+ },
184
+ async deleteFxRateSet(db, id) {
185
+ const [row] = await db
186
+ .delete(fxRateSets)
187
+ .where(eq(fxRateSets.id, id))
188
+ .returning({ id: fxRateSets.id });
189
+ return row ?? null;
190
+ },
191
+ async listExchangeRates(db, query) {
192
+ const conditions = [];
193
+ if (query.fxRateSetId)
194
+ conditions.push(eq(exchangeRates.fxRateSetId, query.fxRateSetId));
195
+ if (query.baseCurrency)
196
+ conditions.push(eq(exchangeRates.baseCurrency, query.baseCurrency));
197
+ if (query.quoteCurrency)
198
+ conditions.push(eq(exchangeRates.quoteCurrency, query.quoteCurrency));
199
+ const where = conditions.length > 0 ? and(...conditions) : undefined;
200
+ return paginate(db
201
+ .select()
202
+ .from(exchangeRates)
203
+ .where(where)
204
+ .limit(query.limit)
205
+ .offset(query.offset)
206
+ .orderBy(asc(exchangeRates.quoteCurrency)), db.select({ count: sql `count(*)::int` }).from(exchangeRates).where(where), query.limit, query.offset);
207
+ },
208
+ async createExchangeRate(db, fxRateSetId, data) {
209
+ const [rateSet] = await db
210
+ .select({ id: fxRateSets.id })
211
+ .from(fxRateSets)
212
+ .where(eq(fxRateSets.id, fxRateSetId))
213
+ .limit(1);
214
+ if (!rateSet)
215
+ return null;
216
+ const [row] = await db
217
+ .insert(exchangeRates)
218
+ .values({
219
+ ...data,
220
+ fxRateSetId,
221
+ observedAt: toTimestamp(data.observedAt),
222
+ })
223
+ .returning();
224
+ return row ?? null;
225
+ },
226
+ async updateExchangeRate(db, id, data) {
227
+ const [row] = await db
228
+ .update(exchangeRates)
229
+ .set({
230
+ ...data,
231
+ observedAt: data.observedAt === undefined ? undefined : toTimestamp(data.observedAt),
232
+ })
233
+ .where(eq(exchangeRates.id, id))
234
+ .returning();
235
+ return row ?? null;
236
+ },
237
+ async deleteExchangeRate(db, id) {
238
+ const [row] = await db
239
+ .delete(exchangeRates)
240
+ .where(eq(exchangeRates.id, id))
241
+ .returning({ id: exchangeRates.id });
242
+ return row ?? null;
243
+ },
244
+ async listMarketPriceCatalogs(db, query) {
245
+ const conditions = [];
246
+ if (query.marketId)
247
+ conditions.push(eq(marketPriceCatalogs.marketId, query.marketId));
248
+ if (query.priceCatalogId)
249
+ conditions.push(eq(marketPriceCatalogs.priceCatalogId, query.priceCatalogId));
250
+ if (query.active !== undefined)
251
+ conditions.push(eq(marketPriceCatalogs.active, query.active));
252
+ const where = conditions.length > 0 ? and(...conditions) : undefined;
253
+ return paginate(db
254
+ .select()
255
+ .from(marketPriceCatalogs)
256
+ .where(where)
257
+ .limit(query.limit)
258
+ .offset(query.offset)
259
+ .orderBy(desc(marketPriceCatalogs.isDefault), desc(marketPriceCatalogs.priority)), db.select({ count: sql `count(*)::int` }).from(marketPriceCatalogs).where(where), query.limit, query.offset);
260
+ },
261
+ async getMarketPriceCatalogById(db, id) {
262
+ const [row] = await db
263
+ .select()
264
+ .from(marketPriceCatalogs)
265
+ .where(eq(marketPriceCatalogs.id, id))
266
+ .limit(1);
267
+ return row ?? null;
268
+ },
269
+ async createMarketPriceCatalog(db, data) {
270
+ const [market] = await db
271
+ .select({ id: markets.id })
272
+ .from(markets)
273
+ .where(eq(markets.id, data.marketId))
274
+ .limit(1);
275
+ if (!market)
276
+ return null;
277
+ const [row] = await db.insert(marketPriceCatalogs).values(data).returning();
278
+ return row ?? null;
279
+ },
280
+ async updateMarketPriceCatalog(db, id, data) {
281
+ const [row] = await db
282
+ .update(marketPriceCatalogs)
283
+ .set({ ...data, updatedAt: new Date() })
284
+ .where(eq(marketPriceCatalogs.id, id))
285
+ .returning();
286
+ return row ?? null;
287
+ },
288
+ async deleteMarketPriceCatalog(db, id) {
289
+ const [row] = await db
290
+ .delete(marketPriceCatalogs)
291
+ .where(eq(marketPriceCatalogs.id, id))
292
+ .returning({ id: marketPriceCatalogs.id });
293
+ return row ?? null;
294
+ },
295
+ async listMarketProductRules(db, query) {
296
+ const conditions = [];
297
+ if (query.marketId)
298
+ conditions.push(eq(marketProductRules.marketId, query.marketId));
299
+ if (query.productId)
300
+ conditions.push(eq(marketProductRules.productId, query.productId));
301
+ if (query.optionId)
302
+ conditions.push(eq(marketProductRules.optionId, query.optionId));
303
+ if (query.sellability)
304
+ conditions.push(eq(marketProductRules.sellability, query.sellability));
305
+ if (query.active !== undefined)
306
+ conditions.push(eq(marketProductRules.active, query.active));
307
+ const where = conditions.length > 0 ? and(...conditions) : undefined;
308
+ return paginate(db
309
+ .select()
310
+ .from(marketProductRules)
311
+ .where(where)
312
+ .limit(query.limit)
313
+ .offset(query.offset)
314
+ .orderBy(desc(marketProductRules.updatedAt)), db.select({ count: sql `count(*)::int` }).from(marketProductRules).where(where), query.limit, query.offset);
315
+ },
316
+ async getMarketProductRuleById(db, id) {
317
+ const [row] = await db
318
+ .select()
319
+ .from(marketProductRules)
320
+ .where(eq(marketProductRules.id, id))
321
+ .limit(1);
322
+ return row ?? null;
323
+ },
324
+ async createMarketProductRule(db, data) {
325
+ const [market] = await db
326
+ .select({ id: markets.id })
327
+ .from(markets)
328
+ .where(eq(markets.id, data.marketId))
329
+ .limit(1);
330
+ if (!market)
331
+ return null;
332
+ const [row] = await db.insert(marketProductRules).values(data).returning();
333
+ return row ?? null;
334
+ },
335
+ async updateMarketProductRule(db, id, data) {
336
+ const [row] = await db
337
+ .update(marketProductRules)
338
+ .set({ ...data, updatedAt: new Date() })
339
+ .where(eq(marketProductRules.id, id))
340
+ .returning();
341
+ return row ?? null;
342
+ },
343
+ async deleteMarketProductRule(db, id) {
344
+ const [row] = await db
345
+ .delete(marketProductRules)
346
+ .where(eq(marketProductRules.id, id))
347
+ .returning({ id: marketProductRules.id });
348
+ return row ?? null;
349
+ },
350
+ async listMarketChannelRules(db, query) {
351
+ const conditions = [];
352
+ if (query.marketId)
353
+ conditions.push(eq(marketChannelRules.marketId, query.marketId));
354
+ if (query.channelId)
355
+ conditions.push(eq(marketChannelRules.channelId, query.channelId));
356
+ if (query.sellability)
357
+ conditions.push(eq(marketChannelRules.sellability, query.sellability));
358
+ if (query.active !== undefined)
359
+ conditions.push(eq(marketChannelRules.active, query.active));
360
+ const where = conditions.length > 0 ? and(...conditions) : undefined;
361
+ return paginate(db
362
+ .select()
363
+ .from(marketChannelRules)
364
+ .where(where)
365
+ .limit(query.limit)
366
+ .offset(query.offset)
367
+ .orderBy(desc(marketChannelRules.priority), desc(marketChannelRules.updatedAt)), db.select({ count: sql `count(*)::int` }).from(marketChannelRules).where(where), query.limit, query.offset);
368
+ },
369
+ async getMarketChannelRuleById(db, id) {
370
+ const [row] = await db
371
+ .select()
372
+ .from(marketChannelRules)
373
+ .where(eq(marketChannelRules.id, id))
374
+ .limit(1);
375
+ return row ?? null;
376
+ },
377
+ async createMarketChannelRule(db, data) {
378
+ const [market] = await db
379
+ .select({ id: markets.id })
380
+ .from(markets)
381
+ .where(eq(markets.id, data.marketId))
382
+ .limit(1);
383
+ if (!market)
384
+ return null;
385
+ const [row] = await db.insert(marketChannelRules).values(data).returning();
386
+ return row ?? null;
387
+ },
388
+ async updateMarketChannelRule(db, id, data) {
389
+ const [row] = await db
390
+ .update(marketChannelRules)
391
+ .set({ ...data, updatedAt: new Date() })
392
+ .where(eq(marketChannelRules.id, id))
393
+ .returning();
394
+ return row ?? null;
395
+ },
396
+ async deleteMarketChannelRule(db, id) {
397
+ const [row] = await db
398
+ .delete(marketChannelRules)
399
+ .where(eq(marketChannelRules.id, id))
400
+ .returning({ id: marketChannelRules.id });
401
+ return row ?? null;
402
+ },
403
+ };