Skip to content

Commit d7769bb

Browse files
committed
refactor: share filter-building logic between findByFilters and countByFilters
1 parent 90e4778 commit d7769bb

1 file changed

Lines changed: 78 additions & 142 deletions

File tree

src/repositories/event-repository.ts

Lines changed: 78 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -71,90 +71,16 @@ export class EventRepository implements IEventRepository {
7171
const queries = filters.map((currentFilter) => {
7272
const builder = this.readReplicaDbClient<DBEvent>('events')
7373

74-
forEachObjIndexed((tableFields: string[], filterName: string | number) => {
75-
builder.andWhere((bd) => {
76-
cond([
77-
[isEmpty, () => void bd.whereRaw('1 = 0')],
78-
[
79-
complement(isNil),
80-
pipe(
81-
groupByLengthSpec,
82-
evolve({
83-
exact: (pubkeys: string[]) =>
84-
tableFields.forEach((tableField) => bd.orWhereIn(tableField, pubkeys.map(toBuffer))),
85-
even: forEach((prefix: string) =>
86-
tableFields.forEach((tableField) =>
87-
bd.orWhereRaw(`substring("${tableField}" from 1 for ?) = ?`, [
88-
prefix.length >> 1,
89-
toBuffer(prefix),
90-
]),
91-
),
92-
),
93-
odd: forEach((prefix: string) =>
94-
tableFields.forEach((tableField) =>
95-
bd.orWhereRaw(`substring("${tableField}" from 1 for ?) BETWEEN ? AND ?`, [
96-
(prefix.length >> 1) + 1,
97-
`\\x${prefix}0`,
98-
`\\x${prefix}f`,
99-
]),
100-
),
101-
),
102-
} as any),
103-
),
104-
],
105-
])(currentFilter[filterName] as string[])
106-
})
107-
})({
108-
authors: ['event_pubkey'],
109-
ids: ['event_id'],
110-
})
111-
112-
if (Array.isArray(currentFilter.kinds)) {
113-
builder.whereIn('event_kind', currentFilter.kinds)
114-
}
115-
116-
if (typeof currentFilter.since === 'number') {
117-
builder.where('event_created_at', '>=', currentFilter.since)
118-
}
119-
120-
if (typeof currentFilter.until === 'number') {
121-
builder.where('event_created_at', '<=', currentFilter.until)
122-
}
74+
const isTagQuery = this.applyFilterConditions(builder, currentFilter)
12375

12476
if (typeof currentFilter.limit === 'number') {
12577
builder.limit(currentFilter.limit).orderBy('event_created_at', 'DESC').orderBy('event_id', 'asc')
12678
} else {
12779
builder.limit(500).orderBy('event_created_at', 'asc').orderBy('event_id', 'asc')
12880
}
12981

130-
const andWhereRaw = invoker(1, 'andWhereRaw')
131-
const orWhereRaw = invoker(2, 'orWhereRaw')
132-
133-
let isTagQuery = false
134-
pipe(
135-
toPairs,
136-
filter(pipe(nth(0) as () => string, isGenericTagQuery)) as any,
137-
forEach(([filterName, criteria]: [string, string[]]) => {
138-
isTagQuery = true
139-
builder.andWhere((bd) => {
140-
ifElse(
141-
isEmpty,
142-
() => andWhereRaw('1 = 0', bd),
143-
forEach(
144-
(criterion: string) =>
145-
void orWhereRaw(
146-
'event_tags.tag_name = ? AND event_tags.tag_value = ?',
147-
[filterName[1], criterion],
148-
bd,
149-
),
150-
),
151-
)(criteria)
152-
})
153-
}),
154-
)(currentFilter as any)
155-
15682
if (isTagQuery) {
157-
builder.leftJoin('event_tags', 'events.event_id', 'event_tags.event_id').select('events.*')
83+
builder.select('events.*')
15884
}
15985

16086
return builder
@@ -180,78 +106,14 @@ export class EventRepository implements IEventRepository {
180106
const queries = filters.map((currentFilter) => {
181107
const builder = this.readReplicaDbClient<DBEvent>('events').select('events.event_id')
182108

183-
forEachObjIndexed((tableFields: string[], filterName: string | number) => {
184-
builder.andWhere((bd) => {
185-
cond([
186-
[isEmpty, () => void bd.whereRaw('1 = 0')],
187-
[
188-
complement(isNil),
189-
pipe(
190-
groupByLengthSpec,
191-
evolve({
192-
exact: (pubkeys: string[]) =>
193-
tableFields.forEach((tableField) => bd.orWhereIn(tableField, pubkeys.map(toBuffer))),
194-
even: forEach((prefix: string) =>
195-
tableFields.forEach((tableField) =>
196-
bd.orWhereRaw(`substring("${tableField}" from 1 for ?) = ?`, [prefix.length >> 1, toBuffer(prefix)]),
197-
),
198-
),
199-
odd: forEach((prefix: string) =>
200-
tableFields.forEach((tableField) =>
201-
bd.orWhereRaw(`substring("${tableField}" from 1 for ?) BETWEEN ? AND ?`, [
202-
(prefix.length >> 1) + 1,
203-
`\\x${prefix}0`,
204-
`\\x${prefix}f`,
205-
]),
206-
),
207-
),
208-
} as any),
209-
),
210-
],
211-
])(currentFilter[filterName] as string[])
212-
})
213-
})({ authors: ['event_pubkey'], ids: ['event_id'] })
214-
215-
if (Array.isArray(currentFilter.kinds)) {
216-
builder.whereIn('event_kind', currentFilter.kinds)
217-
}
218-
219-
if (typeof currentFilter.since === 'number') {
220-
builder.where('event_created_at', '>=', currentFilter.since)
221-
}
222-
223-
if (typeof currentFilter.until === 'number') {
224-
builder.where('event_created_at', '<=', currentFilter.until)
225-
}
109+
const isTagQuery = this.applyFilterConditions(builder, currentFilter)
226110

227111
if (typeof currentFilter.limit === 'number') {
228112
builder.limit(currentFilter.limit).orderBy('event_created_at', 'DESC').orderBy('event_id', 'asc')
229113
}
230114

231-
const andWhereRaw = invoker(1, 'andWhereRaw')
232-
const orWhereRaw = invoker(2, 'orWhereRaw')
233-
234-
let isTagQuery = false
235-
pipe(
236-
toPairs,
237-
filter(pipe(nth(0) as () => string, isGenericTagQuery)) as any,
238-
forEach(([filterName, criteria]: [string, string[]]) => {
239-
isTagQuery = true
240-
builder.andWhere((bd) => {
241-
ifElse(
242-
isEmpty,
243-
() => andWhereRaw('1 = 0', bd),
244-
forEach(
245-
(criterion: string) =>
246-
void orWhereRaw('event_tags.tag_name = ? AND event_tags.tag_value = ?', [filterName[1], criterion], bd),
247-
),
248-
)(criteria)
249-
})
250-
}),
251-
)(currentFilter as any)
252-
253115
if (isTagQuery) {
254-
builder.leftJoin('event_tags', 'events.event_id', 'event_tags.event_id').select('events.event_id')
116+
builder.select('events.event_id')
255117
}
256118

257119
builder.whereNull('events.deleted_at').andWhere((bd) => {
@@ -271,6 +133,80 @@ export class EventRepository implements IEventRepository {
271133
return Number(result?.count ?? 0)
272134
}
273135

136+
private applyFilterConditions(builder: any, currentFilter: SubscriptionFilter): boolean {
137+
forEachObjIndexed((tableFields: string[], filterName: string | number) => {
138+
builder.andWhere((bd) => {
139+
cond([
140+
[isEmpty, () => void bd.whereRaw('1 = 0')],
141+
[
142+
complement(isNil),
143+
pipe(
144+
groupByLengthSpec,
145+
evolve({
146+
exact: (pubkeys: string[]) =>
147+
tableFields.forEach((tableField) => bd.orWhereIn(tableField, pubkeys.map(toBuffer))),
148+
even: forEach((prefix: string) =>
149+
tableFields.forEach((tableField) =>
150+
bd.orWhereRaw(`substring("${tableField}" from 1 for ?) = ?`, [prefix.length >> 1, toBuffer(prefix)]),
151+
),
152+
),
153+
odd: forEach((prefix: string) =>
154+
tableFields.forEach((tableField) =>
155+
bd.orWhereRaw(`substring("${tableField}" from 1 for ?) BETWEEN ? AND ?`, [
156+
(prefix.length >> 1) + 1,
157+
`\\x${prefix}0`,
158+
`\\x${prefix}f`,
159+
]),
160+
),
161+
),
162+
} as any),
163+
),
164+
],
165+
])(currentFilter[filterName] as string[])
166+
})
167+
})({ authors: ['event_pubkey'], ids: ['event_id'] })
168+
169+
if (Array.isArray(currentFilter.kinds)) {
170+
builder.whereIn('event_kind', currentFilter.kinds)
171+
}
172+
173+
if (typeof currentFilter.since === 'number') {
174+
builder.where('event_created_at', '>=', currentFilter.since)
175+
}
176+
177+
if (typeof currentFilter.until === 'number') {
178+
builder.where('event_created_at', '<=', currentFilter.until)
179+
}
180+
181+
const andWhereRaw = invoker(1, 'andWhereRaw')
182+
const orWhereRaw = invoker(2, 'orWhereRaw')
183+
184+
let isTagQuery = false
185+
pipe(
186+
toPairs,
187+
filter(pipe(nth(0) as () => string, isGenericTagQuery)) as any,
188+
forEach(([filterName, criteria]: [string, string[]]) => {
189+
isTagQuery = true
190+
builder.andWhere((bd) => {
191+
ifElse(
192+
isEmpty,
193+
() => andWhereRaw('1 = 0', bd),
194+
forEach(
195+
(criterion: string) =>
196+
void orWhereRaw('event_tags.tag_name = ? AND event_tags.tag_value = ?', [filterName[1], criterion], bd),
197+
),
198+
)(criteria)
199+
})
200+
}),
201+
)(currentFilter as any)
202+
203+
if (isTagQuery) {
204+
builder.leftJoin('event_tags', 'events.event_id', 'event_tags.event_id')
205+
}
206+
207+
return isTagQuery
208+
}
209+
274210
public async create(event: Event): Promise<number> {
275211
return this.insert(event).then(prop('rowCount') as () => number, () => 0)
276212
}

0 commit comments

Comments
 (0)