Skip to content

Commit 4b7031c

Browse files
committed
feat(search): refactor data client with updated service
1 parent 2d0bdca commit 4b7031c

File tree

4 files changed

+109
-235
lines changed

4 files changed

+109
-235
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { expressionBuilder, Kysely, SqlBool } from "kysely";
2+
import { BaseArgs } from "../graphql/schemas/args/baseArgs.js";
3+
import { SortOrder } from "../graphql/schemas/enums/sortEnums.js";
4+
import { buildWhereCondition } from "../graphql/schemas/utils/filters-kysely.js";
5+
6+
export abstract class BaseSupabaseService<DB> {
7+
protected db: Kysely<DB>;
8+
9+
protected constructor(db: Kysely<DB>) {
10+
this.db = db;
11+
}
12+
13+
abstract getDataQuery<T extends keyof DB & string, A extends object>(
14+
tableName: T,
15+
args: BaseArgs<A>, // eslint-disable-next-line @typescript-eslint/no-explicit-any
16+
): any;
17+
18+
abstract getCountQuery<T extends keyof DB & string, A extends object>(
19+
tableName: T,
20+
args: BaseArgs<A>, // eslint-disable-next-line @typescript-eslint/no-explicit-any
21+
): any;
22+
23+
handleGetData<T extends keyof DB & string, A extends object>(
24+
tableName: T,
25+
args: BaseArgs<A> & {
26+
first?: number;
27+
offset?: number;
28+
},
29+
) {
30+
let query = this.getDataQuery(tableName, args);
31+
const { where, first, offset, sort } = args;
32+
const eb = expressionBuilder(query);
33+
34+
if (where) {
35+
query = this.applyWhereConditions(query, where, tableName, eb);
36+
}
37+
38+
if (sort?.by) {
39+
query = this.applySorting(query, sort.by);
40+
}
41+
42+
if (first) query = query.limit(first);
43+
if (offset) query = query.offset(offset);
44+
45+
return query;
46+
}
47+
48+
handleGetCount<T extends keyof DB & string, A extends object>(
49+
tableName: T,
50+
args: BaseArgs<A> & {
51+
first?: number;
52+
offset?: number;
53+
},
54+
) {
55+
let query = this.getCountQuery(tableName, args);
56+
57+
const { where } = args;
58+
const eb = expressionBuilder(query);
59+
60+
if (where) {
61+
query = this.applyWhereConditions(query, where, tableName, eb);
62+
}
63+
64+
return query;
65+
}
66+
67+
private applyWhereConditions<T extends string>(
68+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
69+
query: any,
70+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
71+
where: any,
72+
tableName: T,
73+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
74+
eb: any,
75+
) {
76+
const conditions = Object.entries(where)
77+
.map(([column, value]) =>
78+
buildWhereCondition(column, value, tableName, eb),
79+
)
80+
.filter(Boolean);
81+
82+
return conditions.reduce((q, condition) => {
83+
return q.where(condition as SqlBool);
84+
}, query);
85+
}
86+
87+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
88+
private applySorting(query: any, sortBy: any) {
89+
for (const [column, direction] of Object.entries(sortBy)) {
90+
if (!column || !direction) continue;
91+
const dir: "asc" | "desc" =
92+
direction === SortOrder.ascending ? "asc" : "desc";
93+
query = query.orderBy(column, dir);
94+
}
95+
return query;
96+
}
97+
}

src/services/SupabaseCachingService.ts

Lines changed: 3 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,15 @@ import { GetFractionsArgs } from "../graphql/schemas/args/fractionArgs.js";
88
import { GetSalesArgs } from "../graphql/schemas/args/salesArgs.js";
99
import { kyselyCaching } from "../client/kysely.js";
1010
import { supabaseCaching as supabaseClient } from "../client/supabase.js";
11-
import { expressionBuilder, Kysely, SqlBool } from "kysely";
1211
import { GetAllowlistRecordsArgs } from "../graphql/schemas/args/allowlistRecordArgs.js";
1312
import { singleton } from "tsyringe";
1413
import { BaseArgs } from "../graphql/schemas/args/baseArgs.js";
15-
import { SortOrder } from "../graphql/schemas/enums/sortEnums.js";
16-
import { buildWhereCondition } from "../graphql/schemas/utils/filters-kysely.js";
14+
import { BaseSupabaseService } from "./BaseSupabaseService.js";
1715

