@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
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Verifies SecurityService / PortfolioService / PriceService / TransactionService
|
|
3
|
+
// each populate LinkCache on a successful createOrUpdate. Pure unit tests —
|
|
4
|
+
// the gRPC client is replaced via Object.assign on the service instance so we
|
|
5
|
+
// never hit the wire.
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
23
|
+
if (mod && mod.__esModule) return mod;
|
|
24
|
+
var result = {};
|
|
25
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
26
|
+
__setModuleDefault(result, mod);
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
30
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
31
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
32
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
33
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
34
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
35
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
const uuid_1 = require("../models/utils/uuid");
|
|
43
|
+
const datetime_1 = require("../models/utils/datetime");
|
|
44
|
+
const local_timestamp_pb_1 = require("../../fintekkers/models/util/local_timestamp_pb");
|
|
45
|
+
const timestamp_pb_1 = require("google-protobuf/google/protobuf/timestamp_pb");
|
|
46
|
+
const security_pb_1 = require("../../fintekkers/models/security/security_pb");
|
|
47
|
+
const portfolio_pb_1 = require("../../fintekkers/models/portfolio/portfolio_pb");
|
|
48
|
+
const price_pb_1 = require("../../fintekkers/models/price/price_pb");
|
|
49
|
+
const transaction_pb_1 = require("../../fintekkers/models/transaction/transaction_pb");
|
|
50
|
+
const create_security_response_pb_1 = require("../../fintekkers/requests/security/create_security_response_pb");
|
|
51
|
+
const create_portfolio_response_pb_1 = require("../../fintekkers/requests/portfolio/create_portfolio_response_pb");
|
|
52
|
+
const create_price_response_pb_1 = require("../../fintekkers/requests/price/create_price_response_pb");
|
|
53
|
+
const create_transaction_response_pb_1 = require("../../fintekkers/requests/transaction/create_transaction_response_pb");
|
|
54
|
+
const SecurityService_1 = require("./security-service/SecurityService");
|
|
55
|
+
const PortfolioService_1 = require("./portfolio-service/PortfolioService");
|
|
56
|
+
const PriceService_1 = require("./price-service/PriceService");
|
|
57
|
+
const TransactionService_1 = require("./transaction-service/TransactionService");
|
|
58
|
+
const transaction_1 = __importDefault(require("../models/transaction/transaction"));
|
|
59
|
+
const LinkCacheModule = __importStar(require("../util/link-cache"));
|
|
60
|
+
function makeAsOf(epochSecondsOffset = 0) {
|
|
61
|
+
const ts = new timestamp_pb_1.Timestamp();
|
|
62
|
+
ts.setSeconds(1700000000 + epochSecondsOffset);
|
|
63
|
+
ts.setNanos(0);
|
|
64
|
+
const proto = new local_timestamp_pb_1.LocalTimestampProto();
|
|
65
|
+
proto.setTimestamp(ts);
|
|
66
|
+
proto.setTimeZone('UTC');
|
|
67
|
+
return proto;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Build a fake gRPC client that returns a pre-canned response on
|
|
71
|
+
* createOrUpdate. Mimics the callback shape the real grpc-js client uses,
|
|
72
|
+
* since the service wraps it with `promisify`.
|
|
73
|
+
*/
|
|
74
|
+
function fakeClient(response) {
|
|
75
|
+
return {
|
|
76
|
+
createOrUpdate(_req, cb) {
|
|
77
|
+
cb(null, response);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
LinkCacheModule.SECURITY.clear();
|
|
83
|
+
LinkCacheModule.PORTFOLIO.clear();
|
|
84
|
+
LinkCacheModule.PRICE.clear();
|
|
85
|
+
LinkCacheModule.TRANSACTION.clear();
|
|
86
|
+
});
|
|
87
|
+
test('SecurityService.createSecurity populates LinkCache.SECURITY', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
|
+
const uuid = uuid_1.UUID.random();
|
|
89
|
+
const asOf = makeAsOf(0);
|
|
90
|
+
const persisted = new security_pb_1.SecurityProto();
|
|
91
|
+
persisted.setUuid(uuid.toUUIDProto());
|
|
92
|
+
persisted.setAsOf(asOf);
|
|
93
|
+
persisted.setIssuerName('ACME');
|
|
94
|
+
const response = new create_security_response_pb_1.CreateSecurityResponseProto();
|
|
95
|
+
response.setSecurityResponse(persisted);
|
|
96
|
+
const svc = new SecurityService_1.SecurityService();
|
|
97
|
+
svc.client = fakeClient(response);
|
|
98
|
+
yield svc.createSecurity(new security_pb_1.SecurityProto());
|
|
99
|
+
const cached = LinkCacheModule.SECURITY.get(uuid.toString(), new datetime_1.ZonedDateTime(asOf));
|
|
100
|
+
expect(cached).toBeDefined();
|
|
101
|
+
expect(cached.getIssuerName()).toBe('ACME');
|
|
102
|
+
}));
|
|
103
|
+
test('PortfolioService.createPortfolio populates LinkCache.PORTFOLIO', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
104
|
+
const uuid = uuid_1.UUID.random();
|
|
105
|
+
const asOf = makeAsOf(1);
|
|
106
|
+
const persisted = new portfolio_pb_1.PortfolioProto();
|
|
107
|
+
persisted.setUuid(uuid.toUUIDProto());
|
|
108
|
+
persisted.setAsOf(asOf);
|
|
109
|
+
persisted.setPortfolioName('Strategy Z');
|
|
110
|
+
const response = new create_portfolio_response_pb_1.CreatePortfolioResponseProto();
|
|
111
|
+
response.addPortfolioResponse(persisted);
|
|
112
|
+
const svc = new PortfolioService_1.PortfolioService();
|
|
113
|
+
svc.client = fakeClient(response);
|
|
114
|
+
yield svc.createPortfolio(new portfolio_pb_1.PortfolioProto());
|
|
115
|
+
const cached = LinkCacheModule.PORTFOLIO.get(uuid.toString(), new datetime_1.ZonedDateTime(asOf));
|
|
116
|
+
expect(cached).toBeDefined();
|
|
117
|
+
expect(cached.getPortfolioName()).toBe('Strategy Z');
|
|
118
|
+
}));
|
|
119
|
+
test('PriceService.createOrUpdate populates LinkCache.PRICE', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
120
|
+
const uuid = uuid_1.UUID.random();
|
|
121
|
+
const asOf = makeAsOf(2);
|
|
122
|
+
const persisted = new price_pb_1.PriceProto();
|
|
123
|
+
persisted.setUuid(uuid.toUUIDProto());
|
|
124
|
+
persisted.setAsOf(asOf);
|
|
125
|
+
const response = new create_price_response_pb_1.CreatePriceResponseProto();
|
|
126
|
+
response.addPriceResponse(persisted);
|
|
127
|
+
const svc = new PriceService_1.PriceService();
|
|
128
|
+
svc.client = fakeClient(response);
|
|
129
|
+
yield svc.createOrUpdate(new price_pb_1.PriceProto());
|
|
130
|
+
const cached = LinkCacheModule.PRICE.get(uuid.toString(), new datetime_1.ZonedDateTime(asOf));
|
|
131
|
+
expect(cached).toBeDefined();
|
|
132
|
+
}));
|
|
133
|
+
test('TransactionService.createTransaction populates LinkCache.TRANSACTION', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
134
|
+
const uuid = uuid_1.UUID.random();
|
|
135
|
+
const asOf = makeAsOf(3);
|
|
136
|
+
const persisted = new transaction_pb_1.TransactionProto();
|
|
137
|
+
persisted.setUuid(uuid.toUUIDProto());
|
|
138
|
+
persisted.setAsOf(asOf);
|
|
139
|
+
const response = new create_transaction_response_pb_1.CreateTransactionResponseProto();
|
|
140
|
+
response.setTransactionResponse(persisted);
|
|
141
|
+
const svc = new TransactionService_1.TransactionService();
|
|
142
|
+
svc.client = fakeClient(response);
|
|
143
|
+
yield svc.createTransaction(new transaction_1.default(new transaction_pb_1.TransactionProto()));
|
|
144
|
+
const cached = LinkCacheModule.TRANSACTION.get(uuid.toString(), new datetime_1.ZonedDateTime(asOf));
|
|
145
|
+
expect(cached).toBeDefined();
|
|
146
|
+
}));
|
|
147
|
+
//# sourceMappingURL=service-client-writethrough.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-client-writethrough.test.js","sourceRoot":"","sources":["service-client-writethrough.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Verifies SecurityService / PortfolioService / PriceService / TransactionService
|
|
2
|
+
// each populate LinkCache on a successful createOrUpdate. Pure unit tests —
|
|
3
|
+
// the gRPC client is replaced via Object.assign on the service instance so we
|
|
4
|
+
// never hit the wire.
|
|
5
|
+
|
|
6
|
+
import { UUID } from '../models/utils/uuid';
|
|
7
|
+
import { ZonedDateTime } from '../models/utils/datetime';
|
|
8
|
+
import { LocalTimestampProto } from '../../fintekkers/models/util/local_timestamp_pb';
|
|
9
|
+
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
|
10
|
+
|
|
11
|
+
import { SecurityProto } from '../../fintekkers/models/security/security_pb';
|
|
12
|
+
import { PortfolioProto } from '../../fintekkers/models/portfolio/portfolio_pb';
|
|
13
|
+
import { PriceProto } from '../../fintekkers/models/price/price_pb';
|
|
14
|
+
import { TransactionProto } from '../../fintekkers/models/transaction/transaction_pb';
|
|
15
|
+
|
|
16
|
+
import { CreateSecurityResponseProto } from '../../fintekkers/requests/security/create_security_response_pb';
|
|
17
|
+
import { CreatePortfolioResponseProto } from '../../fintekkers/requests/portfolio/create_portfolio_response_pb';
|
|
18
|
+
import { CreatePriceResponseProto } from '../../fintekkers/requests/price/create_price_response_pb';
|
|
19
|
+
import { CreateTransactionResponseProto } from '../../fintekkers/requests/transaction/create_transaction_response_pb';
|
|
20
|
+
|
|
21
|
+
import { SecurityService } from './security-service/SecurityService';
|
|
22
|
+
import { PortfolioService } from './portfolio-service/PortfolioService';
|
|
23
|
+
import { PriceService } from './price-service/PriceService';
|
|
24
|
+
import { TransactionService } from './transaction-service/TransactionService';
|
|
25
|
+
import Transaction from '../models/transaction/transaction';
|
|
26
|
+
|
|
27
|
+
import * as LinkCacheModule from '../util/link-cache';
|
|
28
|
+
|
|
29
|
+
function makeAsOf(epochSecondsOffset = 0): LocalTimestampProto {
|
|
30
|
+
const ts = new Timestamp();
|
|
31
|
+
ts.setSeconds(1_700_000_000 + epochSecondsOffset);
|
|
32
|
+
ts.setNanos(0);
|
|
33
|
+
const proto = new LocalTimestampProto();
|
|
34
|
+
proto.setTimestamp(ts);
|
|
35
|
+
proto.setTimeZone('UTC');
|
|
36
|
+
return proto;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Build a fake gRPC client that returns a pre-canned response on
|
|
41
|
+
* createOrUpdate. Mimics the callback shape the real grpc-js client uses,
|
|
42
|
+
* since the service wraps it with `promisify`.
|
|
43
|
+
*/
|
|
44
|
+
function fakeClient<TRes>(response: TRes): any {
|
|
45
|
+
return {
|
|
46
|
+
createOrUpdate(_req: unknown, cb: (err: unknown, res: TRes) => void) {
|
|
47
|
+
cb(null, response);
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
LinkCacheModule.SECURITY.clear();
|
|
54
|
+
LinkCacheModule.PORTFOLIO.clear();
|
|
55
|
+
LinkCacheModule.PRICE.clear();
|
|
56
|
+
LinkCacheModule.TRANSACTION.clear();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('SecurityService.createSecurity populates LinkCache.SECURITY', async () => {
|
|
60
|
+
const uuid = UUID.random();
|
|
61
|
+
const asOf = makeAsOf(0);
|
|
62
|
+
|
|
63
|
+
const persisted = new SecurityProto();
|
|
64
|
+
persisted.setUuid(uuid.toUUIDProto());
|
|
65
|
+
persisted.setAsOf(asOf);
|
|
66
|
+
persisted.setIssuerName('ACME');
|
|
67
|
+
|
|
68
|
+
const response = new CreateSecurityResponseProto();
|
|
69
|
+
response.setSecurityResponse(persisted);
|
|
70
|
+
|
|
71
|
+
const svc = new SecurityService();
|
|
72
|
+
(svc as any).client = fakeClient(response);
|
|
73
|
+
|
|
74
|
+
await svc.createSecurity(new SecurityProto());
|
|
75
|
+
|
|
76
|
+
const cached = LinkCacheModule.SECURITY.get(uuid.toString(), new ZonedDateTime(asOf));
|
|
77
|
+
expect(cached).toBeDefined();
|
|
78
|
+
expect(cached!.getIssuerName()).toBe('ACME');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('PortfolioService.createPortfolio populates LinkCache.PORTFOLIO', async () => {
|
|
82
|
+
const uuid = UUID.random();
|
|
83
|
+
const asOf = makeAsOf(1);
|
|
84
|
+
|
|
85
|
+
const persisted = new PortfolioProto();
|
|
86
|
+
persisted.setUuid(uuid.toUUIDProto());
|
|
87
|
+
persisted.setAsOf(asOf);
|
|
88
|
+
persisted.setPortfolioName('Strategy Z');
|
|
89
|
+
|
|
90
|
+
const response = new CreatePortfolioResponseProto();
|
|
91
|
+
response.addPortfolioResponse(persisted);
|
|
92
|
+
|
|
93
|
+
const svc = new PortfolioService();
|
|
94
|
+
(svc as any).client = fakeClient(response);
|
|
95
|
+
|
|
96
|
+
await svc.createPortfolio(new PortfolioProto());
|
|
97
|
+
|
|
98
|
+
const cached = LinkCacheModule.PORTFOLIO.get(uuid.toString(), new ZonedDateTime(asOf));
|
|
99
|
+
expect(cached).toBeDefined();
|
|
100
|
+
expect(cached!.getPortfolioName()).toBe('Strategy Z');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('PriceService.createOrUpdate populates LinkCache.PRICE', async () => {
|
|
104
|
+
const uuid = UUID.random();
|
|
105
|
+
const asOf = makeAsOf(2);
|
|
106
|
+
|
|
107
|
+
const persisted = new PriceProto();
|
|
108
|
+
persisted.setUuid(uuid.toUUIDProto());
|
|
109
|
+
persisted.setAsOf(asOf);
|
|
110
|
+
|
|
111
|
+
const response = new CreatePriceResponseProto();
|
|
112
|
+
response.addPriceResponse(persisted);
|
|
113
|
+
|
|
114
|
+
const svc = new PriceService();
|
|
115
|
+
(svc as any).client = fakeClient(response);
|
|
116
|
+
|
|
117
|
+
await svc.createOrUpdate(new PriceProto());
|
|
118
|
+
|
|
119
|
+
const cached = LinkCacheModule.PRICE.get(uuid.toString(), new ZonedDateTime(asOf));
|
|
120
|
+
expect(cached).toBeDefined();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('TransactionService.createTransaction populates LinkCache.TRANSACTION', async () => {
|
|
124
|
+
const uuid = UUID.random();
|
|
125
|
+
const asOf = makeAsOf(3);
|
|
126
|
+
|
|
127
|
+
const persisted = new TransactionProto();
|
|
128
|
+
persisted.setUuid(uuid.toUUIDProto());
|
|
129
|
+
persisted.setAsOf(asOf);
|
|
130
|
+
|
|
131
|
+
const response = new CreateTransactionResponseProto();
|
|
132
|
+
response.setTransactionResponse(persisted);
|
|
133
|
+
|
|
134
|
+
const svc = new TransactionService();
|
|
135
|
+
(svc as any).client = fakeClient(response);
|
|
136
|
+
|
|
137
|
+
await svc.createTransaction(new Transaction(new TransactionProto()));
|
|
138
|
+
|
|
139
|
+
const cached = LinkCacheModule.TRANSACTION.get(uuid.toString(), new ZonedDateTime(asOf));
|
|
140
|
+
expect(cached).toBeDefined();
|
|
141
|
+
});
|
|
@@ -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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
26
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
27
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -23,6 +46,9 @@ const create_transaction_request_pb_1 = require("../../../fintekkers/requests/tr
|
|
|
23
46
|
const query_transaction_request_pb_1 = require("../../../fintekkers/requests/transaction/query_transaction_request_pb");
|
|
24
47
|
const requestcontext_1 = __importDefault(require("../../models/utils/requestcontext"));
|
|
25
48
|
const link_resolver_1 = __importDefault(require("../../util/link-resolver"));
|
|
49
|
+
const LinkCacheModule = __importStar(require("../../util/link-cache"));
|
|
50
|
+
const uuid_1 = require("../../models/utils/uuid");
|
|
51
|
+
const datetime_1 = require("../../models/utils/datetime");
|
|
26
52
|
class TransactionService {
|
|
27
53
|
constructor(apiKey) {
|
|
28
54
|
if (apiKey) {
|
|
@@ -52,6 +78,16 @@ class TransactionService {
|
|
|
52
78
|
createRequest.setCreateTransactionInput(transaction.proto);
|
|
53
79
|
const createTransactionAsync = (0, util_1.promisify)(this.client.createOrUpdate.bind(this.client));
|
|
54
80
|
const response = yield createTransactionAsync(createRequest);
|
|
81
|
+
// Write-through to LinkCache. transactionResponse is a singular field.
|
|
82
|
+
const persisted = response.getTransactionResponse();
|
|
83
|
+
if (persisted) {
|
|
84
|
+
const uuidProto = persisted.getUuid();
|
|
85
|
+
const asOfProto = persisted.getAsOf();
|
|
86
|
+
if (uuidProto && asOfProto) {
|
|
87
|
+
const uuidKey = uuid_1.UUID.fromU8Array(uuidProto.getRawUuid_asU8()).toString();
|
|
88
|
+
LinkCacheModule.TRANSACTION.put(uuidKey, persisted, new datetime_1.ZonedDateTime(asOfProto));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
55
91
|
return response;
|
|
56
92
|
});
|
|
57
93
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionService.js","sourceRoot":"","sources":["TransactionService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TransactionService.js","sourceRoot":"","sources":["TransactionService.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,9 @@ import { QueryTransactionRequestProto } from '../../../fintekkers/requests/trans
|
|
|
16
16
|
import { QueryTransactionResponseProto } from '../../../fintekkers/requests/transaction/query_transaction_response_pb';
|
|
17
17
|
import EnvConfig from '../../models/utils/requestcontext';
|
|
18
18
|
import LinkResolver from '../../util/link-resolver';
|
|
19
|
+
import * as LinkCacheModule from '../../util/link-cache';
|
|
20
|
+
import { UUID } from '../../models/utils/uuid';
|
|
21
|
+
import { ZonedDateTime } from '../../models/utils/datetime';
|
|
19
22
|
|
|
20
23
|
|
|
21
24
|
class TransactionService {
|
|
@@ -49,6 +52,16 @@ class TransactionService {
|
|
|
49
52
|
|
|
50
53
|
const createTransactionAsync = promisify(this.client.createOrUpdate.bind(this.client));
|
|
51
54
|
const response = await createTransactionAsync(createRequest) as CreateTransactionResponseProto;
|
|
55
|
+
// Write-through to LinkCache. transactionResponse is a singular field.
|
|
56
|
+
const persisted = response.getTransactionResponse();
|
|
57
|
+
if (persisted) {
|
|
58
|
+
const uuidProto = persisted.getUuid();
|
|
59
|
+
const asOfProto = persisted.getAsOf();
|
|
60
|
+
if (uuidProto && asOfProto) {
|
|
61
|
+
const uuidKey = UUID.fromU8Array(uuidProto.getRawUuid_asU8()).toString();
|
|
62
|
+
LinkCacheModule.TRANSACTION.put(uuidKey, persisted, new ZonedDateTime(asOfProto));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
52
65
|
return response;
|
|
53
66
|
}
|
|
54
67
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { SecurityProto } from '../../fintekkers/models/security/security_pb';
|
|
2
|
+
import { PortfolioProto } from '../../fintekkers/models/portfolio/portfolio_pb';
|
|
3
|
+
import { PriceProto } from '../../fintekkers/models/price/price_pb';
|
|
4
|
+
import { TransactionProto } from '../../fintekkers/models/transaction/transaction_pb';
|
|
5
|
+
import { ZonedDateTime } from '../models/utils/datetime';
|
|
6
|
+
/**
|
|
7
|
+
* LinkCache — process-wide cache of resolved proto bodies backing link-mode
|
|
8
|
+
* wrappers. TypeScript mirror of `common.util.LinkCache` (Java) and
|
|
9
|
+
* `fintekkers.wrappers.util.link_cache` (Python). See
|
|
10
|
+
* `docs/adr/lazy-link-hydration.md`.
|
|
11
|
+
*
|
|
12
|
+
* Read semantics (`get`):
|
|
13
|
+
* - `requestedAsOf == null` ("latest acceptable") — cache hit allowed;
|
|
14
|
+
* subject to `ttlForLatestMs` to bound cross-process staleness this
|
|
15
|
+
* process can't observe. Past TTL ⇒ miss.
|
|
16
|
+
* - `requestedAsOf != null` (bitemporal-precise) — cache hit only when the
|
|
17
|
+
* cached entry's asOf equals the requested. No TTL — history doesn't
|
|
18
|
+
* change, so a past vintage cached arbitrarily long is fine.
|
|
19
|
+
*
|
|
20
|
+
* Write semantics (`put`): newest-vintage wins. An older-vintage put does
|
|
21
|
+
* not evict a newer cached entry.
|
|
22
|
+
*
|
|
23
|
+
* Later Portfolio can likely be 1 day, security 1 day, transaction 1 minute,
|
|
24
|
+
* price 30 seconds — once per-entity TTLs are wired up, the shared singletons
|
|
25
|
+
* below should be constructed with those values.
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEFAULT_TTL_FOR_LATEST_MS = 600000;
|
|
28
|
+
export declare class LinkCache<V> {
|
|
29
|
+
private ttlForLatestMs;
|
|
30
|
+
private map;
|
|
31
|
+
constructor(ttlForLatestMs?: number);
|
|
32
|
+
/**
|
|
33
|
+
* @param uuidKey the entity uuid rendered as a stable string key
|
|
34
|
+
* (use uuid.toString())
|
|
35
|
+
* @param requestedAsOf null = "latest acceptable" (TTL-bounded);
|
|
36
|
+
* non-null = exact-vintage match required (no TTL)
|
|
37
|
+
* @returns the cached value if the lookup is a hit; otherwise undefined
|
|
38
|
+
* (caller must refetch)
|
|
39
|
+
*/
|
|
40
|
+
get(uuidKey: string, requestedAsOf: ZonedDateTime | null): V | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Newest-wins write: if a cached entry for `uuidKey` already exists with
|
|
43
|
+
* an asOf strictly after the incoming asOf, the write is ignored.
|
|
44
|
+
*/
|
|
45
|
+
put(uuidKey: string, value: V, asOf: ZonedDateTime): void;
|
|
46
|
+
evict(uuidKey: string): void;
|
|
47
|
+
clear(): void;
|
|
48
|
+
/** Test helper. */
|
|
49
|
+
size(): number;
|
|
50
|
+
private _sameAsOf;
|
|
51
|
+
private _isStrictlyAfter;
|
|
52
|
+
}
|
|
53
|
+
export declare const SECURITY: LinkCache<SecurityProto>;
|
|
54
|
+
export declare const PORTFOLIO: LinkCache<PortfolioProto>;
|
|
55
|
+
export declare const PRICE: LinkCache<PriceProto>;
|
|
56
|
+
export declare const TRANSACTION: LinkCache<TransactionProto>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TRANSACTION = exports.PRICE = exports.PORTFOLIO = exports.SECURITY = exports.LinkCache = exports.DEFAULT_TTL_FOR_LATEST_MS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* LinkCache — process-wide cache of resolved proto bodies backing link-mode
|
|
6
|
+
* wrappers. TypeScript mirror of `common.util.LinkCache` (Java) and
|
|
7
|
+
* `fintekkers.wrappers.util.link_cache` (Python). See
|
|
8
|
+
* `docs/adr/lazy-link-hydration.md`.
|
|
9
|
+
*
|
|
10
|
+
* Read semantics (`get`):
|
|
11
|
+
* - `requestedAsOf == null` ("latest acceptable") — cache hit allowed;
|
|
12
|
+
* subject to `ttlForLatestMs` to bound cross-process staleness this
|
|
13
|
+
* process can't observe. Past TTL ⇒ miss.
|
|
14
|
+
* - `requestedAsOf != null` (bitemporal-precise) — cache hit only when the
|
|
15
|
+
* cached entry's asOf equals the requested. No TTL — history doesn't
|
|
16
|
+
* change, so a past vintage cached arbitrarily long is fine.
|
|
17
|
+
*
|
|
18
|
+
* Write semantics (`put`): newest-vintage wins. An older-vintage put does
|
|
19
|
+
* not evict a newer cached entry.
|
|
20
|
+
*
|
|
21
|
+
* Later Portfolio can likely be 1 day, security 1 day, transaction 1 minute,
|
|
22
|
+
* price 30 seconds — once per-entity TTLs are wired up, the shared singletons
|
|
23
|
+
* below should be constructed with those values.
|
|
24
|
+
*/
|
|
25
|
+
exports.DEFAULT_TTL_FOR_LATEST_MS = 600000;
|
|
26
|
+
class LinkCache {
|
|
27
|
+
constructor(ttlForLatestMs = exports.DEFAULT_TTL_FOR_LATEST_MS) {
|
|
28
|
+
this.ttlForLatestMs = ttlForLatestMs;
|
|
29
|
+
this.map = new Map();
|
|
30
|
+
if (ttlForLatestMs < 0) {
|
|
31
|
+
throw new Error(`ttlForLatestMs must be non-negative; got ${ttlForLatestMs}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @param uuidKey the entity uuid rendered as a stable string key
|
|
36
|
+
* (use uuid.toString())
|
|
37
|
+
* @param requestedAsOf null = "latest acceptable" (TTL-bounded);
|
|
38
|
+
* non-null = exact-vintage match required (no TTL)
|
|
39
|
+
* @returns the cached value if the lookup is a hit; otherwise undefined
|
|
40
|
+
* (caller must refetch)
|
|
41
|
+
*/
|
|
42
|
+
get(uuidKey, requestedAsOf) {
|
|
43
|
+
const entry = this.map.get(uuidKey);
|
|
44
|
+
if (!entry)
|
|
45
|
+
return undefined;
|
|
46
|
+
if (requestedAsOf == null) {
|
|
47
|
+
if (Date.now() - entry.cachedAtMs > this.ttlForLatestMs) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return entry.value;
|
|
51
|
+
}
|
|
52
|
+
return this._sameAsOf(entry.asOf, requestedAsOf) ? entry.value : undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Newest-wins write: if a cached entry for `uuidKey` already exists with
|
|
56
|
+
* an asOf strictly after the incoming asOf, the write is ignored.
|
|
57
|
+
*/
|
|
58
|
+
put(uuidKey, value, asOf) {
|
|
59
|
+
if (!uuidKey || !value || !asOf) {
|
|
60
|
+
throw new Error(`uuidKey / value / asOf must all be set; got uuidKey=${uuidKey} value=${value ? '<non-null>' : 'null'} asOf=${asOf}`);
|
|
61
|
+
}
|
|
62
|
+
const existing = this.map.get(uuidKey);
|
|
63
|
+
if (existing && this._isStrictlyAfter(existing.asOf, asOf)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.map.set(uuidKey, { value, asOf, cachedAtMs: Date.now() });
|
|
67
|
+
}
|
|
68
|
+
evict(uuidKey) {
|
|
69
|
+
this.map.delete(uuidKey);
|
|
70
|
+
}
|
|
71
|
+
clear() {
|
|
72
|
+
this.map.clear();
|
|
73
|
+
}
|
|
74
|
+
/** Test helper. */
|
|
75
|
+
size() {
|
|
76
|
+
return this.map.size;
|
|
77
|
+
}
|
|
78
|
+
_sameAsOf(a, b) {
|
|
79
|
+
return a.getSeconds() === b.getSeconds() && a.getNanoSeconds() === b.getNanoSeconds();
|
|
80
|
+
}
|
|
81
|
+
_isStrictlyAfter(a, b) {
|
|
82
|
+
if (a.getSeconds() !== b.getSeconds())
|
|
83
|
+
return a.getSeconds() > b.getSeconds();
|
|
84
|
+
return a.getNanoSeconds() > b.getNanoSeconds();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.LinkCache = LinkCache;
|
|
88
|
+
exports.SECURITY = new LinkCache();
|
|
89
|
+
exports.PORTFOLIO = new LinkCache();
|
|
90
|
+
exports.PRICE = new LinkCache();
|
|
91
|
+
exports.TRANSACTION = new LinkCache();
|
|
92
|
+
//# sourceMappingURL=link-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-cache.js","sourceRoot":"","sources":["link-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|