@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
|
@@ -6,6 +6,14 @@ declare class Portfolio {
|
|
|
6
6
|
proto: PortfolioProto;
|
|
7
7
|
constructor(proto: PortfolioProto);
|
|
8
8
|
toString(): string;
|
|
9
|
+
isLink(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Lazy hydration. On a link-mode proto, swap in the resolved proto from
|
|
12
|
+
* LinkCache. On cache miss, throws — caller must pre-warm via
|
|
13
|
+
* LinkResolver. Cache-only by design (same rationale as Security wrapper:
|
|
14
|
+
* keeps the sync getter API). See docs/adr/lazy-link-hydration.md.
|
|
15
|
+
*/
|
|
16
|
+
private ensureHydrated;
|
|
9
17
|
getID(): UUID;
|
|
10
18
|
getAsOf(): ZonedDateTime;
|
|
11
19
|
getPortfolioName(): string;
|
|
@@ -1,14 +1,66 @@
|
|
|
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 datetime_1 = require("../utils/datetime");
|
|
5
28
|
const uuid_1 = require("../utils/uuid");
|
|
29
|
+
const LinkCacheModule = __importStar(require("../../util/link-cache"));
|
|
6
30
|
class Portfolio {
|
|
7
31
|
constructor(proto) {
|
|
8
32
|
this.proto = proto;
|
|
9
33
|
}
|
|
10
34
|
toString() {
|
|
11
|
-
return this.getPortfolioName();
|
|
35
|
+
return this.isLink() ? `<link ${this.getID().toString()}>` : this.getPortfolioName();
|
|
36
|
+
}
|
|
37
|
+
isLink() {
|
|
38
|
+
return this.proto.getIsLink();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Lazy hydration. On a link-mode proto, swap in the resolved proto from
|
|
42
|
+
* LinkCache. On cache miss, throws — caller must pre-warm via
|
|
43
|
+
* LinkResolver. Cache-only by design (same rationale as Security wrapper:
|
|
44
|
+
* keeps the sync getter API). See docs/adr/lazy-link-hydration.md.
|
|
45
|
+
*/
|
|
46
|
+
ensureHydrated() {
|
|
47
|
+
if (!this.proto.getIsLink())
|
|
48
|
+
return;
|
|
49
|
+
const uuidProto = this.proto.getUuid();
|
|
50
|
+
if (!uuidProto) {
|
|
51
|
+
throw new Error("Cannot read fields on link-mode Portfolio with no UUID set.");
|
|
52
|
+
}
|
|
53
|
+
const uuidKey = uuid_1.UUID.fromU8Array(uuidProto.getRawUuid_asU8()).toString();
|
|
54
|
+
const asOfProto = this.proto.getAsOf();
|
|
55
|
+
const asOf = asOfProto ? new datetime_1.ZonedDateTime(asOfProto) : null;
|
|
56
|
+
const cached = LinkCacheModule.PORTFOLIO.get(uuidKey, asOf);
|
|
57
|
+
if (cached) {
|
|
58
|
+
this.proto = cached;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Cannot read fields on link-mode Portfolio uuid=${uuidKey} `
|
|
62
|
+
+ `— LinkCache miss. Pre-warm via LinkResolver. `
|
|
63
|
+
+ `See docs/adr/lazy-link-hydration.md.`);
|
|
12
64
|
}
|
|
13
65
|
getID() {
|
|
14
66
|
const uuid = this.proto.getUuid();
|
|
@@ -23,6 +75,7 @@ class Portfolio {
|
|
|
23
75
|
return new datetime_1.ZonedDateTime(asOf);
|
|
24
76
|
}
|
|
25
77
|
getPortfolioName() {
|
|
78
|
+
this.ensureHydrated();
|
|
26
79
|
return this.proto.getPortfolioName();
|
|
27
80
|
}
|
|
28
81
|
getFields() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portfolio.js","sourceRoot":"","sources":["portfolio.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"portfolio.js","sourceRoot":"","sources":["portfolio.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { PortfolioProto } from "../../../fintekkers/models/portfolio/portfolio_p
|
|
|
2
2
|
import { FieldProto } from "../../../fintekkers/models/position/field_pb";
|
|
3
3
|
import { ZonedDateTime } from "../utils/datetime";
|
|
4
4
|
import { UUID } from "../utils/uuid";
|
|
5
|
+
import * as LinkCacheModule from "../../util/link-cache";
|
|
5
6
|
|
|
6
7
|
class Portfolio {
|
|
7
8
|
proto: PortfolioProto;
|
|
@@ -11,7 +12,38 @@ class Portfolio {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
toString(): string {
|
|
14
|
-
return this.getPortfolioName();
|
|
15
|
+
return this.isLink() ? `<link ${this.getID().toString()}>` : this.getPortfolioName();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
isLink(): boolean {
|
|
19
|
+
return this.proto.getIsLink();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Lazy hydration. On a link-mode proto, swap in the resolved proto from
|
|
24
|
+
* LinkCache. On cache miss, throws — caller must pre-warm via
|
|
25
|
+
* LinkResolver. Cache-only by design (same rationale as Security wrapper:
|
|
26
|
+
* keeps the sync getter API). See docs/adr/lazy-link-hydration.md.
|
|
27
|
+
*/
|
|
28
|
+
private ensureHydrated(): void {
|
|
29
|
+
if (!this.proto.getIsLink()) return;
|
|
30
|
+
const uuidProto = this.proto.getUuid();
|
|
31
|
+
if (!uuidProto) {
|
|
32
|
+
throw new Error("Cannot read fields on link-mode Portfolio with no UUID set.");
|
|
33
|
+
}
|
|
34
|
+
const uuidKey = UUID.fromU8Array(uuidProto.getRawUuid_asU8()).toString();
|
|
35
|
+
const asOfProto = this.proto.getAsOf();
|
|
36
|
+
const asOf = asOfProto ? new ZonedDateTime(asOfProto) : null;
|
|
37
|
+
const cached = LinkCacheModule.PORTFOLIO.get(uuidKey, asOf);
|
|
38
|
+
if (cached) {
|
|
39
|
+
this.proto = cached;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Cannot read fields on link-mode Portfolio uuid=${uuidKey} `
|
|
44
|
+
+ `— LinkCache miss. Pre-warm via LinkResolver. `
|
|
45
|
+
+ `See docs/adr/lazy-link-hydration.md.`
|
|
46
|
+
);
|
|
15
47
|
}
|
|
16
48
|
|
|
17
49
|
getID(): UUID {
|
|
@@ -27,6 +59,7 @@ class Portfolio {
|
|
|
27
59
|
}
|
|
28
60
|
|
|
29
61
|
getPortfolioName(): string {
|
|
62
|
+
this.ensureHydrated();
|
|
30
63
|
return this.proto.getPortfolioName();
|
|
31
64
|
}
|
|
32
65
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Lazy-hydrate tests for Portfolio / Price / Transaction wrappers.
|
|
3
|
+
// Mirror of security.lazy-hydrate.test.ts — cache-only design, throws on miss.
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
21
|
+
if (mod && mod.__esModule) return mod;
|
|
22
|
+
var result = {};
|
|
23
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
24
|
+
__setModuleDefault(result, mod);
|
|
25
|
+
return result;
|
|
26
|
+
};
|
|
27
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
28
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
29
|
+
};
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
const portfolio_1 = __importDefault(require("./portfolio/portfolio"));
|
|
32
|
+
const Price_1 = __importDefault(require("./price/Price"));
|
|
33
|
+
const transaction_1 = __importDefault(require("./transaction/transaction"));
|
|
34
|
+
const uuid_1 = require("./utils/uuid");
|
|
35
|
+
const datetime_1 = require("./utils/datetime");
|
|
36
|
+
const portfolio_pb_1 = require("../../fintekkers/models/portfolio/portfolio_pb");
|
|
37
|
+
const price_pb_1 = require("../../fintekkers/models/price/price_pb");
|
|
38
|
+
const transaction_pb_1 = require("../../fintekkers/models/transaction/transaction_pb");
|
|
39
|
+
const decimal_value_pb_1 = require("../../fintekkers/models/util/decimal_value_pb");
|
|
40
|
+
const local_timestamp_pb_1 = require("../../fintekkers/models/util/local_timestamp_pb");
|
|
41
|
+
const timestamp_pb_1 = require("google-protobuf/google/protobuf/timestamp_pb");
|
|
42
|
+
const LinkCache = __importStar(require("../util/link-cache"));
|
|
43
|
+
function makeAsOf(epochSeconds = 1700000000) {
|
|
44
|
+
const ts = new timestamp_pb_1.Timestamp();
|
|
45
|
+
ts.setSeconds(epochSeconds);
|
|
46
|
+
ts.setNanos(0);
|
|
47
|
+
const proto = new local_timestamp_pb_1.LocalTimestampProto();
|
|
48
|
+
proto.setTimestamp(ts);
|
|
49
|
+
proto.setTimeZone('UTC');
|
|
50
|
+
return new datetime_1.ZonedDateTime(proto);
|
|
51
|
+
}
|
|
52
|
+
function linkPortfolio(uuid, asOf) {
|
|
53
|
+
const p = new portfolio_pb_1.PortfolioProto();
|
|
54
|
+
p.setUuid(uuid.toUUIDProto());
|
|
55
|
+
p.setAsOf(asOf.toProto());
|
|
56
|
+
p.setIsLink(true);
|
|
57
|
+
return p;
|
|
58
|
+
}
|
|
59
|
+
function fullPortfolio(uuid, asOf, name) {
|
|
60
|
+
const p = new portfolio_pb_1.PortfolioProto();
|
|
61
|
+
p.setUuid(uuid.toUUIDProto());
|
|
62
|
+
p.setAsOf(asOf.toProto());
|
|
63
|
+
p.setIsLink(false);
|
|
64
|
+
p.setPortfolioName(name);
|
|
65
|
+
return p;
|
|
66
|
+
}
|
|
67
|
+
function linkPriceProto(uuid, asOf) {
|
|
68
|
+
const p = new price_pb_1.PriceProto();
|
|
69
|
+
p.setUuid(uuid.toUUIDProto());
|
|
70
|
+
p.setAsOf(asOf.toProto());
|
|
71
|
+
p.setIsLink(true);
|
|
72
|
+
return p;
|
|
73
|
+
}
|
|
74
|
+
function fullPriceProto(uuid, asOf, value) {
|
|
75
|
+
const p = new price_pb_1.PriceProto();
|
|
76
|
+
p.setUuid(uuid.toUUIDProto());
|
|
77
|
+
p.setAsOf(asOf.toProto());
|
|
78
|
+
p.setIsLink(false);
|
|
79
|
+
const dv = new decimal_value_pb_1.DecimalValueProto();
|
|
80
|
+
dv.setArbitraryPrecisionValue(value);
|
|
81
|
+
p.setPrice(dv);
|
|
82
|
+
return p;
|
|
83
|
+
}
|
|
84
|
+
function linkTxnProto(uuid, asOf) {
|
|
85
|
+
const p = new transaction_pb_1.TransactionProto();
|
|
86
|
+
p.setUuid(uuid.toUUIDProto());
|
|
87
|
+
p.setAsOf(asOf.toProto());
|
|
88
|
+
p.setIsLink(true);
|
|
89
|
+
return p;
|
|
90
|
+
}
|
|
91
|
+
function fullTxnProto(uuid, asOf) {
|
|
92
|
+
const p = new transaction_pb_1.TransactionProto();
|
|
93
|
+
p.setUuid(uuid.toUUIDProto());
|
|
94
|
+
p.setAsOf(asOf.toProto());
|
|
95
|
+
p.setIsLink(false);
|
|
96
|
+
p.setTradeName('TXN');
|
|
97
|
+
return p;
|
|
98
|
+
}
|
|
99
|
+
beforeEach(() => {
|
|
100
|
+
LinkCache.PORTFOLIO.clear();
|
|
101
|
+
LinkCache.PRICE.clear();
|
|
102
|
+
LinkCache.TRANSACTION.clear();
|
|
103
|
+
});
|
|
104
|
+
// ---- Portfolio ----
|
|
105
|
+
test('Portfolio getPortfolioName on link wrapper hydrates from cache', () => {
|
|
106
|
+
const uuid = uuid_1.UUID.random();
|
|
107
|
+
const asOf = makeAsOf(1);
|
|
108
|
+
LinkCache.PORTFOLIO.put(uuid.toString(), fullPortfolio(uuid, asOf, 'Strategy Z'), asOf);
|
|
109
|
+
const p = new portfolio_1.default(linkPortfolio(uuid, asOf));
|
|
110
|
+
expect(p.isLink()).toBe(true);
|
|
111
|
+
expect(p.getPortfolioName()).toBe('Strategy Z');
|
|
112
|
+
expect(p.proto.getIsLink()).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
test('Portfolio cache miss throws with uuid in message', () => {
|
|
115
|
+
const uuid = uuid_1.UUID.random();
|
|
116
|
+
const asOf = makeAsOf(2);
|
|
117
|
+
const p = new portfolio_1.default(linkPortfolio(uuid, asOf));
|
|
118
|
+
expect(() => p.getPortfolioName()).toThrow(new RegExp(uuid.toString()));
|
|
119
|
+
});
|
|
120
|
+
// ---- Price ----
|
|
121
|
+
test('Price getPrice on link wrapper hydrates from cache', () => {
|
|
122
|
+
const uuid = uuid_1.UUID.random();
|
|
123
|
+
const asOf = makeAsOf(3);
|
|
124
|
+
LinkCache.PRICE.put(uuid.toString(), fullPriceProto(uuid, asOf, '123.45'), asOf);
|
|
125
|
+
const pr = new Price_1.default(linkPriceProto(uuid, asOf));
|
|
126
|
+
expect(pr.isLink()).toBe(true);
|
|
127
|
+
expect(pr.getPrice().toString()).toBe('123.45');
|
|
128
|
+
});
|
|
129
|
+
test('Price cache miss throws with uuid in message', () => {
|
|
130
|
+
const uuid = uuid_1.UUID.random();
|
|
131
|
+
const asOf = makeAsOf(4);
|
|
132
|
+
const pr = new Price_1.default(linkPriceProto(uuid, asOf));
|
|
133
|
+
expect(() => pr.getPrice()).toThrow(new RegExp(uuid.toString()));
|
|
134
|
+
});
|
|
135
|
+
// ---- Transaction ----
|
|
136
|
+
test('Transaction getTradeName on link wrapper hydrates from cache', () => {
|
|
137
|
+
const uuid = uuid_1.UUID.random();
|
|
138
|
+
const asOf = makeAsOf(5);
|
|
139
|
+
LinkCache.TRANSACTION.put(uuid.toString(), fullTxnProto(uuid, asOf), asOf);
|
|
140
|
+
const t = new transaction_1.default(linkTxnProto(uuid, asOf));
|
|
141
|
+
expect(t.isLink()).toBe(true);
|
|
142
|
+
expect(t.getTradeName()).toBe('TXN');
|
|
143
|
+
});
|
|
144
|
+
test('Transaction cache miss throws with uuid in message', () => {
|
|
145
|
+
const uuid = uuid_1.UUID.random();
|
|
146
|
+
const asOf = makeAsOf(6);
|
|
147
|
+
const t = new transaction_1.default(linkTxnProto(uuid, asOf));
|
|
148
|
+
expect(() => t.getTradeName()).toThrow(new RegExp(uuid.toString()));
|
|
149
|
+
});
|
|
150
|
+
test('Transaction link-safe accessors do not hydrate', () => {
|
|
151
|
+
const uuid = uuid_1.UUID.random();
|
|
152
|
+
const asOf = makeAsOf(7);
|
|
153
|
+
// No cache entry, no fetcher — link-safe accessors must still work.
|
|
154
|
+
const t = new transaction_1.default(linkTxnProto(uuid, asOf));
|
|
155
|
+
expect(t.isLink()).toBe(true);
|
|
156
|
+
expect(t.getID().toString()).toBe(uuid.toString());
|
|
157
|
+
});
|
|
158
|
+
//# sourceMappingURL=portfolio-price-transaction.lazy-hydrate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portfolio-price-transaction.lazy-hydrate.test.js","sourceRoot":"","sources":["portfolio-price-transaction.lazy-hydrate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Lazy-hydrate tests for Portfolio / Price / Transaction wrappers.
|
|
2
|
+
// Mirror of security.lazy-hydrate.test.ts — cache-only design, throws on miss.
|
|
3
|
+
|
|
4
|
+
import Portfolio from './portfolio/portfolio';
|
|
5
|
+
import Price from './price/Price';
|
|
6
|
+
import Transaction from './transaction/transaction';
|
|
7
|
+
import { UUID } from './utils/uuid';
|
|
8
|
+
import { ZonedDateTime } from './utils/datetime';
|
|
9
|
+
|
|
10
|
+
import { PortfolioProto } from '../../fintekkers/models/portfolio/portfolio_pb';
|
|
11
|
+
import { PriceProto } from '../../fintekkers/models/price/price_pb';
|
|
12
|
+
import { TransactionProto } from '../../fintekkers/models/transaction/transaction_pb';
|
|
13
|
+
import { DecimalValueProto } from '../../fintekkers/models/util/decimal_value_pb';
|
|
14
|
+
import { LocalTimestampProto } from '../../fintekkers/models/util/local_timestamp_pb';
|
|
15
|
+
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
|
16
|
+
|
|
17
|
+
import * as LinkCache from '../util/link-cache';
|
|
18
|
+
|
|
19
|
+
function makeAsOf(epochSeconds = 1_700_000_000): ZonedDateTime {
|
|
20
|
+
const ts = new Timestamp();
|
|
21
|
+
ts.setSeconds(epochSeconds);
|
|
22
|
+
ts.setNanos(0);
|
|
23
|
+
const proto = new LocalTimestampProto();
|
|
24
|
+
proto.setTimestamp(ts);
|
|
25
|
+
proto.setTimeZone('UTC');
|
|
26
|
+
return new ZonedDateTime(proto);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function linkPortfolio(uuid: UUID, asOf: ZonedDateTime): PortfolioProto {
|
|
30
|
+
const p = new PortfolioProto();
|
|
31
|
+
p.setUuid(uuid.toUUIDProto());
|
|
32
|
+
p.setAsOf(asOf.toProto());
|
|
33
|
+
p.setIsLink(true);
|
|
34
|
+
return p;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function fullPortfolio(uuid: UUID, asOf: ZonedDateTime, name: string): PortfolioProto {
|
|
38
|
+
const p = new PortfolioProto();
|
|
39
|
+
p.setUuid(uuid.toUUIDProto());
|
|
40
|
+
p.setAsOf(asOf.toProto());
|
|
41
|
+
p.setIsLink(false);
|
|
42
|
+
p.setPortfolioName(name);
|
|
43
|
+
return p;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function linkPriceProto(uuid: UUID, asOf: ZonedDateTime): PriceProto {
|
|
47
|
+
const p = new PriceProto();
|
|
48
|
+
p.setUuid(uuid.toUUIDProto());
|
|
49
|
+
p.setAsOf(asOf.toProto());
|
|
50
|
+
p.setIsLink(true);
|
|
51
|
+
return p;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function fullPriceProto(uuid: UUID, asOf: ZonedDateTime, value: string): PriceProto {
|
|
55
|
+
const p = new PriceProto();
|
|
56
|
+
p.setUuid(uuid.toUUIDProto());
|
|
57
|
+
p.setAsOf(asOf.toProto());
|
|
58
|
+
p.setIsLink(false);
|
|
59
|
+
const dv = new DecimalValueProto();
|
|
60
|
+
dv.setArbitraryPrecisionValue(value);
|
|
61
|
+
p.setPrice(dv);
|
|
62
|
+
return p;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function linkTxnProto(uuid: UUID, asOf: ZonedDateTime): TransactionProto {
|
|
66
|
+
const p = new TransactionProto();
|
|
67
|
+
p.setUuid(uuid.toUUIDProto());
|
|
68
|
+
p.setAsOf(asOf.toProto());
|
|
69
|
+
p.setIsLink(true);
|
|
70
|
+
return p;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function fullTxnProto(uuid: UUID, asOf: ZonedDateTime): TransactionProto {
|
|
74
|
+
const p = new TransactionProto();
|
|
75
|
+
p.setUuid(uuid.toUUIDProto());
|
|
76
|
+
p.setAsOf(asOf.toProto());
|
|
77
|
+
p.setIsLink(false);
|
|
78
|
+
p.setTradeName('TXN');
|
|
79
|
+
return p;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
LinkCache.PORTFOLIO.clear();
|
|
84
|
+
LinkCache.PRICE.clear();
|
|
85
|
+
LinkCache.TRANSACTION.clear();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// ---- Portfolio ----
|
|
89
|
+
|
|
90
|
+
test('Portfolio getPortfolioName on link wrapper hydrates from cache', () => {
|
|
91
|
+
const uuid = UUID.random();
|
|
92
|
+
const asOf = makeAsOf(1);
|
|
93
|
+
LinkCache.PORTFOLIO.put(uuid.toString(), fullPortfolio(uuid, asOf, 'Strategy Z'), asOf);
|
|
94
|
+
|
|
95
|
+
const p = new Portfolio(linkPortfolio(uuid, asOf));
|
|
96
|
+
expect(p.isLink()).toBe(true);
|
|
97
|
+
expect(p.getPortfolioName()).toBe('Strategy Z');
|
|
98
|
+
expect(p.proto.getIsLink()).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('Portfolio cache miss throws with uuid in message', () => {
|
|
102
|
+
const uuid = UUID.random();
|
|
103
|
+
const asOf = makeAsOf(2);
|
|
104
|
+
const p = new Portfolio(linkPortfolio(uuid, asOf));
|
|
105
|
+
expect(() => p.getPortfolioName()).toThrow(new RegExp(uuid.toString()));
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// ---- Price ----
|
|
109
|
+
|
|
110
|
+
test('Price getPrice on link wrapper hydrates from cache', () => {
|
|
111
|
+
const uuid = UUID.random();
|
|
112
|
+
const asOf = makeAsOf(3);
|
|
113
|
+
LinkCache.PRICE.put(uuid.toString(), fullPriceProto(uuid, asOf, '123.45'), asOf);
|
|
114
|
+
|
|
115
|
+
const pr = new Price(linkPriceProto(uuid, asOf));
|
|
116
|
+
expect(pr.isLink()).toBe(true);
|
|
117
|
+
expect(pr.getPrice().toString()).toBe('123.45');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('Price cache miss throws with uuid in message', () => {
|
|
121
|
+
const uuid = UUID.random();
|
|
122
|
+
const asOf = makeAsOf(4);
|
|
123
|
+
const pr = new Price(linkPriceProto(uuid, asOf));
|
|
124
|
+
expect(() => pr.getPrice()).toThrow(new RegExp(uuid.toString()));
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// ---- Transaction ----
|
|
128
|
+
|
|
129
|
+
test('Transaction getTradeName on link wrapper hydrates from cache', () => {
|
|
130
|
+
const uuid = UUID.random();
|
|
131
|
+
const asOf = makeAsOf(5);
|
|
132
|
+
LinkCache.TRANSACTION.put(uuid.toString(), fullTxnProto(uuid, asOf), asOf);
|
|
133
|
+
|
|
134
|
+
const t = new Transaction(linkTxnProto(uuid, asOf));
|
|
135
|
+
expect(t.isLink()).toBe(true);
|
|
136
|
+
expect(t.getTradeName()).toBe('TXN');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('Transaction cache miss throws with uuid in message', () => {
|
|
140
|
+
const uuid = UUID.random();
|
|
141
|
+
const asOf = makeAsOf(6);
|
|
142
|
+
const t = new Transaction(linkTxnProto(uuid, asOf));
|
|
143
|
+
expect(() => t.getTradeName()).toThrow(new RegExp(uuid.toString()));
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('Transaction link-safe accessors do not hydrate', () => {
|
|
147
|
+
const uuid = UUID.random();
|
|
148
|
+
const asOf = makeAsOf(7);
|
|
149
|
+
// No cache entry, no fetcher — link-safe accessors must still work.
|
|
150
|
+
const t = new Transaction(linkTxnProto(uuid, asOf));
|
|
151
|
+
expect(t.isLink()).toBe(true);
|
|
152
|
+
expect(t.getID().toString()).toBe(uuid.toString());
|
|
153
|
+
});
|
|
@@ -32,6 +32,11 @@ declare class Price {
|
|
|
32
32
|
* See docs/adr/is_link_pattern.md. Pair with LinkResolver to hydrate.
|
|
33
33
|
*/
|
|
34
34
|
isLink(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Lazy hydration. Cache-only — caller must pre-warm via LinkResolver.
|
|
37
|
+
* See docs/adr/lazy-link-hydration.md.
|
|
38
|
+
*/
|
|
39
|
+
private ensureHydrated;
|
|
35
40
|
getPrice(): Decimal;
|
|
36
41
|
getPriceType(): PriceTypeProto;
|
|
37
42
|
getSecurity(): Security;
|
|
@@ -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
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
@@ -11,6 +34,7 @@ const security_1 = __importDefault(require("../security/security"));
|
|
|
11
34
|
const datetime_1 = require("../utils/datetime");
|
|
12
35
|
const uuid_1 = require("../utils/uuid");
|
|
13
36
|
const decimal_js_1 = require("decimal.js");
|
|
37
|
+
const LinkCacheModule = __importStar(require("../../util/link-cache"));
|
|
14
38
|
class Price {
|
|
15
39
|
constructor(proto) {
|
|
16
40
|
this.proto = proto;
|
|
@@ -75,13 +99,37 @@ class Price {
|
|
|
75
99
|
isLink() {
|
|
76
100
|
return this.proto.getIsLink();
|
|
77
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Lazy hydration. Cache-only — caller must pre-warm via LinkResolver.
|
|
104
|
+
* See docs/adr/lazy-link-hydration.md.
|
|
105
|
+
*/
|
|
106
|
+
ensureHydrated() {
|
|
107
|
+
if (!this.proto.getIsLink())
|
|
108
|
+
return;
|
|
109
|
+
const uuidProto = this.proto.getUuid();
|
|
110
|
+
if (!uuidProto)
|
|
111
|
+
throw new Error("Cannot read fields on link-mode Price with no UUID set.");
|
|
112
|
+
const uuidKey = uuid_1.UUID.fromU8Array(uuidProto.getRawUuid_asU8()).toString();
|
|
113
|
+
const asOfProto = this.proto.getAsOf();
|
|
114
|
+
const asOf = asOfProto ? new datetime_1.ZonedDateTime(asOfProto) : null;
|
|
115
|
+
const cached = LinkCacheModule.PRICE.get(uuidKey, asOf);
|
|
116
|
+
if (cached) {
|
|
117
|
+
this.proto = cached;
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
throw new Error(`Cannot read fields on link-mode Price uuid=${uuidKey} `
|
|
121
|
+
+ `— LinkCache miss. Pre-warm via LinkResolver. `
|
|
122
|
+
+ `See docs/adr/lazy-link-hydration.md.`);
|
|
123
|
+
}
|
|
78
124
|
getPrice() {
|
|
125
|
+
this.ensureHydrated();
|
|
79
126
|
const priceValue = this.proto.getPrice();
|
|
80
127
|
if (!priceValue)
|
|
81
128
|
throw new Error("Price value is required");
|
|
82
129
|
return new decimal_js_1.Decimal(priceValue.getArbitraryPrecisionValue());
|
|
83
130
|
}
|
|
84
131
|
getPriceType() {
|
|
132
|
+
this.ensureHydrated();
|
|
85
133
|
return this.proto.getPriceType();
|
|
86
134
|
}
|
|
87
135
|
getSecurity() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Price.js","sourceRoot":"","sources":["Price.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Price.js","sourceRoot":"","sources":["Price.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ import Security from "../security/security";
|
|
|
6
6
|
import { ZonedDateTime } from "../utils/datetime";
|
|
7
7
|
import { UUID } from "../utils/uuid";
|
|
8
8
|
import { Decimal } from "decimal.js";
|
|
9
|
+
import * as LinkCacheModule from "../../util/link-cache";
|
|
9
10
|
|
|
10
11
|
class Price {
|
|
11
12
|
proto: PriceProto;
|
|
@@ -88,13 +89,38 @@ class Price {
|
|
|
88
89
|
return this.proto.getIsLink();
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Lazy hydration. Cache-only — caller must pre-warm via LinkResolver.
|
|
94
|
+
* See docs/adr/lazy-link-hydration.md.
|
|
95
|
+
*/
|
|
96
|
+
private ensureHydrated(): void {
|
|
97
|
+
if (!this.proto.getIsLink()) return;
|
|
98
|
+
const uuidProto = this.proto.getUuid();
|
|
99
|
+
if (!uuidProto) throw new Error("Cannot read fields on link-mode Price with no UUID set.");
|
|
100
|
+
const uuidKey = UUID.fromU8Array(uuidProto.getRawUuid_asU8()).toString();
|
|
101
|
+
const asOfProto = this.proto.getAsOf();
|
|
102
|
+
const asOf = asOfProto ? new ZonedDateTime(asOfProto) : null;
|
|
103
|
+
const cached = LinkCacheModule.PRICE.get(uuidKey, asOf);
|
|
104
|
+
if (cached) {
|
|
105
|
+
this.proto = cached;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Cannot read fields on link-mode Price uuid=${uuidKey} `
|
|
110
|
+
+ `— LinkCache miss. Pre-warm via LinkResolver. `
|
|
111
|
+
+ `See docs/adr/lazy-link-hydration.md.`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
91
115
|
getPrice(): Decimal {
|
|
116
|
+
this.ensureHydrated();
|
|
92
117
|
const priceValue = this.proto.getPrice();
|
|
93
118
|
if (!priceValue) throw new Error("Price value is required");
|
|
94
119
|
return new Decimal(priceValue.getArbitraryPrecisionValue());
|
|
95
120
|
}
|
|
96
121
|
|
|
97
122
|
getPriceType(): PriceTypeProto {
|
|
123
|
+
this.ensureHydrated();
|
|
98
124
|
return this.proto.getPriceType();
|
|
99
125
|
}
|
|
100
126
|
|
|
@@ -28,10 +28,16 @@ declare class Security {
|
|
|
28
28
|
private static _uuidToProto;
|
|
29
29
|
private static _zonedDateTimeToProto;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* Lazy hydration. If this Security is in link mode, swap in the resolved
|
|
32
|
+
* proto from LinkCache. On cache miss, throws — caller must pre-warm via
|
|
33
|
+
* LinkResolver. See docs/adr/lazy-link-hydration.md.
|
|
34
|
+
*
|
|
35
|
+
* TS variant is cache-only (no fetcher hook) because the gRPC stubs are
|
|
36
|
+
* async and chaining the resolver into every getter would force every
|
|
37
|
+
* accessor to become async. Pre-warming through LinkResolver keeps the
|
|
38
|
+
* sync getter API.
|
|
33
39
|
*/
|
|
34
|
-
private
|
|
40
|
+
private ensureHydrated;
|
|
35
41
|
/**
|
|
36
42
|
* Factory method to create the appropriate Security subclass based on
|
|
37
43
|
* the proto's product_type. Dispatch rules:
|