@fintekkers/ledger-models 0.1.130 → 0.1.132
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/fintekkers/models/portfolio/portfolio_pb.js +19 -13
- package/node/fintekkers/models/position/field_pb.js +7 -1
- package/node/fintekkers/models/position/measure_pb.js +7 -1
- package/node/fintekkers/models/position/position_filter_pb.js +13 -7
- package/node/fintekkers/models/position/position_pb.js +17 -11
- package/node/fintekkers/models/position/position_status_pb.js +7 -1
- package/node/fintekkers/models/position/position_util_pb.js +17 -11
- package/node/fintekkers/models/price/price_pb.js +20 -14
- package/node/fintekkers/models/price/price_type_pb.js +7 -1
- package/node/fintekkers/models/security/bond/auction_type_pb.js +7 -1
- package/node/fintekkers/models/security/bond/issuance_pb.js +23 -17
- package/node/fintekkers/models/security/coupon_frequency_pb.js +7 -1
- package/node/fintekkers/models/security/coupon_type_pb.js +7 -1
- package/node/fintekkers/models/security/identifier/identifier_pb.js +15 -9
- package/node/fintekkers/models/security/identifier/identifier_type_pb.js +7 -1
- package/node/fintekkers/models/security/index/index_type_pb.js +7 -1
- package/node/fintekkers/models/security/index_composition_grpc_pb.js +1 -0
- package/node/fintekkers/models/security/index_composition_pb.js +29 -23
- package/node/fintekkers/models/security/security_pb.js +96 -90
- package/node/fintekkers/models/security/security_quantity_type_pb.js +7 -1
- package/node/fintekkers/models/security/security_type_pb.js +7 -1
- package/node/fintekkers/models/security/tenor_pb.js +15 -9
- package/node/fintekkers/models/security/tenor_type_pb.js +7 -1
- package/node/fintekkers/models/strategy/strategy_allocation_pb.js +19 -13
- package/node/fintekkers/models/strategy/strategy_pb.js +20 -14
- package/node/fintekkers/models/transaction/transaction_pb.js +30 -24
- package/node/fintekkers/models/transaction/transaction_type_pb.js +7 -1
- package/node/fintekkers/models/util/api/api_key_pb.js +16 -10
- package/node/fintekkers/models/util/currency_grpc_pb.js +1 -0
- package/node/fintekkers/models/util/currency_pb.js +10 -4
- package/node/fintekkers/models/util/date_range_pb.js +14 -8
- package/node/fintekkers/models/util/decimal_value_pb.js +10 -4
- package/node/fintekkers/models/util/endpoint_pb.js +13 -7
- package/node/fintekkers/models/util/local_date_pb.js +11 -5
- package/node/fintekkers/models/util/local_timestamp_pb.js +11 -5
- package/node/fintekkers/models/util/lock/node_partition_pb.js +15 -9
- package/node/fintekkers/models/util/lock/node_state_pb.js +16 -10
- package/node/fintekkers/models/util/uuid_pb.js +9 -3
- package/node/fintekkers/models/valuation/cashflow_grpc_pb.js +1 -0
- package/node/fintekkers/models/valuation/cashflow_pb.js +13 -7
- package/node/fintekkers/requests/index_composition/create_index_composition_request_grpc_pb.js +1 -0
- package/node/fintekkers/requests/index_composition/create_index_composition_request_pb.js +22 -16
- package/node/fintekkers/requests/index_composition/get_index_composition_request_grpc_pb.js +1 -0
- package/node/fintekkers/requests/index_composition/get_index_composition_request_pb.js +22 -16
- package/node/fintekkers/requests/portfolio/create_portfolio_request_pb.js +13 -7
- package/node/fintekkers/requests/portfolio/create_portfolio_response_pb.js +14 -8
- package/node/fintekkers/requests/portfolio/query_portfolio_request_pb.js +17 -11
- package/node/fintekkers/requests/portfolio/query_portfolio_response_pb.js +14 -8
- package/node/fintekkers/requests/position/query_position_request_pb.js +27 -15
- package/node/fintekkers/requests/position/query_position_response_pb.js +16 -10
- package/node/fintekkers/requests/price/create_price_request_pb.js +13 -7
- package/node/fintekkers/requests/price/create_price_response_pb.js +14 -8
- package/node/fintekkers/requests/price/query_price_request_pb.js +18 -12
- package/node/fintekkers/requests/price/query_price_response_pb.js +14 -8
- package/node/fintekkers/requests/security/create_security_request_pb.js +13 -7
- package/node/fintekkers/requests/security/create_security_response_pb.js +15 -9
- package/node/fintekkers/requests/security/get_field_values_request_pb.js +13 -7
- package/node/fintekkers/requests/security/get_field_values_response_pb.js +13 -7
- package/node/fintekkers/requests/security/get_fields_response_pb.js +17 -8
- package/node/fintekkers/requests/security/query_security_request_pb.js +17 -11
- package/node/fintekkers/requests/security/query_security_response_pb.js +15 -9
- package/node/fintekkers/requests/transaction/create_transaction_request_pb.js +13 -7
- package/node/fintekkers/requests/transaction/create_transaction_response_pb.js +14 -8
- package/node/fintekkers/requests/transaction/query_transaction_request_pb.js +16 -10
- package/node/fintekkers/requests/transaction/query_transaction_response_pb.js +15 -9
- package/node/fintekkers/requests/util/delete_request_grpc_pb.js +1 -0
- package/node/fintekkers/requests/util/delete_request_pb.js +34 -28
- package/node/fintekkers/requests/util/errors/error_pb.js +13 -7
- package/node/fintekkers/requests/util/errors/message_pb.js +12 -6
- package/node/fintekkers/requests/util/errors/summary_pb.js +10 -4
- package/node/fintekkers/requests/util/lock/lock_request_pb.js +14 -8
- package/node/fintekkers/requests/util/lock/lock_response_pb.js +15 -9
- package/node/fintekkers/requests/util/operation_pb.js +7 -1
- package/node/fintekkers/requests/valuation/curve_request_grpc_pb.js +1 -0
- package/node/fintekkers/requests/valuation/curve_request_pb.d.ts +12 -0
- package/node/fintekkers/requests/valuation/curve_request_pb.js +125 -14
- package/node/fintekkers/requests/valuation/curve_response_grpc_pb.js +1 -0
- package/node/fintekkers/requests/valuation/curve_response_pb.js +21 -15
- package/node/fintekkers/requests/valuation/product_inputs.test.d.ts +6 -0
- package/node/fintekkers/requests/valuation/product_inputs.test.js +146 -0
- package/node/fintekkers/requests/valuation/product_inputs.test.js.map +1 -0
- package/node/fintekkers/requests/valuation/product_inputs_grpc_pb.js +1 -0
- package/node/fintekkers/requests/valuation/product_inputs_pb.d.ts +42 -0
- package/node/fintekkers/requests/valuation/product_inputs_pb.js +360 -27
- package/node/fintekkers/requests/valuation/valuation_request_pb.js +25 -16
- package/node/fintekkers/requests/valuation/valuation_response_pb.js +16 -10
- package/node/fintekkers/services/index-composition-service/index_composition_service_grpc_pb.js +14 -14
- package/node/fintekkers/services/index-composition-service/index_composition_service_pb.js +7 -1
- package/node/fintekkers/services/lock-service/lock_service_grpc_pb.js +23 -23
- package/node/fintekkers/services/lock-service/lock_service_pb.js +21 -15
- package/node/fintekkers/services/portfolio-service/portfolio_service_grpc_pb.js +8 -8
- package/node/fintekkers/services/portfolio-service/portfolio_service_pb.js +7 -1
- package/node/fintekkers/services/position-service/position_service_grpc_pb.js +10 -10
- package/node/fintekkers/services/position-service/position_service_pb.js +7 -1
- package/node/fintekkers/services/price-service/price_service_grpc_pb.js +6 -6
- package/node/fintekkers/services/price-service/price_service_pb.js +7 -1
- package/node/fintekkers/services/security-service/security_service_grpc_pb.js +12 -12
- package/node/fintekkers/services/security-service/security_service_pb.js +7 -1
- package/node/fintekkers/services/transaction-service/transaction_service_grpc_pb.js +11 -11
- package/node/fintekkers/services/transaction-service/transaction_service_pb.js +7 -1
- package/node/fintekkers/services/valuation-service/valuation_service_grpc_pb.js +5 -5
- package/node/fintekkers/services/valuation-service/valuation_service_pb.js +7 -1
- package/node/wrappers/models/price/Price.d.ts +5 -0
- package/node/wrappers/models/price/Price.js +7 -0
- package/node/wrappers/models/price/Price.js.map +1 -1
- package/node/wrappers/models/price/Price.ts +8 -0
- package/node/wrappers/models/security/security.d.ts +6 -0
- package/node/wrappers/models/security/security.js +8 -0
- package/node/wrappers/models/security/security.js.map +1 -1
- package/node/wrappers/models/security/security.ts +9 -0
- package/node/wrappers/services/price-service/PriceService.d.ts +19 -0
- package/node/wrappers/services/price-service/PriceService.js +26 -0
- package/node/wrappers/services/price-service/PriceService.js.map +1 -1
- package/node/wrappers/services/price-service/PriceService.ts +29 -0
- package/node/wrappers/services/searchWithSecurities.test.js +125 -0
- package/node/wrappers/services/searchWithSecurities.test.js.map +1 -0
- package/node/wrappers/services/searchWithSecurities.test.ts +103 -0
- package/node/wrappers/services/transaction-service/TransactionService.d.ts +14 -0
- package/node/wrappers/services/transaction-service/TransactionService.js +25 -0
- package/node/wrappers/services/transaction-service/TransactionService.js.map +1 -1
- package/node/wrappers/services/transaction-service/TransactionService.ts +29 -0
- package/node/wrappers/util/link-resolver.d.ts +127 -0
- package/node/wrappers/util/link-resolver.js +378 -0
- package/node/wrappers/util/link-resolver.js.map +1 -0
- package/node/wrappers/util/link-resolver.test.d.ts +1 -0
- package/node/wrappers/util/link-resolver.test.js +349 -0
- package/node/wrappers/util/link-resolver.test.js.map +1 -0
- package/node/wrappers/util/link-resolver.test.ts +402 -0
- package/node/wrappers/util/link-resolver.ts +448 -0
- package/package.json +1 -1
- package/node/wrappers/services/security-service/SecurityService.searchByUuid.test.js +0 -38
- package/node/wrappers/services/security-service/SecurityService.searchByUuid.test.js.map +0 -1
- package/node/wrappers/services/security-service/SecurityService.searchByUuid.test.ts +0 -32
- /package/node/wrappers/services/{security-service/SecurityService.searchByUuid.test.d.ts → searchWithSecurities.test.d.ts} +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
const PriceService_1 = require("./price-service/PriceService");
|
|
39
|
+
const link_resolver_1 = __importDefault(require("../util/link-resolver"));
|
|
40
|
+
const Price_1 = __importDefault(require("../models/price/Price"));
|
|
41
|
+
const uuid_1 = require("../models/utils/uuid");
|
|
42
|
+
const positionfilter_1 = require("../models/position/positionfilter");
|
|
43
|
+
const dt = __importStar(require("../models/utils/datetime"));
|
|
44
|
+
const security_pb_1 = require("../../fintekkers/models/security/security_pb");
|
|
45
|
+
const price_pb_1 = require("../../fintekkers/models/price/price_pb");
|
|
46
|
+
const decimal_value_pb_1 = require("../../fintekkers/models/util/decimal_value_pb");
|
|
47
|
+
const identifier_pb_1 = require("../../fintekkers/models/security/identifier/identifier_pb");
|
|
48
|
+
const query_security_response_pb_1 = require("../../fintekkers/requests/security/query_security_response_pb");
|
|
49
|
+
/**
|
|
50
|
+
* End-to-end test: priceService.searchWithSecurities resolves all link
|
|
51
|
+
* securities embedded in the returned Prices via a single batched
|
|
52
|
+
* GetByIds RPC.
|
|
53
|
+
*/
|
|
54
|
+
function fullSecurity(uuid, issuerName) {
|
|
55
|
+
const proto = new security_pb_1.SecurityProto();
|
|
56
|
+
proto.setObjectClass('Security');
|
|
57
|
+
proto.setVersion('0.0.1');
|
|
58
|
+
proto.setUuid(uuid.toUUIDProto());
|
|
59
|
+
proto.setIsLink(false);
|
|
60
|
+
proto.setIssuerName(issuerName);
|
|
61
|
+
const ident = new identifier_pb_1.IdentifierProto();
|
|
62
|
+
ident.setIdentifierValue(`TICKER-${issuerName}`);
|
|
63
|
+
proto.setIdentifier(ident);
|
|
64
|
+
return proto;
|
|
65
|
+
}
|
|
66
|
+
function linkPriceProto(securityUuid, priceValue) {
|
|
67
|
+
const linkSec = new security_pb_1.SecurityProto();
|
|
68
|
+
linkSec.setUuid(securityUuid.toUUIDProto());
|
|
69
|
+
linkSec.setIsLink(true);
|
|
70
|
+
const priceProto = new price_pb_1.PriceProto();
|
|
71
|
+
priceProto.setObjectClass('Price');
|
|
72
|
+
priceProto.setVersion('0.0.1');
|
|
73
|
+
priceProto.setUuid(uuid_1.UUID.random().toUUIDProto());
|
|
74
|
+
priceProto.setSecurity(linkSec);
|
|
75
|
+
const dv = new decimal_value_pb_1.DecimalValueProto();
|
|
76
|
+
dv.setArbitraryPrecisionValue(priceValue);
|
|
77
|
+
priceProto.setPrice(dv);
|
|
78
|
+
return priceProto;
|
|
79
|
+
}
|
|
80
|
+
test('PriceService.searchWithSecurities returns hydrated Prices end-to-end', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
81
|
+
const uuidA = uuid_1.UUID.random();
|
|
82
|
+
const uuidB = uuid_1.UUID.random();
|
|
83
|
+
const store = new Map([
|
|
84
|
+
[uuidA.toString(), fullSecurity(uuidA, 'AAPL')],
|
|
85
|
+
[uuidB.toString(), fullSecurity(uuidB, 'MSFT')],
|
|
86
|
+
]);
|
|
87
|
+
const callLog = { count: 0 };
|
|
88
|
+
// Stub LinkResolver with a mock SecurityClient.
|
|
89
|
+
const mockSecurityClient = {
|
|
90
|
+
getByIds: (request, callback) => {
|
|
91
|
+
callLog.count += 1;
|
|
92
|
+
const requested = request.getUuidsList().map((u) => uuid_1.UUID.fromU8Array(u.getRawUuid_asU8()).toString());
|
|
93
|
+
const response = new query_security_response_pb_1.QuerySecurityResponseProto();
|
|
94
|
+
response.setSecurityResponseList(requested.map((u) => store.get(u)).filter(Boolean));
|
|
95
|
+
setImmediate(() => callback(null, response));
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const linkResolver = new link_resolver_1.default({
|
|
99
|
+
securityClient: mockSecurityClient,
|
|
100
|
+
portfolioClient: {},
|
|
101
|
+
});
|
|
102
|
+
// Stub PriceService.search to skip the gRPC stream and return canned Prices.
|
|
103
|
+
const priceService = new PriceService_1.PriceService();
|
|
104
|
+
jest
|
|
105
|
+
.spyOn(priceService, 'search')
|
|
106
|
+
.mockResolvedValue([
|
|
107
|
+
new Price_1.default(linkPriceProto(uuidA, '100')),
|
|
108
|
+
new Price_1.default(linkPriceProto(uuidA, '101')),
|
|
109
|
+
new Price_1.default(linkPriceProto(uuidB, '200')),
|
|
110
|
+
]);
|
|
111
|
+
const asOf = dt.ZonedDateTime.now().toProto();
|
|
112
|
+
const filter = new positionfilter_1.PositionFilter();
|
|
113
|
+
const prices = yield priceService.searchWithSecurities(asOf, filter, linkResolver);
|
|
114
|
+
expect(prices).toHaveLength(3);
|
|
115
|
+
// 1 batched RPC for 2 unique security UUIDs.
|
|
116
|
+
expect(callLog.count).toBe(1);
|
|
117
|
+
// Every Price now has a hydrated full Security embedded.
|
|
118
|
+
for (const p of prices) {
|
|
119
|
+
const sec = p.proto.getSecurity();
|
|
120
|
+
expect(sec.getIsLink()).toBe(false);
|
|
121
|
+
expect(['AAPL', 'MSFT']).toContain(sec.getIssuerName());
|
|
122
|
+
expect(sec.getIdentifier().getIdentifierValue()).toMatch(/^TICKER-/);
|
|
123
|
+
}
|
|
124
|
+
}));
|
|
125
|
+
//# sourceMappingURL=searchWithSecurities.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"searchWithSecurities.test.js","sourceRoot":"","sources":["searchWithSecurities.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { PriceService } from './price-service/PriceService';
|
|
2
|
+
import LinkResolver from '../util/link-resolver';
|
|
3
|
+
import Price from '../models/price/Price';
|
|
4
|
+
import { UUID } from '../models/utils/uuid';
|
|
5
|
+
import { PositionFilter } from '../models/position/positionfilter';
|
|
6
|
+
import * as dt from '../models/utils/datetime';
|
|
7
|
+
|
|
8
|
+
import { SecurityProto } from '../../fintekkers/models/security/security_pb';
|
|
9
|
+
import { PriceProto } from '../../fintekkers/models/price/price_pb';
|
|
10
|
+
import { DecimalValueProto } from '../../fintekkers/models/util/decimal_value_pb';
|
|
11
|
+
import { IdentifierProto } from '../../fintekkers/models/security/identifier/identifier_pb';
|
|
12
|
+
import { QuerySecurityResponseProto } from '../../fintekkers/requests/security/query_security_response_pb';
|
|
13
|
+
import { QuerySecurityRequestProto } from '../../fintekkers/requests/security/query_security_request_pb';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* End-to-end test: priceService.searchWithSecurities resolves all link
|
|
17
|
+
* securities embedded in the returned Prices via a single batched
|
|
18
|
+
* GetByIds RPC.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
function fullSecurity(uuid: UUID, issuerName: string): SecurityProto {
|
|
22
|
+
const proto = new SecurityProto();
|
|
23
|
+
proto.setObjectClass('Security');
|
|
24
|
+
proto.setVersion('0.0.1');
|
|
25
|
+
proto.setUuid(uuid.toUUIDProto());
|
|
26
|
+
proto.setIsLink(false);
|
|
27
|
+
proto.setIssuerName(issuerName);
|
|
28
|
+
const ident = new IdentifierProto();
|
|
29
|
+
ident.setIdentifierValue(`TICKER-${issuerName}`);
|
|
30
|
+
proto.setIdentifier(ident);
|
|
31
|
+
return proto;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function linkPriceProto(securityUuid: UUID, priceValue: string): PriceProto {
|
|
35
|
+
const linkSec = new SecurityProto();
|
|
36
|
+
linkSec.setUuid(securityUuid.toUUIDProto());
|
|
37
|
+
linkSec.setIsLink(true);
|
|
38
|
+
|
|
39
|
+
const priceProto = new PriceProto();
|
|
40
|
+
priceProto.setObjectClass('Price');
|
|
41
|
+
priceProto.setVersion('0.0.1');
|
|
42
|
+
priceProto.setUuid(UUID.random().toUUIDProto());
|
|
43
|
+
priceProto.setSecurity(linkSec);
|
|
44
|
+
const dv = new DecimalValueProto();
|
|
45
|
+
dv.setArbitraryPrecisionValue(priceValue);
|
|
46
|
+
priceProto.setPrice(dv);
|
|
47
|
+
return priceProto;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
test('PriceService.searchWithSecurities returns hydrated Prices end-to-end', async () => {
|
|
51
|
+
const uuidA = UUID.random();
|
|
52
|
+
const uuidB = UUID.random();
|
|
53
|
+
const store = new Map<string, SecurityProto>([
|
|
54
|
+
[uuidA.toString(), fullSecurity(uuidA, 'AAPL')],
|
|
55
|
+
[uuidB.toString(), fullSecurity(uuidB, 'MSFT')],
|
|
56
|
+
]);
|
|
57
|
+
const callLog = { count: 0 };
|
|
58
|
+
|
|
59
|
+
// Stub LinkResolver with a mock SecurityClient.
|
|
60
|
+
const mockSecurityClient = {
|
|
61
|
+
getByIds: (
|
|
62
|
+
request: QuerySecurityRequestProto,
|
|
63
|
+
callback: (err: Error | null, response: QuerySecurityResponseProto) => void,
|
|
64
|
+
) => {
|
|
65
|
+
callLog.count += 1;
|
|
66
|
+
const requested = request.getUuidsList().map((u) => UUID.fromU8Array(u.getRawUuid_asU8()).toString());
|
|
67
|
+
const response = new QuerySecurityResponseProto();
|
|
68
|
+
response.setSecurityResponseList(requested.map((u) => store.get(u)!).filter(Boolean));
|
|
69
|
+
setImmediate(() => callback(null, response));
|
|
70
|
+
},
|
|
71
|
+
} as any;
|
|
72
|
+
|
|
73
|
+
const linkResolver = new LinkResolver({
|
|
74
|
+
securityClient: mockSecurityClient,
|
|
75
|
+
portfolioClient: {} as any,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Stub PriceService.search to skip the gRPC stream and return canned Prices.
|
|
79
|
+
const priceService = new PriceService();
|
|
80
|
+
jest
|
|
81
|
+
.spyOn(priceService, 'search')
|
|
82
|
+
.mockResolvedValue([
|
|
83
|
+
new Price(linkPriceProto(uuidA, '100')),
|
|
84
|
+
new Price(linkPriceProto(uuidA, '101')),
|
|
85
|
+
new Price(linkPriceProto(uuidB, '200')),
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
const asOf = dt.ZonedDateTime.now().toProto();
|
|
89
|
+
const filter = new PositionFilter();
|
|
90
|
+
|
|
91
|
+
const prices = await priceService.searchWithSecurities(asOf, filter, linkResolver);
|
|
92
|
+
|
|
93
|
+
expect(prices).toHaveLength(3);
|
|
94
|
+
// 1 batched RPC for 2 unique security UUIDs.
|
|
95
|
+
expect(callLog.count).toBe(1);
|
|
96
|
+
// Every Price now has a hydrated full Security embedded.
|
|
97
|
+
for (const p of prices) {
|
|
98
|
+
const sec = p.proto.getSecurity()!;
|
|
99
|
+
expect(sec.getIsLink()).toBe(false);
|
|
100
|
+
expect(['AAPL', 'MSFT']).toContain(sec.getIssuerName());
|
|
101
|
+
expect(sec.getIdentifier()!.getIdentifierValue()).toMatch(/^TICKER-/);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
@@ -3,11 +3,25 @@ import { PositionFilter } from '../../models/position/positionfilter';
|
|
|
3
3
|
import { LocalTimestampProto } from '../../../fintekkers/models/util/local_timestamp_pb';
|
|
4
4
|
import { SummaryProto } from '../../../fintekkers/requests/util/errors/summary_pb';
|
|
5
5
|
import { CreateTransactionResponseProto } from '../../../fintekkers/requests/transaction/create_transaction_response_pb';
|
|
6
|
+
import LinkResolver from '../../util/link-resolver';
|
|
6
7
|
declare class TransactionService {
|
|
7
8
|
private client;
|
|
8
9
|
constructor(apiKey?: string);
|
|
9
10
|
validateCreateTransaction(transaction: Transaction): Promise<SummaryProto>;
|
|
10
11
|
createTransaction(transaction: Transaction): Promise<CreateTransactionResponseProto>;
|
|
11
12
|
searchTransaction(asOf: LocalTimestampProto, positionFilter: PositionFilter, maxResults?: number): Promise<Transaction[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Search transactions and hydrate each Transaction's embedded Security
|
|
15
|
+
* AND Portfolio from link to full entity, with both fetches batched.
|
|
16
|
+
*
|
|
17
|
+
* Pass a shared `linkResolver` to share caching across multiple
|
|
18
|
+
* service-wrapper calls in the same request scope. If omitted, a new
|
|
19
|
+
* resolver is constructed per call.
|
|
20
|
+
*
|
|
21
|
+
* Mutates each returned Transaction.proto's embedded SecurityProto and
|
|
22
|
+
* PortfolioProto in place (link → full). See LinkResolver for cache +
|
|
23
|
+
* dedupe semantics.
|
|
24
|
+
*/
|
|
25
|
+
searchWithSecurityAndPortfolio(asOf: LocalTimestampProto, positionFilter: PositionFilter, maxResults?: number, linkResolver?: LinkResolver): Promise<Transaction[]>;
|
|
12
26
|
}
|
|
13
27
|
export { TransactionService };
|
|
@@ -22,6 +22,7 @@ const transaction_service_grpc_pb_1 = require("../../../fintekkers/services/tran
|
|
|
22
22
|
const create_transaction_request_pb_1 = require("../../../fintekkers/requests/transaction/create_transaction_request_pb");
|
|
23
23
|
const query_transaction_request_pb_1 = require("../../../fintekkers/requests/transaction/query_transaction_request_pb");
|
|
24
24
|
const requestcontext_1 = __importDefault(require("../../models/utils/requestcontext"));
|
|
25
|
+
const link_resolver_1 = __importDefault(require("../../util/link-resolver"));
|
|
25
26
|
class TransactionService {
|
|
26
27
|
constructor(apiKey) {
|
|
27
28
|
if (apiKey) {
|
|
@@ -86,6 +87,30 @@ class TransactionService {
|
|
|
86
87
|
}
|
|
87
88
|
return processStreamSynchronously();
|
|
88
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Search transactions and hydrate each Transaction's embedded Security
|
|
92
|
+
* AND Portfolio from link to full entity, with both fetches batched.
|
|
93
|
+
*
|
|
94
|
+
* Pass a shared `linkResolver` to share caching across multiple
|
|
95
|
+
* service-wrapper calls in the same request scope. If omitted, a new
|
|
96
|
+
* resolver is constructed per call.
|
|
97
|
+
*
|
|
98
|
+
* Mutates each returned Transaction.proto's embedded SecurityProto and
|
|
99
|
+
* PortfolioProto in place (link → full). See LinkResolver for cache +
|
|
100
|
+
* dedupe semantics.
|
|
101
|
+
*/
|
|
102
|
+
searchWithSecurityAndPortfolio(asOf, positionFilter, maxResults = 100, linkResolver) {
|
|
103
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
+
const txns = yield this.searchTransaction(asOf, positionFilter, maxResults);
|
|
105
|
+
const resolver = linkResolver !== null && linkResolver !== void 0 ? linkResolver : new link_resolver_1.default();
|
|
106
|
+
// Run both resolves in parallel — they hit different services.
|
|
107
|
+
yield Promise.all([
|
|
108
|
+
resolver.resolveSecurities(txns),
|
|
109
|
+
resolver.resolvePortfolios(txns),
|
|
110
|
+
]);
|
|
111
|
+
return txns;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
89
114
|
}
|
|
90
115
|
exports.TransactionService = TransactionService;
|
|
91
116
|
//# sourceMappingURL=TransactionService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionService.js","sourceRoot":"","sources":["TransactionService.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,+BAAiC;AAEjC,SAAS;AACT,uFAA+D;AAK/D,cAAc;AAEd,sBAAsB;AACtB,8HAAiH;AACjH,0HAAuH;AAEvH,wHAAqH;AAErH,uFAA0D;
|
|
1
|
+
{"version":3,"file":"TransactionService.js","sourceRoot":"","sources":["TransactionService.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ import { CreateTransactionResponseProto } from '../../../fintekkers/requests/tra
|
|
|
15
15
|
import { QueryTransactionRequestProto } from '../../../fintekkers/requests/transaction/query_transaction_request_pb';
|
|
16
16
|
import { QueryTransactionResponseProto } from '../../../fintekkers/requests/transaction/query_transaction_response_pb';
|
|
17
17
|
import EnvConfig from '../../models/utils/requestcontext';
|
|
18
|
+
import LinkResolver from '../../util/link-resolver';
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class TransactionService {
|
|
@@ -89,6 +90,34 @@ class TransactionService {
|
|
|
89
90
|
|
|
90
91
|
return processStreamSynchronously();
|
|
91
92
|
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Search transactions and hydrate each Transaction's embedded Security
|
|
96
|
+
* AND Portfolio from link to full entity, with both fetches batched.
|
|
97
|
+
*
|
|
98
|
+
* Pass a shared `linkResolver` to share caching across multiple
|
|
99
|
+
* service-wrapper calls in the same request scope. If omitted, a new
|
|
100
|
+
* resolver is constructed per call.
|
|
101
|
+
*
|
|
102
|
+
* Mutates each returned Transaction.proto's embedded SecurityProto and
|
|
103
|
+
* PortfolioProto in place (link → full). See LinkResolver for cache +
|
|
104
|
+
* dedupe semantics.
|
|
105
|
+
*/
|
|
106
|
+
async searchWithSecurityAndPortfolio(
|
|
107
|
+
asOf: LocalTimestampProto,
|
|
108
|
+
positionFilter: PositionFilter,
|
|
109
|
+
maxResults: number = 100,
|
|
110
|
+
linkResolver?: LinkResolver,
|
|
111
|
+
): Promise<Transaction[]> {
|
|
112
|
+
const txns = await this.searchTransaction(asOf, positionFilter, maxResults);
|
|
113
|
+
const resolver = linkResolver ?? new LinkResolver();
|
|
114
|
+
// Run both resolves in parallel — they hit different services.
|
|
115
|
+
await Promise.all([
|
|
116
|
+
resolver.resolveSecurities(txns),
|
|
117
|
+
resolver.resolvePortfolios(txns),
|
|
118
|
+
]);
|
|
119
|
+
return txns;
|
|
120
|
+
}
|
|
92
121
|
}
|
|
93
122
|
|
|
94
123
|
export { TransactionService };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { SecurityProto } from '../../fintekkers/models/security/security_pb';
|
|
2
|
+
import { PortfolioProto } from '../../fintekkers/models/portfolio/portfolio_pb';
|
|
3
|
+
import { LocalTimestampProto } from '../../fintekkers/models/util/local_timestamp_pb';
|
|
4
|
+
import { SecurityClient } from '../../fintekkers/services/security-service/security_service_grpc_pb';
|
|
5
|
+
import { PortfolioClient } from '../../fintekkers/services/portfolio-service/portfolio_service_grpc_pb';
|
|
6
|
+
import Security from '../models/security/security';
|
|
7
|
+
import Portfolio from '../models/portfolio/portfolio';
|
|
8
|
+
import { UUID } from '../models/utils/uuid';
|
|
9
|
+
/**
|
|
10
|
+
* LinkResolver — bulk hydration of `is_link=true` entity references into
|
|
11
|
+
* full entities. Implements the consumer side of the `is_link` pattern
|
|
12
|
+
* documented in `docs/adr/is_link_pattern.md`.
|
|
13
|
+
*
|
|
14
|
+
* Two surface methods:
|
|
15
|
+
* - getSecurity(uuid) / getPortfolio(uuid): single-UUID resolution. Cached
|
|
16
|
+
* and concurrent-deduped.
|
|
17
|
+
* - resolveSecurities(items) / resolvePortfolios(items): bulk in-place
|
|
18
|
+
* mutation across a heterogeneous list of items that each have a
|
|
19
|
+
* proto-style getter+setter for the embedded entity. Collects unique
|
|
20
|
+
* link UUIDs, fires one batched GetByIds RPC, mutates each item's proto
|
|
21
|
+
* to swap the link sub-message for the resolved full entity (with
|
|
22
|
+
* is_link=false on the embedded copy).
|
|
23
|
+
*
|
|
24
|
+
* Caching:
|
|
25
|
+
* - Process-level LRU keyed on UUID string. Default 1000 entries, no TTL
|
|
26
|
+
* (entries live until evicted by LRU). Long-running services that need
|
|
27
|
+
* freshness should pass `{ ttlMs: <ms> }`. Tests can disable with
|
|
28
|
+
* `{ cacheSize: 0 }`.
|
|
29
|
+
* - Concurrent same-UUID requests are deduped via an in-flight promise
|
|
30
|
+
* map — N parallel callers for the same UUID share one RPC.
|
|
31
|
+
*
|
|
32
|
+
* RPC choice: uses `GetByIds` (unary, UUID-keyed bulk) per the ADR. The
|
|
33
|
+
* existing `SecurityService.search` (streaming) would also work but
|
|
34
|
+
* requires more wrapper plumbing for batched-by-UUID semantics.
|
|
35
|
+
*
|
|
36
|
+
* Mutation semantic: when bulk-resolving, the embedded sub-message is
|
|
37
|
+
* replaced (not the outer entity). Outer Price.proto.is_link is unchanged;
|
|
38
|
+
* only the inner SecurityProto is swapped from link-stub to full entity.
|
|
39
|
+
* Wrapper objects that read through the proto (`price.getSecurity()`)
|
|
40
|
+
* automatically see the resolved data.
|
|
41
|
+
*
|
|
42
|
+
* Time-travel (`as_of`) semantic: per is_link_pattern.md addendum, when
|
|
43
|
+
* a link sub-message has only `uuid` set the resolver fetches the latest
|
|
44
|
+
* version. When the link sub-message ALSO has `as_of` set, the resolver
|
|
45
|
+
* fetches the version of the entity as of that timestamp. The cache is
|
|
46
|
+
* keyed on (uuid, as_of) so the same UUID at different timestamps does
|
|
47
|
+
* not collide. Bulk lookups group by `as_of` (one GetByIds RPC per unique
|
|
48
|
+
* timestamp bucket, since the request proto carries a single as_of).
|
|
49
|
+
*/
|
|
50
|
+
export interface LinkResolverOptions {
|
|
51
|
+
/** Optional API key. If omitted, EnvConfig.apiCredentials is used. */
|
|
52
|
+
apiKey?: string;
|
|
53
|
+
/** LRU max entries. Default 1000. Set to 0 to disable caching. */
|
|
54
|
+
cacheSize?: number;
|
|
55
|
+
/** Per-entry TTL in ms. Default undefined (no expiry). */
|
|
56
|
+
ttlMs?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Test injection: clients to use instead of constructing real ones.
|
|
59
|
+
* Production callers should not set these.
|
|
60
|
+
*/
|
|
61
|
+
securityClient?: SecurityClient;
|
|
62
|
+
portfolioClient?: PortfolioClient;
|
|
63
|
+
}
|
|
64
|
+
declare class LinkResolver {
|
|
65
|
+
private securityClient;
|
|
66
|
+
private portfolioClient;
|
|
67
|
+
private securityCache;
|
|
68
|
+
private portfolioCache;
|
|
69
|
+
private securityInFlight;
|
|
70
|
+
private portfolioInFlight;
|
|
71
|
+
constructor(opts?: LinkResolverOptions);
|
|
72
|
+
/**
|
|
73
|
+
* Resolve a single SecurityProto by UUID. If `asOf` is supplied, fetch
|
|
74
|
+
* the version of the entity as of that timestamp; otherwise fetch the
|
|
75
|
+
* latest. Cached + concurrent-deduped on the (uuid, asOf) pair.
|
|
76
|
+
* Throws if the server doesn't return the UUID (no silent null).
|
|
77
|
+
*/
|
|
78
|
+
getSecurity(uuid: UUID, asOf?: LocalTimestampProto): Promise<Security>;
|
|
79
|
+
/**
|
|
80
|
+
* Resolve a single PortfolioProto by UUID, optionally as of `asOf`.
|
|
81
|
+
* Cached + concurrent-deduped on (uuid, asOf).
|
|
82
|
+
*/
|
|
83
|
+
getPortfolio(uuid: UUID, asOf?: LocalTimestampProto): Promise<Portfolio>;
|
|
84
|
+
/**
|
|
85
|
+
* Walk `items`, find the ones whose embedded security is `is_link=true`,
|
|
86
|
+
* batch-fetch the unique (uuid, as_of) pairs (grouped by as_of so each
|
|
87
|
+
* GetByIds RPC carries one timestamp), and mutate each item's proto in
|
|
88
|
+
* place so subsequent `item.getSecurity()` calls return the full entity.
|
|
89
|
+
* Returns the same array for chaining.
|
|
90
|
+
*
|
|
91
|
+
* Honors per-link `as_of`: if the embedded sub-message has `as_of` set,
|
|
92
|
+
* the resolver fetches the version of the entity at that timestamp,
|
|
93
|
+
* not the latest.
|
|
94
|
+
*
|
|
95
|
+
* `T` is structural: anything with a `proto` field that exposes
|
|
96
|
+
* `getSecurity()` / `setSecurity()` works (Price, Transaction, etc).
|
|
97
|
+
*/
|
|
98
|
+
resolveSecurities<T extends ResolvableSecurity>(items: T[]): Promise<T[]>;
|
|
99
|
+
/**
|
|
100
|
+
* Same shape as resolveSecurities, but for embedded PortfolioProto.
|
|
101
|
+
* Honors per-link `as_of` the same way.
|
|
102
|
+
*/
|
|
103
|
+
resolvePortfolios<T extends ResolvablePortfolio>(items: T[]): Promise<T[]>;
|
|
104
|
+
/** Test/debug helper. Not part of the stable API. */
|
|
105
|
+
clearCache(): void;
|
|
106
|
+
private fetchSecurityProto;
|
|
107
|
+
private fetchPortfolioProto;
|
|
108
|
+
private batchFetchSecurities;
|
|
109
|
+
private batchFetchPortfolios;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Structural type — anything with a proto that has getSecurity/setSecurity
|
|
113
|
+
* (Price, Transaction, etc.) is resolvable.
|
|
114
|
+
*/
|
|
115
|
+
export interface ResolvableSecurity {
|
|
116
|
+
proto: {
|
|
117
|
+
getSecurity(): SecurityProto | undefined;
|
|
118
|
+
setSecurity(s: SecurityProto): unknown;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export interface ResolvablePortfolio {
|
|
122
|
+
proto: {
|
|
123
|
+
getPortfolio(): PortfolioProto | undefined;
|
|
124
|
+
setPortfolio(p: PortfolioProto): unknown;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export default LinkResolver;
|