Skip to content

Commit 660ce64

Browse files
committed
feat: fix graphtally database model and add migrations
Signed-off-by: Tomás Migone <[email protected]>
1 parent 3579e8e commit 660ce64

File tree

3 files changed

+590
-38
lines changed

3 files changed

+590
-38
lines changed
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
import { Logger } from '@graphprotocol/common-ts'
2+
import { QueryInterface, DataTypes } from 'sequelize'
3+
4+
interface MigrationContext {
5+
queryInterface: QueryInterface
6+
logger: Logger
7+
}
8+
9+
interface Context {
10+
context: MigrationContext
11+
}
12+
13+
export async function up({ context }: Context): Promise<void> {
14+
const { queryInterface, logger } = context
15+
16+
const tables = await queryInterface.showAllTables()
17+
logger.debug(`Checking if tap_horizon_receipts table exists`, { tables })
18+
19+
if (tables.includes('tap_horizon_receipts')) {
20+
logger.debug(`tap_horizon_receipts already exist, migration not necessary`)
21+
} else {
22+
logger.info(`Create tap_horizon_receipts`)
23+
await queryInterface.createTable('tap_horizon_receipts', {
24+
id: {
25+
type: DataTypes.BIGINT,
26+
primaryKey: true,
27+
autoIncrement: true,
28+
},
29+
allocation_id: {
30+
type: DataTypes.CHAR(40),
31+
allowNull: false,
32+
},
33+
signer_address: {
34+
type: DataTypes.CHAR(40),
35+
allowNull: false,
36+
},
37+
signature: {
38+
type: DataTypes.BLOB,
39+
allowNull: false,
40+
},
41+
timestamp_ns: {
42+
type: DataTypes.DECIMAL(20),
43+
allowNull: false,
44+
},
45+
nonce: {
46+
type: DataTypes.DECIMAL,
47+
allowNull: false,
48+
},
49+
value: {
50+
type: DataTypes.DECIMAL(39),
51+
allowNull: false,
52+
},
53+
})
54+
}
55+
56+
logger.debug('Create function and trigger using raw SQL')
57+
const functionSQL = `
58+
CREATE FUNCTION tap_horizon_receipt_notify()
59+
RETURNS trigger AS
60+
$$
61+
BEGIN
62+
PERFORM pg_notify('tap_horizon_receipt_notification', format('{"id": %s, "allocation_id": "%s", "signer_address": "%s", "timestamp_ns": %s, "value": %s}', NEW.id, NEW.allocation_id, NEW.signer_address, NEW.timestamp_ns, NEW.value));
63+
RETURN NEW;
64+
END;
65+
$$ LANGUAGE 'plpgsql';
66+
`
67+
const triggerSQL = `
68+
CREATE TRIGGER receipt_update AFTER INSERT OR UPDATE
69+
ON tap_horizon_receipts
70+
FOR EACH ROW EXECUTE PROCEDURE tap_horizon_receipt_notify();
71+
`
72+
await queryInterface.sequelize.query(functionSQL)
73+
await queryInterface.sequelize.query(triggerSQL)
74+
75+
queryInterface.addIndex('tap_horizon_receipts', ['allocation_id'], {
76+
name: 'tap_horizon_receipts_allocation_id_idx',
77+
})
78+
queryInterface.addIndex('tap_horizon_receipts', ['timestamp_ns'], {
79+
name: 'tap_horizon_receipts_timestamp_ns_idx',
80+
})
81+
82+
if (tables.includes('tap_horizon_receipts_invalid')) {
83+
logger.info(
84+
`tap_horizon_receipts_invalid already exist, migration not necessary`,
85+
)
86+
} else {
87+
// Create the tap_horizon_ravs table if it doesn't exist
88+
await queryInterface.createTable('tap_horizon_receipts_invalid', {
89+
id: {
90+
type: DataTypes.BIGINT,
91+
primaryKey: true,
92+
autoIncrement: true,
93+
},
94+
allocation_id: {
95+
type: DataTypes.CHAR(40),
96+
allowNull: false,
97+
},
98+
signer_address: {
99+
type: DataTypes.CHAR(40),
100+
allowNull: false,
101+
},
102+
signature: {
103+
type: DataTypes.BLOB,
104+
allowNull: false,
105+
},
106+
timestamp_ns: {
107+
type: DataTypes.DECIMAL(20),
108+
allowNull: false,
109+
},
110+
nonce: {
111+
type: DataTypes.DECIMAL,
112+
allowNull: false,
113+
},
114+
value: {
115+
type: DataTypes.DECIMAL(20),
116+
allowNull: false,
117+
},
118+
})
119+
}
120+
121+
if (tables.includes('tap_horizon_ravs')) {
122+
logger.info(`tap_horizon_ravs already exist, migration not necessary`)
123+
} else {
124+
// Create the tap_horizon_ravs table if it doesn't exist
125+
await queryInterface.createTable('tap_horizon_ravs', {
126+
collection_id: {
127+
type: DataTypes.CHAR(64),
128+
allowNull: false,
129+
},
130+
sender_address: {
131+
type: DataTypes.CHAR(40),
132+
allowNull: false,
133+
},
134+
service_provider_address: {
135+
type: DataTypes.CHAR(40),
136+
allowNull: false,
137+
},
138+
data_service_address: {
139+
type: DataTypes.CHAR(40),
140+
allowNull: false,
141+
},
142+
signature: {
143+
type: DataTypes.BLOB,
144+
allowNull: false,
145+
},
146+
timestamp_ns: {
147+
type: DataTypes.DECIMAL,
148+
allowNull: false,
149+
},
150+
value_aggregate: {
151+
type: DataTypes.DECIMAL(39),
152+
allowNull: false,
153+
},
154+
metadata: {
155+
type: DataTypes.BLOB,
156+
allowNull: false,
157+
},
158+
final: {
159+
type: DataTypes.BOOLEAN,
160+
allowNull: false,
161+
defaultValue: false,
162+
},
163+
last: {
164+
type: DataTypes.BOOLEAN,
165+
allowNull: false,
166+
defaultValue: false,
167+
},
168+
redeemed_at: {
169+
type: DataTypes.DATE,
170+
allowNull: true,
171+
},
172+
created_at: {
173+
type: DataTypes.DATE,
174+
allowNull: false,
175+
},
176+
updated_at: {
177+
type: DataTypes.DATE,
178+
allowNull: false,
179+
},
180+
})
181+
}
182+
183+
logger.info(`Add primary key`)
184+
await queryInterface.addConstraint('tap_horizon_ravs', {
185+
fields: ['collection_id', 'sender_address', 'service_provider_address', 'data_service_address'],
186+
type: 'primary key',
187+
name: 'pk_tap_horizon_ravs',
188+
})
189+
190+
await queryInterface.createTable('tap_horizon_rav_requests_failed', {
191+
id: {
192+
type: DataTypes.BIGINT,
193+
primaryKey: true,
194+
autoIncrement: true,
195+
},
196+
collection_id: {
197+
type: DataTypes.CHAR(64),
198+
allowNull: false,
199+
},
200+
sender_address: {
201+
type: DataTypes.CHAR(40),
202+
allowNull: false,
203+
},
204+
service_provider_address: {
205+
type: DataTypes.CHAR(40),
206+
allowNull: false,
207+
},
208+
data_service_address: {
209+
type: DataTypes.CHAR(40),
210+
allowNull: false,
211+
},
212+
expected_rav: {
213+
type: DataTypes.JSON,
214+
allowNull: false,
215+
},
216+
rav_response: {
217+
type: DataTypes.JSON,
218+
allowNull: false,
219+
},
220+
reason: {
221+
allowNull: false,
222+
type: DataTypes.TEXT,
223+
},
224+
})
225+
}
226+
227+
export async function down({ context }: Context): Promise<void> {
228+
const { queryInterface, logger } = context
229+
// Drop the tap_horizon_ravs table
230+
logger.info(`Drop table`)
231+
await queryInterface.dropTable('tap_horizon_ravs')
232+
233+
logger.info(`Drop function, trigger, indices, and table`)
234+
await queryInterface.sequelize.query(
235+
'DROP TRIGGER IF EXISTS receipt_update ON tap_horizon_receipts',
236+
)
237+
await queryInterface.sequelize.query(
238+
'DROP FUNCTION IF EXISTS tap_horizon_receipt_notify',
239+
)
240+
await queryInterface.removeIndex(
241+
'tap_horizon_receipts',
242+
'tap_horizon_receipts_allocation_id_idx',
243+
)
244+
await queryInterface.removeIndex(
245+
'tap_horizon_receipts',
246+
'tap_horizon_receipts_timestamp_ns_idx',
247+
)
248+
await queryInterface.dropTable('tap_horizon_receipts')
249+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Logger } from '@graphprotocol/common-ts'
2+
3+
import { QueryInterface, DataTypes } from 'sequelize'
4+
5+
interface MigrationContext {
6+
queryInterface: QueryInterface
7+
logger: Logger
8+
}
9+
10+
interface Context {
11+
context: MigrationContext
12+
}
13+
14+
export async function up({ context }: Context): Promise<void> {
15+
const { queryInterface, logger } = context
16+
17+
const tables = await queryInterface.showAllTables()
18+
logger.debug(`Checking if tap_horizon_denylist table exists`, { tables })
19+
20+
if (tables.includes('tap_horizon_denylist')) {
21+
logger.debug(`tap_horizon_denylist already exist, migration not necessary`)
22+
} else {
23+
logger.info(`Create tap_horizon_denylist`)
24+
await queryInterface.createTable('tap_horizon_denylist', {
25+
id: {
26+
type: DataTypes.BIGINT,
27+
primaryKey: true,
28+
autoIncrement: true,
29+
},
30+
sender_address: {
31+
type: DataTypes.CHAR(40),
32+
allowNull: false,
33+
},
34+
})
35+
}
36+
const functionSQL = `
37+
CREATE FUNCTION tap_horizon_deny_notify()
38+
RETURNS trigger AS
39+
$$
40+
BEGIN
41+
IF TG_OP = 'DELETE' THEN
42+
PERFORM pg_notify('tap_horizon_deny_notification', format('{"tg_op": "DELETE", "sender_address": "%s"}', OLD.sender_address));
43+
RETURN OLD;
44+
ELSIF TG_OP = 'INSERT' THEN
45+
PERFORM pg_notify('tap_horizon_deny_notification', format('{"tg_op": "INSERT", "sender_address": "%s"}', NEW.sender_address));
46+
RETURN NEW;
47+
ELSE -- UPDATE OR TRUNCATE, should never happen
48+
PERFORM pg_notify('tap_horizon_deny_notification', format('{"tg_op": "%s", "sender_address": null}', TG_OP, NEW.sender_address));
49+
RETURN NEW;
50+
END IF;
51+
END;
52+
$$ LANGUAGE 'plpgsql';
53+
`
54+
const triggerSQL = `
55+
CREATE TRIGGER deny_update AFTER INSERT OR UPDATE OR DELETE
56+
ON tap_horizon_denylist
57+
FOR EACH ROW EXECUTE PROCEDURE tap_horizon_deny_notify();
58+
`
59+
60+
await queryInterface.sequelize.query(functionSQL)
61+
await queryInterface.sequelize.query(triggerSQL)
62+
}
63+
64+
export async function down({ context }: Context): Promise<void> {
65+
const { queryInterface, logger } = context
66+
67+
logger.info(`Drop tap_horizon_denylist`)
68+
await queryInterface.sequelize.query(
69+
'DROP TRIGGER IF EXISTS deny_update ON tap_horizon_denylist',
70+
)
71+
logger.info(`Drop function tap_horizon_deny_notify`)
72+
await queryInterface.sequelize.query(
73+
'DROP FUNCTION IF EXISTS tap_horizon_deny_notify',
74+
)
75+
logger.info(`Drop table tap_horizon_denylist`)
76+
await queryInterface.dropTable('tap_horizon_denylist')
77+
}

0 commit comments

Comments
 (0)