@rosen-bridge/abstract-extractor 0.3.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/ergo/AbstractErgoExtractor.d.ts +31 -8
  3. package/dist/ergo/AbstractErgoExtractor.d.ts.map +1 -1
  4. package/dist/ergo/AbstractErgoExtractor.js +73 -8
  5. package/dist/ergo/AbstractErgoExtractorAction.d.ts +38 -10
  6. package/dist/ergo/AbstractErgoExtractorAction.d.ts.map +1 -1
  7. package/dist/ergo/AbstractErgoExtractorAction.js +134 -1
  8. package/dist/ergo/AbstractErgoExtractorEntity.d.ts +11 -0
  9. package/dist/ergo/AbstractErgoExtractorEntity.d.ts.map +1 -0
  10. package/dist/ergo/AbstractErgoExtractorEntity.js +57 -0
  11. package/dist/ergo/index.d.ts +1 -0
  12. package/dist/ergo/index.d.ts.map +1 -1
  13. package/dist/ergo/index.js +2 -1
  14. package/dist/ergo/initializable/AbstractInitializable.d.ts +4 -3
  15. package/dist/ergo/initializable/AbstractInitializable.d.ts.map +1 -1
  16. package/dist/ergo/initializable/AbstractInitializable.js +9 -5
  17. package/dist/ergo/initializable/AbstractInitializableAction.d.ts +7 -2
  18. package/dist/ergo/initializable/AbstractInitializableAction.d.ts.map +1 -1
  19. package/dist/ergo/initializable/AbstractInitializableAction.js +11 -1
  20. package/dist/ergo/interfaces.d.ts +21 -7
  21. package/dist/ergo/interfaces.d.ts.map +1 -1
  22. package/dist/ergo/interfaces.js +8 -1
  23. package/lib/ergo/AbstractErgoExtractor.ts +107 -23
  24. package/lib/ergo/AbstractErgoExtractorAction.ts +187 -18
  25. package/lib/ergo/AbstractErgoExtractorEntity.ts +28 -0
  26. package/lib/ergo/index.ts +1 -0
  27. package/lib/ergo/initializable/AbstractInitializable.ts +22 -9
  28. package/lib/ergo/initializable/AbstractInitializableAction.ts +19 -3
  29. package/lib/ergo/interfaces.ts +25 -7
  30. package/package.json +6 -2
  31. package/tests/{AbstractExtractor.mock.ts → AbstractErgoExtractor.mock.ts} +12 -7
  32. package/tests/AbstractErgoExtractor.spec.ts +281 -0
  33. package/tests/AbstractErgoExtractorAction.mock.ts +45 -0
  34. package/tests/AbstractErgoExtractorAction.spec.ts +269 -0
  35. package/tests/initializable/AbstractInitializable.mock.ts +15 -8
  36. package/tests/initializable/AbstractInitializable.spec.ts +37 -5
  37. package/tests/initializable/AbstractInitializableAction.mock.ts +45 -0
  38. package/tests/initializable/AbstractInitializableAction.spec.ts +65 -0
  39. package/tests/testData.ts +38 -2
  40. package/tests/testUtils.ts +22 -0
  41. package/tsconfig.build.tsbuildinfo +1 -1
  42. package/dist/ergo/initializable/InitializableByAddress.d.ts +0 -19
  43. package/dist/ergo/initializable/InitializableByAddress.d.ts.map +0 -1
  44. package/dist/ergo/initializable/InitializableByAddress.js +0 -30
  45. package/dist/ergo/initializable/InitializableByToken.d.ts +0 -19
  46. package/dist/ergo/initializable/InitializableByToken.d.ts.map +0 -1
  47. package/dist/ergo/initializable/InitializableByToken.js +0 -30
  48. package/dist/tsconfig.tsbuildinfo +0 -1
  49. package/tests/AbstractExtractor.spec.ts +0 -106
