Skip to content

Commit e6aa703

Browse files
committed
Add few optimizations
1 parent cdb8027 commit e6aa703

File tree

2 files changed

+188
-188
lines changed

2 files changed

+188
-188
lines changed

packages/transaction-decoder/src/sql/abi-store.ts

Lines changed: 113 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,92 @@ import * as AbiStore from '../abi-store.js'
22
import { Effect, Layer } from 'effect'
33
import { SqlClient } from '@effect/sql'
44

5+
// Utility function to build query conditions for a single key
6+
const buildQueryForKey = (
7+
sql: SqlClient.SqlClient,
8+
{ address, signature, event, chainID }: { address: string; signature?: string; event?: string; chainID: number },
9+
) => {
10+
const addressQuery = sql.and([
11+
sql`address = ${address.toLowerCase()}`,
12+
sql`chain = ${chainID}`,
13+
sql`type = 'address'`,
14+
])
15+
16+
const signatureQuery = signature ? sql.and([sql`signature = ${signature}`, sql`type = 'func'`]) : undefined
17+
const eventQuery = event ? sql.and([sql`event = ${event}`, sql`type = 'event'`]) : undefined
18+
19+
return signature == null && event == null
20+
? addressQuery
21+
: sql.or([addressQuery, signatureQuery, eventQuery].filter(Boolean))
22+
}
23+
24+
// Convert database items to result format
25+
const createResult = (items: readonly any[], address: string, chainID: number): AbiStore.ContractAbiResult => {
26+
const successItems = items.filter((item) => item.status === 'success')
27+
28+
const item =
29+
successItems.find((item) => {
30+
// Prioritize address over fragments
31+
return item.type === 'address'
32+
}) ?? successItems[0]
33+
34+
if (item != null) {
35+
return {
36+
status: 'success',
37+
result: {
38+
type: item.type,
39+
event: item.event,
40+
signature: item.signature,
41+
address,
42+
chainID,
43+
abi: item.abi,
44+
},
45+
} as AbiStore.ContractAbiResult
46+
} else if (items[0] != null && items[0].status === 'not-found') {
47+
return {
48+
status: 'not-found',
49+
result: null,
50+
}
51+
}
52+
53+
return {
54+
status: 'empty',
55+
result: null,
56+
}
57+
}
58+
59+
// Build single lookup map with prefixed keys
60+
const buildLookupMap = (allItems: readonly any[]) => {
61+
const lookupMap = new Map<string, any[]>()
62+
63+
const addToMap = (key: string, item: any) => {
64+
if (!lookupMap.has(key)) lookupMap.set(key, [])
65+
lookupMap.get(key)?.push(item)
66+
}
67+
68+
for (const item of allItems) {
69+
// Address-based lookup: "addr:address_chain" (with same type check as original)
70+
if (typeof item.address === 'string' && typeof item.chain === 'number') {
71+
const addressKey = `addr:${item.address.toLowerCase()}_${item.chain}`
72+
addToMap(addressKey, item)
73+
}
74+
75+
// Signature-based lookup: "sig:signature"
76+
if (item.signature && item.type === 'func') {
77+
const signatureKey = `sig:${item.signature}`
78+
addToMap(signatureKey, item)
79+
}
80+
81+
// Event-based lookup: "event:event"
82+
if (item.event && item.type === 'event') {
83+
const eventKey = `event:${item.event}`
84+
addToMap(eventKey, item)
85+
}
86+
}
87+
88+
return lookupMap
89+
}
90+
591
export const make = (strategies: AbiStore.AbiStore['strategies']) =>
692
Layer.scoped(
793
AbiStore.AbiStore,
@@ -89,141 +175,55 @@ export const make = (strategies: AbiStore.AbiStore['strategies']) =>
89175

90176
get: ({ address, signature, event, chainID }) =>
91177
Effect.gen(function* () {
92-
const addressQuery = sql.and([
93-
sql`address = ${address.toLowerCase()}`,
94-
sql`chain = ${chainID}`,
95-
sql`type = 'address'`,
96-
])
97-
98-
const signatureQuery = signature ? sql.and([sql`signature = ${signature}`, sql`type = 'func'`]) : undefined
99-
const eventQuery = event ? sql.and([sql`event = ${event}`, sql`type = 'event'`]) : undefined
100-
const query =
101-
signature == null && event == null
102-
? addressQuery
103-
: sql.or([addressQuery, signatureQuery, eventQuery].filter(Boolean))
178+
const query = buildQueryForKey(sql, { address, signature, event, chainID })
104179

105180
const items = yield* sql` SELECT * FROM ${table} WHERE ${query}`.pipe(
106181
Effect.tapError(Effect.logError),
107182
Effect.catchAll(() => Effect.succeed([])),
108183
)
109184

110-
const successItems = items.filter((item) => item.status === 'success')
111-
112-
const item =
113-
successItems.find((item) => {
114-
// Prioritize address over fragments
115-
return item.type === 'address'
116-
}) ?? successItems[0]
117-
118-
if (item != null) {
119-
return {
120-
status: 'success',
121-
result: {
122-
type: item.type,
123-
event: item.event,
124-
signature: item.signature,
125-
address,
126-
chainID,
127-
abi: item.abi,
128-
},
129-
} as AbiStore.ContractAbiResult
130-
} else if (items[0] != null && items[0].status === 'not-found') {
131-
return {
132-
status: 'not-found',
133-
result: null,
134-
}
135-
}
136-
137-
return {
138-
status: 'empty',
139-
result: null,
140-
}
185+
return createResult(items, address, chainID)
141186
}),
142187

143188
getMany: (keys) =>
144189
Effect.gen(function* () {
145-
if (keys.length === 0) {
146-
return []
147-
}
148-
149-
// Build a batch query for all the keys
150-
const conditions = keys.map(({ address, signature, event, chainID }) => {
151-
const addressQuery = sql.and([
152-
sql`address = ${address.toLowerCase()}`,
153-
sql`chain = ${chainID}`,
154-
sql`type = 'address'`,
155-
])
156-
157-
const signatureQuery = signature
158-
? sql.and([sql`signature = ${signature}`, sql`type = 'func'`])
159-
: undefined
160-
const eventQuery = event ? sql.and([sql`event = ${event}`, sql`type = 'event'`]) : undefined
161-
162-
return signature == null && event == null
163-
? addressQuery
164-
: sql.or([addressQuery, signatureQuery, eventQuery].filter(Boolean))
165-
})
190+
if (keys.length === 0) return []
166191

192+
// Single database query for all keys
193+
const conditions = keys.map((key) => buildQueryForKey(sql, key))
167194
const batchQuery = sql.or(conditions)
168195

169196
const allItems = yield* sql`SELECT * FROM ${table} WHERE ${batchQuery}`.pipe(
170197
Effect.tapError(Effect.logError),
171198
Effect.catchAll(() => Effect.succeed([])),
172199
)
173200

174-
// Process results for each key
201+
// Build efficient lookup map once
202+
const lookupMap = buildLookupMap(allItems)
203+
204+
// Process results for each key using lookup map
175205
return keys.map(({ address, signature, event, chainID }) => {
176-
const keyItems = allItems.filter((item) => {
177-
// Match by address and chain
178-
if (
179-
typeof item.address === 'string' &&
180-
item.address.toLowerCase() === address.toLowerCase() &&
181-
item.chain === chainID
182-
) {
183-
return true
184-
}
185-
// Match by signature
186-
if (signature && item.signature === signature && item.type === 'func') {
187-
return true
188-
}
189-
// Match by event
190-
if (event && item.event === event && item.type === 'event') {
191-
return true
192-
}
193-
return false
194-
})
195-
196-
const successItems = keyItems.filter((item) => item.status === 'success')
197-
198-
const item =
199-
successItems.find((item) => {
200-
// Prioritize address over fragments
201-
return item.type === 'address'
202-
}) ?? successItems[0]
203-
204-
if (item != null) {
205-
return {
206-
status: 'success',
207-
result: {
208-
type: item.type,
209-
event: item.event,
210-
signature: item.signature,
211-
address,
212-
chainID,
213-
abi: item.abi,
214-
},
215-
} as AbiStore.ContractAbiResult
216-
} else if (keyItems[0] != null && keyItems[0].status === 'not-found') {
217-
return {
218-
status: 'not-found',
219-
result: null,
220-
}
206+
const keyItems: any[] = []
207+
208+
// Get address-based matches
209+
const addressKey = `addr:${address.toLowerCase()}_${chainID}`
210+
const addressItems = lookupMap.get(addressKey) || []
211+
keyItems.push(...addressItems)
212+
213+
// Get signature-based matches
214+
if (signature) {
215+
const signatureKey = `sig:${signature}`
216+
const signatureItems = lookupMap.get(signatureKey) || []
217+
keyItems.push(...signatureItems)
221218
}
222219

223-
return {
224-
status: 'empty',
225-
result: null,
220+
// Get event-based matches
221+
if (event) {
222+
const eventKey = `event:${event}`
223+
const eventItems = lookupMap.get(eventKey) || []
224+
keyItems.push(...eventItems)
226225
}
226+
return createResult(keyItems, address, chainID)
227227
})
228228
}),
229229
})

0 commit comments

Comments
 (0)