1816
@singleton()
19-
export class SupabaseCachingService {
20-
public readonly db: Kysely<CachingDatabase>;
21-
17+
export class SupabaseCachingService extends BaseSupabaseService<CachingDatabase> {
2218
constructor() {
23-
this.db = kyselyCaching;
19+
super(kyselyCaching);
2420
}
2521

2622
// Getters
@@ -229,86 +225,6 @@ export class SupabaseCachingService {
229225
}
230226
}
231227

232-
// Generalized query builder and handler of filter, sort, and pagination
233-
handleGetCount<
234-
DB extends CachingDatabase,
235-
T extends keyof DB & string,
236-
A extends object,
237-
>(
238-
tableName: T,
239-
args: BaseArgs<A> & {
240-
first?: number;
241-
offset?: number;
242-
},
243-
) {
244-
let query = this.getCountQuery(tableName, args);
245-
246-
const { where } = args;
247-
const eb = expressionBuilder(query);
248-
249-
if (where) {
250-
query = this.applyWhereConditions(query, where, tableName, eb);
251-
}
252-
253-
return query;
254-
}
255-
256-
handleGetData<
257-
DB extends CachingDatabase,
258-
T extends keyof DB & string,
259-
A extends object,
260-
>(
261-
tableName: T,
262-
args: BaseArgs<A> & {
263-
first?: number;
264-
offset?: number;
265-
},
266-
) {
267-
let query = this.getDataQuery(tableName, args);
268-
const { where, first, offset, sort } = args;
269-
const eb = expressionBuilder(query);
270-
271-
if (where) {
272-
query = this.applyWhereConditions(query, where, tableName, eb);
273-
}
274-
275-
if (sort?.by) {
276-
query = this.applySorting(query, sort.by);
277-
}
278-
279-
if (first) query = query.limit(first);
280-
if (offset) query = query.offset(offset);
281-
282-
return query;
283-
}
284-
285-
private applyWhereConditions<T extends string>(
286-
query: never,
287-
where: never,
288-
tableName: T,
289-
eb: never,
290-
) {
291-
const conditions = Object.entries(where)
292-
.map(([column, value]) =>
293-
buildWhereCondition(column, value, tableName, eb),
294-
)
295-
.filter(Boolean);
296-
297-
return conditions.reduce((q, condition) => {
298-
return q.where(condition as SqlBool);
299-
}, query);
300-
}
301-
302-
private applySorting(query: never, sortBy: never) {
303-
for (const [column, direction] of Object.entries(sortBy)) {
304-
if (!column || !direction) continue;
305-
const dir: "asc" | "desc" =
306-
direction === SortOrder.ascending ? "asc" : "desc";
307-
query = query.orderBy(column, dir);
308-
}
309-
return query;
310-
}
311-
312228
getSalesForTokenIds(tokenIds: bigint[]) {
313229
return supabaseClient
314230
.from("sales")

src/services/SupabaseDataService.ts

Lines changed: 3 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,16 @@ import { singleton } from "tsyringe";
1616
import { GetUserArgs } from "../graphql/schemas/args/userArgs.js";
1717
import type { DataDatabase as KyselyDataDatabase } from "../types/kyselySupabaseData.js";
1818
import { BaseArgs } from "../graphql/schemas/args/baseArgs.js";
19-
import { expressionBuilder, Kysely } from "kysely";
20-
import { generateFilterValues } from "../graphql/schemas/utils/filters-kysely.js";
21-
import { SortOrder } from "../graphql/schemas/enums/sortEnums.js";
2219
import { kyselyData } from "../client/kysely.js";
20+
import { BaseSupabaseService } from "./BaseSupabaseService.js";
2321

2422
@singleton()
25-
export class SupabaseDataService {
23+
export class SupabaseDataService extends BaseSupabaseService<KyselyDataDatabase> {
2624
private supabaseData: SupabaseClient<DataDatabase>;
27-
public readonly db: Kysely<KyselyDataDatabase>;
2825

2926
constructor() {
27+
super(kyselyData);
3028
this.supabaseData = supabaseData;
31-
this.db = kyselyData;
3229
}
3330

3431
storeOrder(
@@ -259,146 +256,4 @@ export class SupabaseDataService {
259256
throw new Error(`Table ${tableName.toString()} not found`);
260257
}
261258
}
262-
263-
// Generalized query builder and handler of filter, sort, and pagination
264-
handleGetData<
265-
DB extends KyselyDataDatabase,
266-
T extends keyof DB & string,
267-
A extends object,
268-
>(
269-
tableName: T,
270-
args: BaseArgs<A> & {
271-
first?: number;
272-
offset?: number;
273-
},
274-
) {
275-
let query = this.getDataQuery(tableName, args);
276-
277-
const { where, first, offset, sort } = args;
278-
const eb = expressionBuilder(query);
279-
280-
if (where) {
281-
query = query.where(
282-
eb.and(
283-
Object.entries(where).flatMap(([column, value]) => {
284-
if (!column || !value) return [];
285-
286-
if (typeof value === "object" && !Array.isArray(value)) {
287-
return Object.entries(value).flatMap(([_column, _value]) => {
288-
if (!_column || !_value) return [];
289-
290-
const res = generateFilterValues(column, _column, _value);
291-
if (res.length > 0) {
292-
return eb(
293-
`${tableName.toString()}.${res[0]}`,
294-
res[1],
295-
res[2],
296-
);
297-
}
298-
299-
const filters = [];
300-
for (const [operator, operand] of Object.entries(_value)) {
301-
if (!operand) continue;
302-
303-
const _table = column;
304-
305-
const [_col, _symbol, _input] = generateFilterValues(
306-
`${_table}.${_column}`,
307-
operator,
308-
operand,
309-
);
310-
311-
filters.push(eb(_col, _symbol, _input));
312-
}
313-
314-
return filters.flat();
315-
});
316-
}
317-
318-
return column && value ? eb(column, "=", value) : [];
319-
}),
320-
),
321-
);
322-
}
323-
324-
if (sort) {
325-
if (sort?.by) {
326-
const { by } = sort;
327-
for (const [column, direction] of Object.entries(by)) {
328-
if (!column || !direction) continue;
329-
330-
const dir: "asc" | "desc" =
331-
direction === SortOrder.ascending ? "asc" : "desc";
332-
333-
query = query.orderBy(column, dir);
334-
}
335-
}
336-
}
337-
338-
if (first) query = query.limit(first);
339-
if (offset) query = query.offset(offset);
340-
341-
return query;
342-
}
343-
344-
handleGetCount<
345-
DB extends KyselyDataDatabase,
346-
T extends keyof DB & string,
347-
A extends object,
348-
>(
349-
tableName: T,
350-
args: BaseArgs<A> & {
351-
first?: number;
352-
offset?: number;
353-
},
354-
) {
355-
let query = this.getCountQuery(tableName, args);
356-
357-
const { where } = args;
358-
const eb = expressionBuilder(query);
359-
360-
if (where) {
361-
query = query.where(
362-
eb.and(
363-
Object.entries(where).flatMap(([column, value]) => {
364-
if (!column || !value) return [];
365-
366-
if (typeof value === "object" && !Array.isArray(value)) {
367-
return Object.entries(value).flatMap(([_column, _value]) => {
368-
if (!_column || !_value) return [];
369-
370-
const res = generateFilterValues(column, _column, _value);
371-
if (res.length > 0) {
372-
return eb(
373-
`${tableName.toString()}.${res[0]}`,
374-
res[1],
375-
res[2],
376-
);
377-
}
378-
379-
const filters = [];
380-
for (const [operator, operand] of Object.entries(_value)) {
381-
if (!operand) continue;
382-
383-
const _table = column;
384-
385-
const [_col, _symbol, _input] = generateFilterValues(
386-
`${_table}.${_column}`,
387-
operator,
388-
operand,
389-
);
390-
filters.push(eb(_col, _symbol, _input));
391-
}
392-
393-
return filters.flat();
394-
});
395-
}
396-
return column && value ? eb(column, "=", value) : [];
397-
}),
398-
),
399-
);
400-
}
401-
402-
return query;
403-
}
404259
}

0 commit comments

Comments
 (0)