Skip to content
This repository was archived by the owner on Feb 8, 2025. It is now read-only.

Commit 6699edd

Browse files
committed
perf(api): parameterize db queries
1 parent d21960e commit 6699edd

18 files changed

+362
-227
lines changed

api/src/feat/activations/activations.service.ts

+21-15
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,14 @@ export class ActivationsService {
6363
}
6464

6565
async fee({ account, feePerGas }: FeeParams): Promise<Decimal | null> {
66-
const a = await this.db.query(
67-
e.select(e.Account, () => ({
68-
filter_single: { address: account },
69-
activationEthFee: true,
70-
})),
66+
const a = await this.db.queryWith(
67+
{ address: e.UAddress },
68+
({ address }) =>
69+
e.select(e.Account, () => ({
70+
filter_single: { address },
71+
activationEthFee: true,
72+
})),
73+
{ address: account },
7174
);
7275
if (!a) return null;
7376
if (a.activationEthFee) return new Decimal(a.activationEthFee);
@@ -88,17 +91,20 @@ export class ActivationsService {
8891
}
8992

9093
async request(address: UAddress) {
91-
const account = await this.db.query(
92-
e.select(e.Account, (a) => ({
93-
filter_single: { address },
94-
active: true,
95-
implementation: true,
96-
salt: true,
97-
initPolicies: e.select(a.policies, (p) => ({
98-
filter: p.initState,
99-
...PolicyShape,
94+
const account = await this.db.queryWith(
95+
{ address: e.UAddress },
96+
({ address }) =>
97+
e.select(e.Account, (a) => ({
98+
filter_single: { address },
99+
active: true,
100+
implementation: true,
101+
salt: true,
102+
initPolicies: e.select(a.policies, (p) => ({
103+
filter: p.initState,
104+
...PolicyShape,
105+
})),
100106
})),
101-
})),
107+
{ address },
102108
);
103109
if (!account) throw new Error(`Account ${address} not found`);
104110
if (account.active) return null;

api/src/feat/activations/activations.worker.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { ActivationsService } from './activations.service';
77
import { ActivationsQueue } from './activations.queue';
88
import { DatabaseService } from '../../core/database/database.service';
99
import e from '~/edgeql-js';
10+
import { selectTransaction2 } from '../transactions/transactions.util';
1011

1112
@Injectable()
1213
@Processor(ActivationsQueue.name, { autorun: false })
@@ -22,13 +23,12 @@ export class ActivationsWorker extends Worker<ActivationsQueue> {
2223
async process(job: TypedJob<ActivationsQueue>): Promise<QueueReturnType<ActivationsQueue>> {
2324
const { account, sponsoringTransaction } = job.data;
2425

25-
const sponsorTx = await this.db.query(
26-
e.select(e.Transaction, () => ({
27-
filter_single: { id: sponsoringTransaction },
28-
executable: true,
29-
})),
26+
const sponsorTxExecutable = await this.db.queryWith(
27+
{ id: e.uuid },
28+
({ id }) => selectTransaction2(id).executable,
29+
{ id: sponsoringTransaction },
3030
);
31-
if (!sponsorTx?.executable)
31+
if (!sponsorTxExecutable)
3232
return `Sponsoring transaction is not executable: ${sponsoringTransaction}`;
3333

3434
// TODO: handle gas limits given `activationFee`. Currently the activation fee may take an additonal transaction to repay

api/src/feat/auth/accounts.cache.service.ts

+25-19
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,23 @@ export class AccountsCacheService implements OnModuleInit {
5555
accounts: JSON.parse(cachedAccounts) as UserAccountContext[],
5656
};
5757

58-
const { user } = await this.db.query(
59-
e.select(
60-
e.insert(e.Approver, { address: approver }).unlessConflict((a) => ({
61-
on: a.address,
62-
else: a,
63-
})),
64-
() => ({
65-
user: {
66-
id: true,
67-
approvers: { address: true },
68-
accounts: { id: true, address: true },
69-
},
70-
}),
71-
),
58+
const { user } = await this.db.queryWith(
59+
{ approver: e.Address },
60+
({ approver }) =>
61+
e.select(
62+
e.insert(e.Approver, { address: approver }).unlessConflict((a) => ({
63+
on: a.address,
64+
else: a,
65+
})),
66+
() => ({
67+
user: {
68+
id: true,
69+
approvers: { address: true },
70+
accounts: { id: true, address: true },
71+
},
72+
}),
73+
),
74+
{ approver },
7275
);
7376

7477
const accounts = user.accounts.map(
@@ -96,11 +99,14 @@ export class AccountsCacheService implements OnModuleInit {
9699
if (!getUserCtx().accounts.find((a) => a.id === account.id))
97100
getUserCtx().accounts.push(account);
98101

99-
const user = await this.db.query(
100-
e.select(e.Approver, () => ({
101-
filter_single: { address: approver },
102-
user: { id: true },
103-
})).user.id,
102+
const user = await this.db.queryWith(
103+
{ approver: e.Address },
104+
({ approver }) =>
105+
e.select(e.Approver, () => ({
106+
filter_single: { address: approver },
107+
user: { id: true },
108+
})).user.id,
109+
{ approver },
104110
);
105111

106112
if (user) {

api/src/feat/contacts/contacts.service.ts

+33-5
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,44 @@ export const selectContact = (id: UniqueContact) =>
1818
})),
1919
);
2020

21+
export const selectContact2 = (id: UniqueContact) =>
22+
e.assert_single(
23+
e.select(e.Contact, (c) => ({
24+
filter: isUAddress(id)
25+
? and(e.op(c.address, '=', id), e.op(c.user, '=', e.global.current_user))
26+
: e.op(c.id, '=', e.uuid(id)),
27+
})),
28+
);
29+
2130
@Injectable()
2231
export class ContactsService {
2332
constructor(private db: DatabaseService) {}
2433

2534
async selectUnique(id: UniqueContact, shape?: ShapeFunc) {
26-
return this.db.query(
27-
e.select(selectContact(id), (c) => ({
28-
...shape?.(c),
29-
})),
30-
);
35+
return isUAddress(id)
36+
? this.db.queryWith(
37+
{ address: e.UAddress },
38+
({ address }) =>
39+
e.assert_single(
40+
e.select(e.Contact, (c) => ({
41+
filter: and(
42+
e.op(c.address, '=', address),
43+
e.op(c.user, '=', e.global.current_user),
44+
),
45+
...shape?.(c),
46+
})),
47+
),
48+
{ address: id },
49+
)
50+
: this.db.queryWith(
51+
{ id: e.uuid },
52+
({ id }) =>
53+
e.select(e.Contact, (c) => ({
54+
filter_single: { id },
55+
...shape?.(c),
56+
})),
57+
{ id: id },
58+
);
3159
}
3260

3361
async select({ query, chain }: ContactsInput, shape?: ShapeFunc<typeof e.Contact>) {

api/src/feat/messages/messages.service.ts

+45-27
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
hexToString,
1111
keccak256,
1212
} from 'viem';
13-
import e from '~/edgeql-js';
13+
import e, { Set } from '~/edgeql-js';
1414
import { selectAccount } from '../accounts/accounts.util';
1515
import { ProposalsService, UniqueProposal } from '../proposals/proposals.service';
1616
import {
@@ -34,10 +34,15 @@ import { ethers } from 'ethers';
3434
import _ from 'lodash';
3535
import { WritableDeep } from 'ts-toolbelt/out/Object/Writable';
3636
import { PoliciesService } from '../policies/policies.service';
37+
import { $uuid } from '~/edgeql-js/modules/std';
38+
import { $ } from 'edgedb';
3739

3840
export const selectMessage = (id: UUID | Hex) =>
3941
e.select(e.Message, () => ({ filter_single: isHex(id) ? { hash: id } : { id } }));
4042

43+
export const selectMessage2 = (id: Set<$uuid, $.Cardinality.One>) =>
44+
e.select(e.Message, () => ({ filter_single: { id } }));
45+
4146
@Injectable()
4247
export class MessagesService {
4348
constructor(
@@ -133,12 +138,19 @@ export class MessagesService {
133138
}
134139

135140
async remove(proposal: UUID) {
136-
const selectedMessage = selectMessage(proposal);
137-
const { account } = await this.db.query(
138-
e.select({
139-
account: e.assert_exists(selectedMessage.account.address),
140-
deleted: e.delete(selectedMessage),
141-
}),
141+
const { account } = await this.db.queryWith(
142+
{ id: e.uuid },
143+
({ id }) => {
144+
const m = selectMessage2(id);
145+
return e.with(
146+
[m],
147+
e.select({
148+
account: e.assert_exists(m.account.address),
149+
deleted: e.delete(m),
150+
}),
151+
);
152+
},
153+
{ id: proposal },
142154
);
143155

144156
this.proposals.publish({ id: proposal, account: asUAddress(account) }, ProposalEvent.delete);
@@ -147,22 +159,25 @@ export class MessagesService {
147159
}
148160

149161
private async trySign(id: UUID) {
150-
const proposal = await this.db.query(
151-
e.select(e.Message, () => ({
152-
filter_single: { id },
153-
hash: true,
154-
message: true,
155-
typedData: true,
156-
signature: true,
157-
approvals: {
158-
approver: { address: true },
162+
const proposal = await this.db.queryWith(
163+
{ id: e.uuid },
164+
({ id }) =>
165+
e.select(e.Message, () => ({
166+
filter_single: { id },
167+
hash: true,
168+
message: true,
169+
typedData: true,
159170
signature: true,
160-
},
161-
account: {
162-
address: true,
163-
policies: PolicyShape,
164-
},
165-
})),
171+
approvals: {
172+
approver: { address: true },
173+
signature: true,
174+
},
175+
account: {
176+
address: true,
177+
policies: PolicyShape,
178+
},
179+
})),
180+
{ id },
166181
);
167182
if (!proposal) return undefined;
168183

@@ -193,11 +208,14 @@ export class MessagesService {
193208
approvals,
194209
});
195210

196-
await this.db.query(
197-
e.update(e.Message, () => ({
198-
filter_single: { id },
199-
set: { signature },
200-
})),
211+
await this.db.queryWith(
212+
{ id: e.uuid, signature: e.Bytes },
213+
({ id, signature }) =>
214+
e.update(e.Message, () => ({
215+
filter_single: { id },
216+
set: { signature },
217+
})),
218+
{ id, signature },
201219
);
202220

203221
await this.proposals.publish({ id, account }, ProposalEvent.signed);

api/src/feat/policies/policies.events.ts

+23-17
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { DatabaseService } from '../../core/database/database.service';
66
import e from '~/edgeql-js';
77
import { and, or } from '../../core/database/database.util';
88
import { getAbiItem } from 'viem';
9-
import { selectAccount } from '../accounts/accounts.util';
9+
import { selectAccount2 } from '../accounts/accounts.util';
1010

1111
const policyAddedEvent = getAbiItem({ abi: ACCOUNT_ABI, name: 'PolicyAdded' });
1212
const policyRemovedEvent = getAbiItem({ abi: ACCOUNT_ABI, name: 'PolicyRemoved' });
@@ -30,23 +30,29 @@ export class PoliciesEventsProcessor {
3030
}
3131

3232
private async markStateAsActive(chain: Chain, log: Log, key: PolicyKey) {
33-
// TODO: filter state by state hash (part of event log) to ensure correct state is activated
34-
// It's possible that two policies are activated in the same proposal; it's not prohibited by a constraint.
35-
const proposal = e.select(e.SystemTx, () => ({
36-
filter_single: { hash: log.transactionHash },
37-
})).proposal;
33+
await this.db.queryWith(
34+
{ account: e.UAddress, hash: e.Bytes32, activationBlock: e.bigint },
35+
({ account, hash, activationBlock }) => {
36+
// TODO: filter state by state hash (part of event log) to ensure correct state is activated
37+
// It's possible that two policies are activated in the same proposal; it's not prohibited by a constraint.
38+
const proposal = e.select(e.SystemTx, () => ({ filter_single: { hash } })).proposal;
3839

39-
await this.db.query(
40-
e.update(e.PolicyState, (ps) => ({
41-
filter: and(
42-
e.op(ps.account, '=', selectAccount(asUAddress(log.address, chain))),
43-
e.op(ps.key, '=', key),
44-
or(e.op(ps.proposal, '?=', proposal), ps.initState),
45-
),
46-
set: {
47-
activationBlock: log.blockNumber,
48-
},
49-
})),
40+
return e.update(e.PolicyState, (ps) => ({
41+
filter: and(
42+
e.op(ps.account, '?=', selectAccount2(account)),
43+
e.op(ps.key, '=', key),
44+
or(e.op(ps.proposal, '?=', proposal), ps.initState),
45+
),
46+
set: {
47+
activationBlock,
48+
},
49+
}));
50+
},
51+
{
52+
account: asUAddress(log.address, chain),
53+
hash: log.transactionHash,
54+
activationBlock: log.blockNumber,
55+
},
5056
);
5157
}
5258
}

0 commit comments

Comments
 (0)