@fintekkers/ledger-models 0.4.8 → 0.4.10
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.
- package/node/wrappers/models/portfolio/portfolio.d.ts +8 -0
- package/node/wrappers/models/portfolio/portfolio.js +54 -1
- package/node/wrappers/models/portfolio/portfolio.js.map +1 -1
- package/node/wrappers/models/portfolio/portfolio.ts +34 -1
- package/node/wrappers/models/portfolio-price-transaction.lazy-hydrate.test.d.ts +1 -0
- package/node/wrappers/models/portfolio-price-transaction.lazy-hydrate.test.js +158 -0
- package/node/wrappers/models/portfolio-price-transaction.lazy-hydrate.test.js.map +1 -0
- package/node/wrappers/models/portfolio-price-transaction.lazy-hydrate.test.ts +153 -0
- package/node/wrappers/models/price/Price.d.ts +5 -0
- package/node/wrappers/models/price/Price.js +48 -0
- package/node/wrappers/models/price/Price.js.map +1 -1
- package/node/wrappers/models/price/Price.ts +26 -0
- package/node/wrappers/models/security/security.d.ts +9 -3
- package/node/wrappers/models/security/security.js +57 -15
- package/node/wrappers/models/security/security.js.map +1 -1
- package/node/wrappers/models/security/security.lazy-hydrate.test.d.ts +1 -0
- package/node/wrappers/models/security/security.lazy-hydrate.test.js +127 -0
- package/node/wrappers/models/security/security.lazy-hydrate.test.js.map +1 -0
- package/node/wrappers/models/security/security.lazy-hydrate.test.ts +123 -0
- package/node/wrappers/models/security/security.ts +35 -17
- package/node/wrappers/models/transaction/transaction.d.ts +7 -0
- package/node/wrappers/models/transaction/transaction.js +61 -0
- package/node/wrappers/models/transaction/transaction.js.map +1 -1
- package/node/wrappers/models/transaction/transaction.ts +40 -0
- package/node/wrappers/services/portfolio-service/PortfolioService.js +35 -0
- package/node/wrappers/services/portfolio-service/PortfolioService.js.map +1 -1
- package/node/wrappers/services/portfolio-service/PortfolioService.ts +14 -2
- package/node/wrappers/services/price-service/PriceService.js +10 -0
- package/node/wrappers/services/price-service/PriceService.js.map +1 -1
- package/node/wrappers/services/price-service/PriceService.ts +12 -2
- package/node/wrappers/services/security-service/SecurityService.js +15 -0
- package/node/wrappers/services/security-service/SecurityService.js.map +1 -1
- package/node/wrappers/services/security-service/SecurityService.ts +17 -2
- package/node/wrappers/services/service-client-writethrough.test.d.ts +1 -0
- package/node/wrappers/services/service-client-writethrough.test.js +147 -0
- package/node/wrappers/services/service-client-writethrough.test.js.map +1 -0
- package/node/wrappers/services/service-client-writethrough.test.ts +141 -0
- package/node/wrappers/services/transaction-service/TransactionService.js +36 -0
- package/node/wrappers/services/transaction-service/TransactionService.js.map +1 -1
- package/node/wrappers/services/transaction-service/TransactionService.ts +13 -0
- package/node/wrappers/util/link-cache.d.ts +56 -0
- package/node/wrappers/util/link-cache.js +92 -0
- package/node/wrappers/util/link-cache.js.map +1 -0
- package/node/wrappers/util/link-cache.test.d.ts +1 -0
- package/node/wrappers/util/link-cache.test.js +107 -0
- package/node/wrappers/util/link-cache.test.js.map +1 -0
- package/node/wrappers/util/link-cache.test.ts +112 -0
- package/node/wrappers/util/link-cache.ts +110 -0
- package/node/wrappers/util/link-resolver.js +52 -0
- package/node/wrappers/util/link-resolver.js.map +1 -1
- package/node/wrappers/util/link-resolver.test.js +75 -0
- package/node/wrappers/util/link-resolver.test.js.map +1 -1
- package/node/wrappers/util/link-resolver.test.ts +62 -0
- package/node/wrappers/util/link-resolver.ts +29 -0
- package/package.json +1 -1
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
26
|
const field_pb_1 = require("../../../fintekkers/models/position/field_pb");
|
|
4
27
|
const security_pb_1 = require("../../../fintekkers/models/security/security_pb");
|
|
@@ -8,6 +31,7 @@ const date_1 = require("../utils/date");
|
|
|
8
31
|
const product_type_pb_1 = require("../../../fintekkers/models/security/product_type_pb");
|
|
9
32
|
const identifier_1 = require("./identifier");
|
|
10
33
|
const product_hierarchy_1 = require("./product_hierarchy");
|
|
34
|
+
const LinkCacheModule = __importStar(require("../../util/link-cache"));
|
|
11
35
|
class Security {
|
|
12
36
|
constructor(proto) {
|
|
13
37
|
this.proto = proto;
|
|
@@ -54,15 +78,33 @@ class Security {
|
|
|
54
78
|
return asOf.toProto();
|
|
55
79
|
}
|
|
56
80
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
81
|
+
* Lazy hydration. If this Security is in link mode, swap in the resolved
|
|
82
|
+
* proto from LinkCache. On cache miss, throws — caller must pre-warm via
|
|
83
|
+
* LinkResolver. See docs/adr/lazy-link-hydration.md.
|
|
84
|
+
*
|
|
85
|
+
* TS variant is cache-only (no fetcher hook) because the gRPC stubs are
|
|
86
|
+
* async and chaining the resolver into every getter would force every
|
|
87
|
+
* accessor to become async. Pre-warming through LinkResolver keeps the
|
|
88
|
+
* sync getter API.
|
|
59
89
|
*/
|
|
60
|
-
|
|
61
|
-
if (this.proto.getIsLink())
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
90
|
+
ensureHydrated() {
|
|
91
|
+
if (!this.proto.getIsLink())
|
|
92
|
+
return;
|
|
93
|
+
const uuidProto = this.proto.getUuid();
|
|
94
|
+
if (!uuidProto) {
|
|
95
|
+
throw new Error("Cannot read fields on link-mode Security with no UUID set.");
|
|
96
|
+
}
|
|
97
|
+
const uuidKey = uuid_1.UUID.fromU8Array(uuidProto.getRawUuid_asU8()).toString();
|
|
98
|
+
const asOfProto = this.proto.getAsOf();
|
|
99
|
+
const asOf = asOfProto ? new datetime_1.ZonedDateTime(asOfProto) : null;
|
|
100
|
+
const cached = LinkCacheModule.SECURITY.get(uuidKey, asOf);
|
|
101
|
+
if (cached) {
|
|
102
|
+
this.proto = cached;
|
|
103
|
+
return;
|
|
65
104
|
}
|
|
105
|
+
throw new Error(`Cannot read fields on link-mode Security uuid=${uuidKey} `
|
|
106
|
+
+ `— LinkCache miss. Pre-warm via LinkResolver. `
|
|
107
|
+
+ `See docs/adr/lazy-link-hydration.md.`);
|
|
66
108
|
}
|
|
67
109
|
/**
|
|
68
110
|
* Factory method to create the appropriate Security subclass based on
|
|
@@ -236,15 +278,15 @@ class Security {
|
|
|
236
278
|
return new datetime_1.ZonedDateTime(asOf);
|
|
237
279
|
}
|
|
238
280
|
getAssetClass() {
|
|
239
|
-
this.
|
|
281
|
+
this.ensureHydrated();
|
|
240
282
|
return this.proto.getAssetClass();
|
|
241
283
|
}
|
|
242
284
|
getProductClass() {
|
|
243
|
-
this.
|
|
285
|
+
this.ensureHydrated();
|
|
244
286
|
throw new Error('Not implemented yet. See Java implementation for reference');
|
|
245
287
|
}
|
|
246
288
|
getProductType() {
|
|
247
|
-
this.
|
|
289
|
+
this.ensureHydrated();
|
|
248
290
|
const securityType = this.proto.getProductType();
|
|
249
291
|
const securityTypeString = Object.keys(product_type_pb_1.ProductTypeProto).find(key => product_type_pb_1.ProductTypeProto[key] === securityType);
|
|
250
292
|
return securityTypeString || 'UNKNOWN_SECURITY_TYPE';
|
|
@@ -254,7 +296,7 @@ class Security {
|
|
|
254
296
|
* Empty list if none are set. Throws on a link-mode Security.
|
|
255
297
|
*/
|
|
256
298
|
getIdentifiers() {
|
|
257
|
-
this.
|
|
299
|
+
this.ensureHydrated();
|
|
258
300
|
const list = this.proto.getIdentifiersList();
|
|
259
301
|
if (!list)
|
|
260
302
|
return [];
|
|
@@ -265,7 +307,7 @@ class Security {
|
|
|
265
307
|
* or undefined if none is present. Throws on a link-mode Security.
|
|
266
308
|
*/
|
|
267
309
|
getIdentifierByType(type) {
|
|
268
|
-
this.
|
|
310
|
+
this.ensureHydrated();
|
|
269
311
|
const list = this.proto.getIdentifiersList();
|
|
270
312
|
if (!list)
|
|
271
313
|
return undefined;
|
|
@@ -286,7 +328,7 @@ class Security {
|
|
|
286
328
|
* properly-formed bond).
|
|
287
329
|
*/
|
|
288
330
|
getIssueDate() {
|
|
289
|
-
this.
|
|
331
|
+
this.ensureHydrated();
|
|
290
332
|
const bond = this.getBondLikeDetails();
|
|
291
333
|
const date = bond ? bond.getIssueDate() : undefined;
|
|
292
334
|
return (0, date_1.localDateProtoToDate)(date);
|
|
@@ -298,7 +340,7 @@ class Security {
|
|
|
298
340
|
* code paths.
|
|
299
341
|
*/
|
|
300
342
|
getMaturityDate() {
|
|
301
|
-
this.
|
|
343
|
+
this.ensureHydrated();
|
|
302
344
|
const bond = this.getBondLikeDetails();
|
|
303
345
|
const date = bond ? bond.getMaturityDate() : undefined;
|
|
304
346
|
return (0, date_1.localDateProtoToDate)(date);
|
|
@@ -315,7 +357,7 @@ class Security {
|
|
|
315
357
|
return (_a = this.proto.getBondDetails()) !== null && _a !== void 0 ? _a : undefined;
|
|
316
358
|
}
|
|
317
359
|
getIssuerName() {
|
|
318
|
-
this.
|
|
360
|
+
this.ensureHydrated();
|
|
319
361
|
return this.proto.getIssuerName();
|
|
320
362
|
}
|
|
321
363
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.js","sourceRoot":"","sources":["security.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["security.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const security_1 = __importDefault(require("./security"));
|
|
30
|
+
const uuid_1 = require("../utils/uuid");
|
|
31
|
+
const datetime_1 = require("../utils/datetime");
|
|
32
|
+
const LinkCache = __importStar(require("../../util/link-cache"));
|
|
33
|
+
const security_pb_1 = require("../../../fintekkers/models/security/security_pb");
|
|
34
|
+
const local_timestamp_pb_1 = require("../../../fintekkers/models/util/local_timestamp_pb");
|
|
35
|
+
const timestamp_pb_1 = require("google-protobuf/google/protobuf/timestamp_pb");
|
|
36
|
+
function makeAsOf(epochSecondsOffset = 0) {
|
|
37
|
+
const ts = new timestamp_pb_1.Timestamp();
|
|
38
|
+
ts.setSeconds(1700000000 + epochSecondsOffset);
|
|
39
|
+
ts.setNanos(0);
|
|
40
|
+
const proto = new local_timestamp_pb_1.LocalTimestampProto();
|
|
41
|
+
proto.setTimestamp(ts);
|
|
42
|
+
proto.setTimeZone('UTC');
|
|
43
|
+
return new datetime_1.ZonedDateTime(proto);
|
|
44
|
+
}
|
|
45
|
+
function makeFullProto(uuid, asOf, issuer = 'ACME') {
|
|
46
|
+
const p = new security_pb_1.SecurityProto();
|
|
47
|
+
p.setUuid(uuid.toUUIDProto());
|
|
48
|
+
p.setAsOf(asOf.toProto());
|
|
49
|
+
p.setIssuerName(issuer);
|
|
50
|
+
p.setAssetClass('Equity');
|
|
51
|
+
return p;
|
|
52
|
+
}
|
|
53
|
+
describe('Security lazy hydrate', () => {
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
LinkCache.SECURITY.clear();
|
|
56
|
+
});
|
|
57
|
+
// ---- A. Hydration on accessors ----
|
|
58
|
+
test('A — getAssetClass on link-mode wrapper hydrates from cache', () => {
|
|
59
|
+
const uuid = uuid_1.UUID.fromU8Array(new Uint8Array(16).fill(0x42));
|
|
60
|
+
const asOf = makeAsOf();
|
|
61
|
+
const resolved = makeFullProto(uuid, asOf, 'ACME-resolved');
|
|
62
|
+
LinkCache.SECURITY.put(uuid.toString(), resolved, asOf);
|
|
63
|
+
const wrapper = new security_1.default(security_1.default.linkOf(uuid, asOf));
|
|
64
|
+
expect(wrapper.isLink()).toBe(true);
|
|
65
|
+
expect(wrapper.getAssetClass()).toBe('Equity');
|
|
66
|
+
// After first accessor, wrapper has swapped in the resolved proto.
|
|
67
|
+
expect(wrapper.proto.getIsLink()).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
test('A — link-safe accessors do not require hydration', () => {
|
|
70
|
+
const uuid = uuid_1.UUID.fromU8Array(new Uint8Array(16).fill(0x07));
|
|
71
|
+
const asOf = makeAsOf();
|
|
72
|
+
// Cache is empty — link-safe accessors must still work.
|
|
73
|
+
const wrapper = new security_1.default(security_1.default.linkOf(uuid, asOf));
|
|
74
|
+
expect(wrapper.isLink()).toBe(true);
|
|
75
|
+
expect(wrapper.getID().toString()).toBe(uuid.toString());
|
|
76
|
+
expect(wrapper.getAsOf().getSeconds()).toBe(asOf.getSeconds());
|
|
77
|
+
});
|
|
78
|
+
// ---- B. Cache behavior ----
|
|
79
|
+
test('B.i — first accessor call hydrates from a pre-populated cache', () => {
|
|
80
|
+
const uuid = uuid_1.UUID.fromU8Array(new Uint8Array(16).fill(0x01));
|
|
81
|
+
const asOf = makeAsOf();
|
|
82
|
+
const resolved = makeFullProto(uuid, asOf, 'hydrated');
|
|
83
|
+
LinkCache.SECURITY.put(uuid.toString(), resolved, asOf);
|
|
84
|
+
const wrapper = new security_1.default(security_1.default.linkOf(uuid, asOf));
|
|
85
|
+
expect(wrapper.getIssuerName()).toBe('hydrated');
|
|
86
|
+
});
|
|
87
|
+
test('B.ii — second accessor call hits the swapped proto, not the cache', () => {
|
|
88
|
+
const uuid = uuid_1.UUID.fromU8Array(new Uint8Array(16).fill(0x02));
|
|
89
|
+
const asOf = makeAsOf();
|
|
90
|
+
const resolved = makeFullProto(uuid, asOf, 'firstRead');
|
|
91
|
+
LinkCache.SECURITY.put(uuid.toString(), resolved, asOf);
|
|
92
|
+
const wrapper = new security_1.default(security_1.default.linkOf(uuid, asOf));
|
|
93
|
+
expect(wrapper.getAssetClass()).toBe('Equity');
|
|
94
|
+
// Evict the cache; wrapper has already swapped in the proto so the
|
|
95
|
+
// second read must succeed without touching the cache.
|
|
96
|
+
LinkCache.SECURITY.evict(uuid.toString());
|
|
97
|
+
expect(wrapper.getIssuerName()).toBe('firstRead');
|
|
98
|
+
});
|
|
99
|
+
test('B.iii — fresh wrapper for same (uuid, asOf) reads cache populated by prior wrapper', () => {
|
|
100
|
+
const uuid = uuid_1.UUID.fromU8Array(new Uint8Array(16).fill(0x03));
|
|
101
|
+
const asOf = makeAsOf();
|
|
102
|
+
const resolved = makeFullProto(uuid, asOf, 'shared');
|
|
103
|
+
LinkCache.SECURITY.put(uuid.toString(), resolved, asOf);
|
|
104
|
+
// Two independent wrappers share the cache entry.
|
|
105
|
+
const wrapperA = new security_1.default(security_1.default.linkOf(uuid, asOf));
|
|
106
|
+
const wrapperB = new security_1.default(security_1.default.linkOf(uuid, asOf));
|
|
107
|
+
expect(wrapperA.getIssuerName()).toBe('shared');
|
|
108
|
+
expect(wrapperB.getIssuerName()).toBe('shared');
|
|
109
|
+
});
|
|
110
|
+
// ---- C. asOf semantics ----
|
|
111
|
+
test('C — link asOf differing from cached asOf is a miss', () => {
|
|
112
|
+
const uuid = uuid_1.UUID.fromU8Array(new Uint8Array(16).fill(0x04));
|
|
113
|
+
const asOfT1 = makeAsOf(0);
|
|
114
|
+
const asOfT2 = makeAsOf(86400);
|
|
115
|
+
LinkCache.SECURITY.put(uuid.toString(), makeFullProto(uuid, asOfT2, 'T2'), asOfT2);
|
|
116
|
+
const wrapper = new security_1.default(security_1.default.linkOf(uuid, asOfT1));
|
|
117
|
+
expect(() => wrapper.getIssuerName()).toThrow(/LinkCache miss/);
|
|
118
|
+
});
|
|
119
|
+
// ---- D. Resolve failure ----
|
|
120
|
+
test('D — cache miss throws with uuid in message', () => {
|
|
121
|
+
const uuid = uuid_1.UUID.fromU8Array(new Uint8Array(16).fill(0x05));
|
|
122
|
+
const asOf = makeAsOf();
|
|
123
|
+
const wrapper = new security_1.default(security_1.default.linkOf(uuid, asOf));
|
|
124
|
+
expect(() => wrapper.getAssetClass()).toThrow(new RegExp(uuid.toString()));
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=security.lazy-hydrate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.lazy-hydrate.test.js","sourceRoot":"","sources":["security.lazy-hydrate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import Security from './security';
|
|
2
|
+
import { UUID } from '../utils/uuid';
|
|
3
|
+
import { ZonedDateTime } from '../utils/datetime';
|
|
4
|
+
|
|
5
|
+
import * as LinkCache from '../../util/link-cache';
|
|
6
|
+
|
|
7
|
+
import { SecurityProto } from '../../../fintekkers/models/security/security_pb';
|
|
8
|
+
import { LocalTimestampProto } from '../../../fintekkers/models/util/local_timestamp_pb';
|
|
9
|
+
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
|
10
|
+
|
|
11
|
+
function makeAsOf(epochSecondsOffset: number = 0): ZonedDateTime {
|
|
12
|
+
const ts = new Timestamp();
|
|
13
|
+
ts.setSeconds(1700000000 + epochSecondsOffset);
|
|
14
|
+
ts.setNanos(0);
|
|
15
|
+
const proto = new LocalTimestampProto();
|
|
16
|
+
proto.setTimestamp(ts);
|
|
17
|
+
proto.setTimeZone('UTC');
|
|
18
|
+
return new ZonedDateTime(proto);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function makeFullProto(uuid: UUID, asOf: ZonedDateTime, issuer = 'ACME'): SecurityProto {
|
|
22
|
+
const p = new SecurityProto();
|
|
23
|
+
p.setUuid(uuid.toUUIDProto());
|
|
24
|
+
p.setAsOf(asOf.toProto());
|
|
25
|
+
p.setIssuerName(issuer);
|
|
26
|
+
p.setAssetClass('Equity');
|
|
27
|
+
return p;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('Security lazy hydrate', () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
LinkCache.SECURITY.clear();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// ---- A. Hydration on accessors ----
|
|
36
|
+
|
|
37
|
+
test('A — getAssetClass on link-mode wrapper hydrates from cache', () => {
|
|
38
|
+
const uuid = UUID.fromU8Array(new Uint8Array(16).fill(0x42));
|
|
39
|
+
const asOf = makeAsOf();
|
|
40
|
+
const resolved = makeFullProto(uuid, asOf, 'ACME-resolved');
|
|
41
|
+
LinkCache.SECURITY.put(uuid.toString(), resolved, asOf);
|
|
42
|
+
|
|
43
|
+
const wrapper = new Security(Security.linkOf(uuid, asOf));
|
|
44
|
+
expect(wrapper.isLink()).toBe(true);
|
|
45
|
+
|
|
46
|
+
expect(wrapper.getAssetClass()).toBe('Equity');
|
|
47
|
+
// After first accessor, wrapper has swapped in the resolved proto.
|
|
48
|
+
expect(wrapper.proto.getIsLink()).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('A — link-safe accessors do not require hydration', () => {
|
|
52
|
+
const uuid = UUID.fromU8Array(new Uint8Array(16).fill(0x07));
|
|
53
|
+
const asOf = makeAsOf();
|
|
54
|
+
// Cache is empty — link-safe accessors must still work.
|
|
55
|
+
const wrapper = new Security(Security.linkOf(uuid, asOf));
|
|
56
|
+
|
|
57
|
+
expect(wrapper.isLink()).toBe(true);
|
|
58
|
+
expect(wrapper.getID().toString()).toBe(uuid.toString());
|
|
59
|
+
expect(wrapper.getAsOf().getSeconds()).toBe(asOf.getSeconds());
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// ---- B. Cache behavior ----
|
|
63
|
+
|
|
64
|
+
test('B.i — first accessor call hydrates from a pre-populated cache', () => {
|
|
65
|
+
const uuid = UUID.fromU8Array(new Uint8Array(16).fill(0x01));
|
|
66
|
+
const asOf = makeAsOf();
|
|
67
|
+
const resolved = makeFullProto(uuid, asOf, 'hydrated');
|
|
68
|
+
LinkCache.SECURITY.put(uuid.toString(), resolved, asOf);
|
|
69
|
+
|
|
70
|
+
const wrapper = new Security(Security.linkOf(uuid, asOf));
|
|
71
|
+
expect(wrapper.getIssuerName()).toBe('hydrated');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('B.ii — second accessor call hits the swapped proto, not the cache', () => {
|
|
75
|
+
const uuid = UUID.fromU8Array(new Uint8Array(16).fill(0x02));
|
|
76
|
+
const asOf = makeAsOf();
|
|
77
|
+
const resolved = makeFullProto(uuid, asOf, 'firstRead');
|
|
78
|
+
LinkCache.SECURITY.put(uuid.toString(), resolved, asOf);
|
|
79
|
+
|
|
80
|
+
const wrapper = new Security(Security.linkOf(uuid, asOf));
|
|
81
|
+
expect(wrapper.getAssetClass()).toBe('Equity');
|
|
82
|
+
|
|
83
|
+
// Evict the cache; wrapper has already swapped in the proto so the
|
|
84
|
+
// second read must succeed without touching the cache.
|
|
85
|
+
LinkCache.SECURITY.evict(uuid.toString());
|
|
86
|
+
expect(wrapper.getIssuerName()).toBe('firstRead');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('B.iii — fresh wrapper for same (uuid, asOf) reads cache populated by prior wrapper', () => {
|
|
90
|
+
const uuid = UUID.fromU8Array(new Uint8Array(16).fill(0x03));
|
|
91
|
+
const asOf = makeAsOf();
|
|
92
|
+
const resolved = makeFullProto(uuid, asOf, 'shared');
|
|
93
|
+
LinkCache.SECURITY.put(uuid.toString(), resolved, asOf);
|
|
94
|
+
|
|
95
|
+
// Two independent wrappers share the cache entry.
|
|
96
|
+
const wrapperA = new Security(Security.linkOf(uuid, asOf));
|
|
97
|
+
const wrapperB = new Security(Security.linkOf(uuid, asOf));
|
|
98
|
+
expect(wrapperA.getIssuerName()).toBe('shared');
|
|
99
|
+
expect(wrapperB.getIssuerName()).toBe('shared');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// ---- C. asOf semantics ----
|
|
103
|
+
|
|
104
|
+
test('C — link asOf differing from cached asOf is a miss', () => {
|
|
105
|
+
const uuid = UUID.fromU8Array(new Uint8Array(16).fill(0x04));
|
|
106
|
+
const asOfT1 = makeAsOf(0);
|
|
107
|
+
const asOfT2 = makeAsOf(86400);
|
|
108
|
+
LinkCache.SECURITY.put(uuid.toString(), makeFullProto(uuid, asOfT2, 'T2'), asOfT2);
|
|
109
|
+
|
|
110
|
+
const wrapper = new Security(Security.linkOf(uuid, asOfT1));
|
|
111
|
+
expect(() => wrapper.getIssuerName()).toThrow(/LinkCache miss/);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// ---- D. Resolve failure ----
|
|
115
|
+
|
|
116
|
+
test('D — cache miss throws with uuid in message', () => {
|
|
117
|
+
const uuid = UUID.fromU8Array(new Uint8Array(16).fill(0x05));
|
|
118
|
+
const asOf = makeAsOf();
|
|
119
|
+
const wrapper = new Security(Security.linkOf(uuid, asOf));
|
|
120
|
+
|
|
121
|
+
expect(() => wrapper.getAssetClass()).toThrow(new RegExp(uuid.toString()));
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -9,6 +9,7 @@ import { ProductTypeProto } from "../../../fintekkers/models/security/product_ty
|
|
|
9
9
|
import { IdentifierTypeProto } from "../../../fintekkers/models/security/identifier/identifier_type_pb";
|
|
10
10
|
import { Identifier } from "./identifier";
|
|
11
11
|
import { isDescendantOf } from "./product_hierarchy";
|
|
12
|
+
import * as LinkCacheModule from "../../util/link-cache";
|
|
12
13
|
|
|
13
14
|
class Security {
|
|
14
15
|
proto: SecurityProto;
|
|
@@ -60,17 +61,34 @@ class Security {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
64
|
+
* Lazy hydration. If this Security is in link mode, swap in the resolved
|
|
65
|
+
* proto from LinkCache. On cache miss, throws — caller must pre-warm via
|
|
66
|
+
* LinkResolver. See docs/adr/lazy-link-hydration.md.
|
|
67
|
+
*
|
|
68
|
+
* TS variant is cache-only (no fetcher hook) because the gRPC stubs are
|
|
69
|
+
* async and chaining the resolver into every getter would force every
|
|
70
|
+
* accessor to become async. Pre-warming through LinkResolver keeps the
|
|
71
|
+
* sync getter API.
|
|
65
72
|
*/
|
|
66
|
-
private
|
|
67
|
-
if (this.proto.getIsLink())
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
private ensureHydrated(): void {
|
|
74
|
+
if (!this.proto.getIsLink()) return;
|
|
75
|
+
const uuidProto = this.proto.getUuid();
|
|
76
|
+
if (!uuidProto) {
|
|
77
|
+
throw new Error("Cannot read fields on link-mode Security with no UUID set.");
|
|
78
|
+
}
|
|
79
|
+
const uuidKey = UUID.fromU8Array(uuidProto.getRawUuid_asU8()).toString();
|
|
80
|
+
const asOfProto = this.proto.getAsOf();
|
|
81
|
+
const asOf = asOfProto ? new ZonedDateTime(asOfProto) : null;
|
|
82
|
+
const cached = LinkCacheModule.SECURITY.get(uuidKey, asOf);
|
|
83
|
+
if (cached) {
|
|
84
|
+
this.proto = cached;
|
|
85
|
+
return;
|
|
73
86
|
}
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Cannot read fields on link-mode Security uuid=${uuidKey} `
|
|
89
|
+
+ `— LinkCache miss. Pre-warm via LinkResolver. `
|
|
90
|
+
+ `See docs/adr/lazy-link-hydration.md.`
|
|
91
|
+
);
|
|
74
92
|
}
|
|
75
93
|
|
|
76
94
|
/**
|
|
@@ -258,17 +276,17 @@ class Security {
|
|
|
258
276
|
}
|
|
259
277
|
|
|
260
278
|
getAssetClass(): string {
|
|
261
|
-
this.
|
|
279
|
+
this.ensureHydrated();
|
|
262
280
|
return this.proto.getAssetClass();
|
|
263
281
|
}
|
|
264
282
|
|
|
265
283
|
getProductClass(): string {
|
|
266
|
-
this.
|
|
284
|
+
this.ensureHydrated();
|
|
267
285
|
throw new Error('Not implemented yet. See Java implementation for reference');
|
|
268
286
|
}
|
|
269
287
|
|
|
270
288
|
getProductType(): string {
|
|
271
|
-
this.
|
|
289
|
+
this.ensureHydrated();
|
|
272
290
|
const securityType = this.proto.getProductType();
|
|
273
291
|
const securityTypeString = (Object.keys(ProductTypeProto) as Array<keyof typeof ProductTypeProto>).find(
|
|
274
292
|
key => ProductTypeProto[key] === securityType
|
|
@@ -282,7 +300,7 @@ class Security {
|
|
|
282
300
|
* Empty list if none are set. Throws on a link-mode Security.
|
|
283
301
|
*/
|
|
284
302
|
getIdentifiers(): Identifier[] {
|
|
285
|
-
this.
|
|
303
|
+
this.ensureHydrated();
|
|
286
304
|
const list = this.proto.getIdentifiersList();
|
|
287
305
|
if (!list) return [];
|
|
288
306
|
return list.map(p => new Identifier(p));
|
|
@@ -293,7 +311,7 @@ class Security {
|
|
|
293
311
|
* or undefined if none is present. Throws on a link-mode Security.
|
|
294
312
|
*/
|
|
295
313
|
getIdentifierByType(type: IdentifierTypeProto): Identifier | undefined {
|
|
296
|
-
this.
|
|
314
|
+
this.ensureHydrated();
|
|
297
315
|
const list = this.proto.getIdentifiersList();
|
|
298
316
|
if (!list) return undefined;
|
|
299
317
|
const found = list.find(p => p.getIdentifierType() === type);
|
|
@@ -314,7 +332,7 @@ class Security {
|
|
|
314
332
|
* properly-formed bond).
|
|
315
333
|
*/
|
|
316
334
|
getIssueDate(): Date | null {
|
|
317
|
-
this.
|
|
335
|
+
this.ensureHydrated();
|
|
318
336
|
const bond = this.getBondLikeDetails();
|
|
319
337
|
const date = bond ? bond.getIssueDate() : undefined;
|
|
320
338
|
return localDateProtoToDate(date);
|
|
@@ -327,7 +345,7 @@ class Security {
|
|
|
327
345
|
* code paths.
|
|
328
346
|
*/
|
|
329
347
|
getMaturityDate(): Date | null {
|
|
330
|
-
this.
|
|
348
|
+
this.ensureHydrated();
|
|
331
349
|
const bond = this.getBondLikeDetails();
|
|
332
350
|
const date = bond ? bond.getMaturityDate() : undefined;
|
|
333
351
|
return localDateProtoToDate(date);
|
|
@@ -344,7 +362,7 @@ class Security {
|
|
|
344
362
|
}
|
|
345
363
|
|
|
346
364
|
getIssuerName(): string {
|
|
347
|
-
this.
|
|
365
|
+
this.ensureHydrated();
|
|
348
366
|
return this.proto.getIssuerName();
|
|
349
367
|
}
|
|
350
368
|
|
|
@@ -29,6 +29,13 @@ declare class Transaction {
|
|
|
29
29
|
toString(): string;
|
|
30
30
|
getFields(): FieldProto[];
|
|
31
31
|
getField(field: FieldProto): any;
|
|
32
|
+
isLink(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Lazy hydration. On a link-mode proto, swap in the resolved proto from
|
|
35
|
+
* LinkCache. On cache miss, throws — caller must pre-warm via LinkResolver.
|
|
36
|
+
* See docs/adr/lazy-link-hydration.md.
|
|
37
|
+
*/
|
|
38
|
+
private ensureHydrated;
|
|
32
39
|
getID(): UUID;
|
|
33
40
|
getAsOf(): ZonedDateTime;
|
|
34
41
|
getPortfolio(): Portfolio;
|