@@ -0,0 +1,281 @@
1
+ import { V1 } from '@rosen-clients/ergo-explorer';
2
+ import { describe, it, expect, vitest } from 'vitest';
3
+
4
+ import {
5
+ OutputBox,
6
+ AbstractBoxData,
7
+ AbstractErgoExtractorAction,
8
+ CallbackType,
9
+ AbstractErgoExtractorEntity,
10
+ } from '../lib';
11
+ import { block, extractedData, tx } from './testData';
12
+ import { MockedErgoExtractor } from './AbstractErgoExtractor.mock';
13
+
14
+ describe('AbstractErgoExtractor', () => {
15
+ describe('processTransactions', () => {
16
+ /**
17
+ * @target processTransactions should initialize extractor with specified id and insert status into db
18
+ * @dependencies
19
+ * @scenario
20
+ * - mock extractor
21
+ * - mock `hasData` to return true for one box
22
+ * - spy `extractBoxData` and `storeBoxes`
23
+ * - run test (call `processTransactions`)
24
+ * @expected
25
+ * - to call `extractBoxData` for the specific box
26
+ * - to insert the extracted box to database
27
+ * - to return true when total procedure is successful
28
+ * - to trigger `INSERT` callbacks with correct data
29
+ */
30
+ it('should process boxes with data and insert data into database', async () => {
31
+ const extractor = new MockedErgoExtractor();
32
+ const triggerCallbacks = vitest.fn();
33
+ extractor['triggerCallbacks'] = triggerCallbacks;
34
+ extractor.hasData = (box: V1.OutputInfo | OutputBox) => {
35
+ if (box.boxId == tx.outputs[0].boxId) return true;
36
+ return false;
37
+ };
38
+ const extractSpy = vitest.fn().mockReturnValue(extractedData);
39
+ extractor.extractBoxData = extractSpy;
40
+ const storeSpy = vitest.fn().mockResolvedValue(true);
41
+ const spendSpy = vitest.fn().mockResolvedValue([]);
42
+ extractor['actions'] = {
43
+ storeBoxes: storeSpy,
44
+ spendBoxes: spendSpy,
45
+ } as unknown as AbstractErgoExtractorAction<
46
+ AbstractBoxData,
47
+ AbstractErgoExtractorEntity
48
+ >;
49
+ const result = await extractor.processTransactions([tx], block);
50
+
51
+ expect(extractSpy).toBeCalledTimes(1);
52
+ expect(extractSpy).toBeCalledWith(tx.outputs[0]);
53
+ expect(storeSpy).toBeCalledWith([extractedData], block, 'Test');
54
+ expect(result).toEqual(true);
55
+ expect(triggerCallbacks).toBeCalledWith(CallbackType.Insert, [
56
+ extractedData,
57
+ ]);
58
+ });
59
+
60
+ /**
61
+ * @target processTransactions should extract spending information of all input boxes
62
+ * @dependencies
63
+ * @scenario
64
+ * - mock extractor (hasData returns false as default)
65
+ * - spy `extractBoxData`, `storeBoxes` and `spendBoxes`
66
+ * - run test (call `processTransactions`)
67
+ * @expected
68
+ * - not to call `extractBoxData` and `storeBoxes` when there is not any box with data
69
+ * - to extractor spend info of input boxes and call `spendBoxes`
70
+ * - to return true when total procedure is successful
71
+ * - to trigger `SPEND` callbacks with correct data
72
+ */
73
+ it('should extract spending information of all input boxes', async () => {
74
+ const extractor = new MockedErgoExtractor();
75
+ const triggerCallbacks = vitest.fn();
76
+ extractor['triggerCallbacks'] = triggerCallbacks;
77
+ const extractSpy = vitest.fn();
78
+ extractor.extractBoxData = extractSpy;
79
+ const storeSpy = vitest.fn().mockResolvedValue(true);
80
+ const spendSpy = vitest
81
+ .fn()
82
+ .mockResolvedValue([
83
+ { boxId: tx.inputs[0].boxId },
84
+ { boxId: tx.inputs[1].boxId },
85
+ ]);
86
+ extractor['actions'] = {
87
+ storeBoxes: storeSpy,
88
+ spendBoxes: spendSpy,
89
+ } as unknown as AbstractErgoExtractorAction<
90
+ AbstractBoxData,
91
+ AbstractErgoExtractorEntity
92
+ >;
93
+ const result = await extractor.processTransactions([tx], block);
94
+
95
+ expect(extractSpy).not.toBeCalled();
96
+ expect(storeSpy).not.toBeCalled();
97
+ expect(spendSpy).toBeCalledWith(
98
+ [
99
+ { boxId: tx.inputs[0].boxId, txId: tx.id, index: 1 },
100
+ { boxId: tx.inputs[1].boxId, txId: tx.id, index: 2 },
101
+ ],
102
+ block,
103
+ 'Test'
104
+ );
105
+ expect(result).toEqual(true);
106
+ expect(triggerCallbacks).toBeCalledWith(CallbackType.Spend, [
107
+ { boxId: tx.inputs[0].boxId },
108
+ { boxId: tx.inputs[1].boxId },
109
+ ]);
110
+ });
111
+
112
+ /**
113
+ * @target processTransactions should return false if data insertion fails
114
+ * @dependencies
115
+ * @scenario
116
+ * - mock extractor
117
+ * - mock `hasData` to return true for one box
118
+ * - spy `extractBoxData` and `storeBoxes`
119
+ * - run test (call `processTransactions`)
120
+ * @expected
121
+ * - to return false when `insertBoxes` returns false
122
+ * - not to call `spendBoxes` if data insertion fails
123
+ */
124
+ it('should return false if data insertion fails', async () => {
125
+ const extractor = new MockedErgoExtractor();
126
+ extractor.hasData = (box: V1.OutputInfo | OutputBox) => {
127
+ if (box.boxId == tx.outputs[0].boxId) return true;
128
+ return false;
129
+ };
130
+ const extractSpy = vitest.fn().mockReturnValue(extractedData);
131
+ extractor.extractBoxData = extractSpy;
132
+ const storeSpy = vitest.fn().mockResolvedValue(false);
133
+ const spendSpy = vitest.fn();
134
+ extractor['actions'] = {
135
+ storeBoxes: storeSpy,
136
+ spendBoxes: spendSpy,
137
+ } as unknown as AbstractErgoExtractorAction<
138
+ AbstractBoxData,
139
+ AbstractErgoExtractorEntity
140
+ >;
141
+ const result = await extractor.processTransactions([tx], block);
142
+
143
+ expect(result).toEqual(false);
144
+ expect(spendSpy).not.toBeCalled();
145
+ });
146
+ });
147
+
148
+ describe('forkBlock', () => {
149
+ /**
150
+ * @target forkBlock should remove all data extracted from the specified block
151
+ * @dependencies
152
+ * @scenario
153
+ * - mock extractor
154
+ * - spy `deleteBlockBoxes`
155
+ * - run test (call `forkBlock`)
156
+ * @expected
157
+ * - to call `deleteBlockBoxes` for the specific box
158
+ * - to trigger `DELETE` callbacks for the deleted box
159
+ * - to trigger `UPDATE` callbacks for the spent box
160
+ */
161
+ it('should remove all data extracted from the specified block', async () => {
162
+ const extractor = new MockedErgoExtractor();
163
+ const removeSpy = vitest.fn().mockResolvedValue({
164
+ deletedData: [{ boxId: 'box1' }],
165
+ updatedData: [{ boxId: 'box2' }],
166
+ });
167
+ extractor['actions'] = {
168
+ deleteBlockBoxes: removeSpy,
169
+ } as unknown as AbstractErgoExtractorAction<
170
+ AbstractBoxData,
171
+ AbstractErgoExtractorEntity
172
+ >;
173
+ const triggerCallbackSpy = vitest.fn().mockClear();
174
+ extractor['triggerCallbacks'] = triggerCallbackSpy;
175
+ await extractor.forkBlock(block.hash);
176
+ expect(removeSpy).toBeCalledWith(block.hash, 'Test');
177
+ expect(triggerCallbackSpy).toBeCalledWith(CallbackType.Delete, [
178
+ { boxId: 'box1' },
179
+ ]);
180
+ expect(triggerCallbackSpy).toBeCalledWith(CallbackType.Update, [
181
+ { boxId: 'box2' },
182
+ ]);
183
+ });
184
+ });
185
+
186
+ describe('hook', () => {
187
+ /**
188
+ * @target hook should hook a new callback on insert with the new id
189
+ * @dependencies
190
+ * @scenario
191
+ * - mock extractor
192
+ * - mock a callback for insert
193
+ * - run test (call `hook`)
194
+ * @expected
195
+ * - hook the callback with the specified id
196
+ * - return true
197
+ */
198
+ it('should hook a new callback on insert with the new id', async () => {
199
+ const extractor = new MockedErgoExtractor();
200
+ const insertCallback = vitest.fn();
201
+ const id = await extractor.hook(CallbackType.Insert, insertCallback);
202
+ expect(extractor['callbacks'][CallbackType.Insert]).toEqual(
203
+ new Map().set(id, insertCallback)
204
+ );
205
+ });
206
+ });
207
+
208
+ describe('unhook', () => {
209
+ /**
210
+ * @target unhook should unhook the callback on insert with the specified id
211
+ * @dependencies
212
+ * @scenario
213
+ * - mock extractor
214
+ * - mock a callback for insert
215
+ * - hook the callback
216
+ * - run test (call `unhook`)
217
+ * @expected
218
+ * - unhook the callback with the specified id
219
+ * - return true
220
+ */
221
+ it('should unhook the callback on insert with the specified id', async () => {
222
+ const extractor = new MockedErgoExtractor();
223
+ const insertCallback = vitest.fn();
224
+ const id = await extractor.hook(CallbackType.Insert, insertCallback);
225
+ const result = await extractor.unhook(CallbackType.Insert, id);
226
+ expect(result).toBeTruthy();
227
+ expect(extractor['callbacks'][CallbackType.Insert].get(id)).toEqual(
228
+ undefined
229
+ );
230
+ });
231
+
232
+ /**
233
+ * @target unhook should not unhook callbacks with the same id on other types
234
+ * @dependencies
235
+ * @scenario
236
+ * - mock extractor
237
+ * - mock two callbacks for insert
238
+ * - hook the first callback
239
+ * - run test (call `unhook` with the same id for second callback)
240
+ * @expected
241
+ * - not to change hooked callbacks when the callback with the id
242
+ * doesn't exists on the specified type
243
+ * - return false
244
+ */
245
+ it('should not unhook callbacks with the same id on other types', async () => {
246
+ const extractor = new MockedErgoExtractor();
247
+ const insertCallback = vitest.fn();
248
+ const id = await extractor.hook(CallbackType.Insert, insertCallback);
249
+ const result = await extractor.unhook(CallbackType.Update, id);
250
+ expect(result).toBeFalsy();
251
+ expect(extractor['callbacks'][CallbackType.Insert].get(id)).toEqual(
252
+ insertCallback
253
+ );
254
+ expect(extractor['callbacks'][CallbackType.Update].get(id)).toEqual(
255
+ undefined
256
+ );
257
+ });
258
+ });
259
+
260
+ describe('triggerCallbacks', () => {
261
+ /**
262
+ * @target triggerCallbacks should trigger all callbacks hooked on a type
263
+ * @dependencies
264
+ * @scenario
265
+ * - mock extractor
266
+ * - mock a callback for insert
267
+ * - hook the callback
268
+ * - run test (call `triggerCallbacks` for insert type)
269
+ * @expected
270
+ * - trigger all callbacks with the specified id
271
+ */
272
+ it('should trigger all callbacks hooked on a type', async () => {
273
+ const extractor = new MockedErgoExtractor();
274
+ const insertCallback = vitest.fn();
275
+ await extractor.hook(CallbackType.Insert, insertCallback);
276
+ const insertedData = [{ boxId: 'boxId', serialized: 'serialized' }];
277
+ await extractor['triggerCallbacks'](CallbackType.Insert, insertedData);
278
+ expect(insertCallback).toBeCalledWith(insertedData);
279
+ });
280
+ });
281
+ });
@@ -0,0 +1,45 @@
1
+ import { DataSource } from 'typeorm';
2
+ import { pick } from 'lodash-es';
3
+
4
+ import {
5
+ AbstractErgoExtractorAction,
6
+ AbstractErgoExtractorEntity,
7
+ BlockInfo,
8
+ AbstractBoxData,
9
+ } from '../lib';
10
+ import { TestEntity } from './testUtils';
11
+
12
+ export class TestErgoExtractorAction extends AbstractErgoExtractorAction<
13
+ AbstractBoxData,
14
+ AbstractErgoExtractorEntity
15
+ > {
16
+ constructor(dataSource: DataSource) {
17
+ super(dataSource, TestEntity);
18
+ }
19
+
20
+ /**
21
+ * create the test database entity from data and block information
22
+ */
23
+ createEntity = (
24
+ boxes: AbstractBoxData[],
25
+ block: BlockInfo,
26
+ extractor: string
27
+ ): Omit<AbstractErgoExtractorEntity, 'id'>[] => {
28
+ return boxes.map((box) => ({
29
+ boxId: box.boxId,
30
+ block: block.hash,
31
+ height: block.height,
32
+ serialized: box.serialized,
33
+ extractor: extractor,
34
+ }));
35
+ };
36
+
37
+ /**
38
+ * convert the database entity back to raw data
39
+ */
40
+ convertEntityToData = (
41
+ entities: AbstractErgoExtractorEntity[]
42
+ ): AbstractBoxData[] => {
43
+ return entities.map((data) => pick(data, ['boxId', 'serialized']));
44
+ };
45
+ }
@@ -0,0 +1,269 @@
1
+ import { DataSource, Repository } from 'typeorm';
2
+ import { describe, it, expect, beforeEach } from 'vitest';
3
+ import { pick } from 'lodash-es';
4
+
5
+ import { TestErgoExtractorAction } from './AbstractErgoExtractorAction.mock';
6
+ import { createDatabase, TestEntity } from './testUtils';
7
+ import { block, block2, sampleEntities } from './testData';
8
+ import { SpendInfo } from '../lib';
9
+
10
+ describe('AbstractErgoExtractorAction', () => {
11
+ let dataSource: DataSource;
12
+ let action: TestErgoExtractorAction;
13
+ let repository: Repository<TestEntity>;
14
+ beforeEach(async () => {
15
+ dataSource = await createDatabase();
16
+ action = new TestErgoExtractorAction(dataSource);
17
+ repository = dataSource.getRepository(TestEntity);
18
+ });
19
+
20
+ describe('storeBoxes', () => {
21
+ /**
22
+ * @target storeBoxes should save the passed box entities to database
23
+ * @dependencies
24
+ * @scenario
25
+ * - run test (call `storeBoxes` with 2 new boxes)
26
+ * @expected
27
+ * - to save 2 new entities
28
+ * - to return 2 inserted entity data
29
+ */
30
+ it(`should save the passed box entities to database`, async () => {
31
+ const result = await action.storeBoxes(
32
+ sampleEntities.slice(0, 2),
33
+ block,
34
+ 'extractor1'
35
+ );
36
+
37
+ const [rows, rowsCount] = await repository.findAndCount();
38
+
39
+ expect(rowsCount).toEqual(2);
40
+ expect(rows[0]).toMatchObject({
41
+ ...sampleEntities[0],
42
+ extractor: 'extractor1',
43
+ block: block.hash,
44
+ height: block.height,
45
+ spendBlock: null,
46
+ spendHeight: null,
47
+ });
48
+ expect(rows[1]).toMatchObject({
49
+ ...sampleEntities[1],
50
+ extractor: 'extractor1',
51
+ block: block.hash,
52
+ height: block.height,
53
+ spendBlock: null,
54
+ spendHeight: null,
55
+ });
56
+ expect(result).toEqual(true);
57
+ });
58
+
59
+ /**
60
+ * @target storeBoxes should correctly save boxes with different extractors
61
+ * @dependencies
62
+ * @scenario
63
+ * - insert 2 boxes belonging to first-extractor
64
+ * - run test (call `storeBoxes` with same boxes for the second-extractor)
65
+ * @expected
66
+ * - to save 2 new entities belonging to second-extractor
67
+ * - to return 2 new inserted entity data
68
+ */
69
+ it(`should correctly save boxes with different extractors`, async () => {
70
+ await repository.insert([
71
+ {
72
+ ...sampleEntities[0],
73
+ extractor: 'first-extractor',
74
+ block: '1',
75
+ height: 1,
76
+ },
77
+ {
78
+ ...sampleEntities[1],
79
+ extractor: 'first-extractor',
80
+ block: '1',
81
+ height: 1,
82
+ },
83
+ ]);
84
+
85
+ const result = await action.storeBoxes(
86
+ [sampleEntities[0], sampleEntities[1]],
87
+ block,
88
+ 'second-extractor'
89
+ );
90
+
91
+ const [insertedRows] = await repository.findAndCount();
92
+ expect(insertedRows[2]).toMatchObject({
93
+ ...sampleEntities[0],
94
+ extractor: 'second-extractor',
95
+ block: 'hash',
96
+ height: block.height,
97
+ spendBlock: null,
98
+ spendHeight: null,
99
+ });
100
+
101
+ expect(insertedRows[3]).toMatchObject({
102
+ ...sampleEntities[1],
103
+ extractor: 'second-extractor',
104
+ block: 'hash',
105
+ height: block.height,
106
+ spendBlock: null,
107
+ spendHeight: null,
108
+ });
109
+ expect(result).toEqual(true);
110
+ });
111
+
112
+ /**
113
+ * @target storeBoxes should update boxes correctly
114
+ * @dependencies
115
+ * @scenario
116
+ * - insert 2 boxes
117
+ * - run test (call `storeBoxes` with the same boxes and updated info)
118
+ * @expected
119
+ * - to update the existing box in database
120
+ * - to return updated box id
121
+ */
122
+ it(`storeBoxes should update boxes correctly`, async () => {
123
+ await repository.insert([
124
+ {
125
+ ...sampleEntities[0],
126
+ extractor: 'extractor',
127
+ block: '1',
128
+ height: 1,
129
+ },
130
+ {
131
+ ...sampleEntities[1],
132
+ extractor: 'extractor',
133
+ block: '1',
134
+ height: 1,
135
+ },
136
+ ]);
137
+
138
+ const result = await action.storeBoxes(
139
+ [
140
+ {
141
+ ...sampleEntities[0],
142
+ serialized: 'updatedBoxSerialized',
143
+ },
144
+ ],
145
+ block,
146
+ 'extractor'
147
+ );
148
+ const [secondInsertRows, secondInsertRowsCount] =
149
+ await repository.findAndCount();
150
+ expect(secondInsertRowsCount).toEqual(2);
151
+ expect(secondInsertRows[0]).toMatchObject({
152
+ ...sampleEntities[0],
153
+ extractor: 'extractor',
154
+ serialized: 'updatedBoxSerialized',
155
+ block: block.hash,
156
+ height: block.height,
157
+ spendBlock: null,
158
+ spendHeight: null,
159
+ });
160
+ expect(result).toEqual(true);
161
+ });
162
+ });
163
+
164
+ describe('spendBoxes', () => {
165
+ /**
166
+ * @target spendBoxes should set spendBlock and spendHeight for a set of boxes
167
+ * @dependencies
168
+ * @scenario
169
+ * - insert two boxes
170
+ * - mock spending information for the first box
171
+ * - run test (call `spendBoxes`)
172
+ * @expected
173
+ * - spend the first box
174
+ * - return boxId and serialized of spent box
175
+ */
176
+ it(`should set spendBlock and spendHeight for a set of boxes`, async () => {
177
+ await action.storeBoxes(sampleEntities.slice(0, 2), block, 'extractor1');
178
+
179
+ const spendBlock = { ...block, hash: 'spendHash', height: 10006016 };
180
+ const spendInfos: Array<SpendInfo> = [
181
+ { txId: 'txId', boxId: sampleEntities[0].boxId, index: 0 },
182
+ ];
183
+
184
+ const spentBoxIds = await action.spendBoxes(
185
+ spendInfos,
186
+ spendBlock,
187
+ 'extractor1'
188
+ );
189
+
190
+ const spentBoxes = await repository.findOneBy({
191
+ boxId: sampleEntities[0].boxId,
192
+ extractor: 'extractor1',
193
+ });
194
+
195
+ expect(spentBoxes).toMatchObject({
196
+ ...sampleEntities[0],
197
+ block: block.hash,
198
+ height: block.height,
199
+ extractor: 'extractor1',
200
+ spendBlock: spendBlock.hash,
201
+ spendHeight: spendBlock.height,
202
+ });
203
+ expect(spentBoxIds).toEqual([pick(sampleEntities[0], ['boxId'])]);
204
+ });
205
+ });
206
+
207
+ describe('deleteBlockBoxes', () => {
208
+ /**
209
+ * @target deleteBlockBoxes should delete the boxes created in the specified block
210
+ * @dependencies
211
+ * @scenario
212
+ * - insert four boxes created in two different blocks
213
+ * - run test(call `deleteBlockBoxes` to delete block2)
214
+ * @expected
215
+ * - to delete the two boxes created in block2
216
+ * - to return the deleted entity data
217
+ */
218
+ it(`should delete the boxes created in the specified block`, async () => {
219
+ await action.storeBoxes(sampleEntities.slice(0, 2), block, 'extractor1');
220
+ await action.storeBoxes(sampleEntities.slice(2), block2, 'extractor1');
221
+
222
+ const result = await action.deleteBlockBoxes(block2.hash, 'extractor1');
223
+
224
+ const [rows, rowsCount] = await repository.findAndCount();
225
+
226
+ expect(rowsCount).toEqual(2);
227
+ expect(rows.map((row) => row.boxId)).not.toContain(
228
+ sampleEntities.slice(2).map((box) => box.boxId)
229
+ );
230
+ expect(result).toEqual({
231
+ deletedData: action.convertEntityToData(
232
+ sampleEntities.slice(2) as TestEntity[]
233
+ ),
234
+ updatedData: [],
235
+ });
236
+ });
237
+
238
+ /**
239
+ * @target deleteBlockBoxes should update the boxes spent in the specified block
240
+ * @dependencies
241
+ * @scenario
242
+ * - insert four boxes created in a block
243
+ * - spend one of the in the block2
244
+ * - run test(call `deleteBlockBoxes` to delete block2)
245
+ * @expected
246
+ * - to update the box spent in block2
247
+ * - to return the updated entity boxId and serialized
248
+ */
249
+ it(`should update the boxes spent in the specified block`, async () => {
250
+ await action.storeBoxes(sampleEntities, block, 'extractor1');
251
+ const spendInfos: Array<SpendInfo> = [
252
+ { txId: 'txId', boxId: sampleEntities[0].boxId, index: 0 },
253
+ ];
254
+ await action.spendBoxes(spendInfos, block2, 'extractor1');
255
+ const result = await action.deleteBlockBoxes(block2.hash, 'extractor1');
256
+
257
+ const [rows, rowsCount] = await repository.findAndCount();
258
+
259
+ expect(rowsCount).toEqual(4);
260
+ expect(rows.map((row) => row.boxId)).not.toContain(
261
+ sampleEntities.slice(2).map((box) => box.boxId)
262
+ );
263
+ expect(result).toEqual({
264
+ deletedData: [],
265
+ updatedData: [pick(sampleEntities[0], ['boxId'])],
266
+ });
267
+ });
268
+ });
269
+ });
@@ -3,11 +3,22 @@ import {
3
3
  AbstractInitializableErgoExtractor,
4
4
  AbstractInitializableErgoExtractorAction,
5
5
  } from '../../lib/ergo/initializable';
6
- import { OutputBox, ErgoExtractedData, BlockInfo } from '../../lib';
6
+ import {
7
+ OutputBox,
8
+ AbstractBoxData,
9
+ BlockInfo,
10
+ AbstractErgoExtractorEntity,
11
+ } from '../../lib';
7
12
  import { ergoBoxes } from './testData';
8
13
 
9
- export class MockedInitializableErgoExtractor extends AbstractInitializableErgoExtractor<ErgoExtractedData> {
10
- actions: AbstractInitializableErgoExtractorAction<ErgoExtractedData>;
14
+ export class MockedInitializableErgoExtractor extends AbstractInitializableErgoExtractor<
15
+ AbstractBoxData,
16
+ AbstractErgoExtractorEntity
17
+ > {
18
+ actions: AbstractInitializableErgoExtractorAction<
19
+ AbstractBoxData,
20
+ AbstractErgoExtractorEntity
21
+ >;
11
22
 
12
23
  getId = () => 'Test';
13
24
 
@@ -21,11 +32,7 @@ export class MockedInitializableErgoExtractor extends AbstractInitializableErgoE
21
32
  return Promise.resolve({ boxes: ergoBoxes, hasNextBatch: true });
22
33
  };
23
34
 
24
- extractBoxData = (
25
- box: V1.OutputInfo | OutputBox,
26
- blockId: string,
27
- height: number
28
- ) => {
35
+ extractBoxData = (box: V1.OutputInfo | OutputBox) => {
29
36
  return undefined;
30
37
  };
31
38
  }