@fintekkers/ledger-models 0.1.132 → 0.1.134
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/security/asset_class_grpc_pb.js +1 -0
- package/node/fintekkers/models/security/asset_class_pb.d.ts +15 -0
- package/node/fintekkers/models/security/asset_class_pb.js +36 -0
- package/node/fintekkers/models/security/security_pb.d.ts +6 -0
- package/node/fintekkers/models/security/security_pb.js +51 -0
- package/node/fintekkers/requests/price/query_price_request_pb.d.ts +3 -0
- package/node/fintekkers/requests/price/query_price_request_pb.js +31 -1
- package/node/fintekkers/requests/price/query_price_response_pb.d.ts +7 -0
- package/node/fintekkers/requests/price/query_price_response_pb.js +54 -1
- package/node/wrappers/models/security/BondSecurity.d.ts +8 -0
- package/node/wrappers/models/security/BondSecurity.js +13 -0
- package/node/wrappers/models/security/BondSecurity.js.map +1 -1
- package/node/wrappers/models/security/BondSecurity.ts +13 -0
- package/node/wrappers/models/security/asset_class.d.ts +37 -0
- package/node/wrappers/models/security/asset_class.js +51 -0
- package/node/wrappers/models/security/asset_class.js.map +1 -0
- package/node/wrappers/models/security/asset_class.test.d.ts +1 -0
- package/node/wrappers/models/security/asset_class.test.js +52 -0
- package/node/wrappers/models/security/asset_class.test.js.map +1 -0
- package/node/wrappers/models/security/asset_class.test.ts +58 -0
- package/node/wrappers/models/security/asset_class.ts +53 -0
- package/node/wrappers/models/security/identifier.d.ts +26 -0
- package/node/wrappers/models/security/identifier.js +39 -0
- package/node/wrappers/models/security/identifier.js.map +1 -1
- package/node/wrappers/models/security/identifier.test.js +62 -0
- package/node/wrappers/models/security/identifier.test.js.map +1 -1
- package/node/wrappers/models/security/identifier.test.ts +70 -0
- package/node/wrappers/models/security/identifier.ts +44 -0
- package/node/wrappers/models/security/security.d.ts +36 -1
- package/node/wrappers/models/security/security.js +45 -2
- package/node/wrappers/models/security/security.js.map +1 -1
- package/node/wrappers/models/security/security.test.js +72 -0
- package/node/wrappers/models/security/security.test.js.map +1 -1
- package/node/wrappers/models/security/security.test.ts +80 -0
- package/node/wrappers/models/security/security.ts +47 -3
- package/node/wrappers/models/security/security_type.d.ts +31 -0
- package/node/wrappers/models/security/security_type.js +45 -0
- package/node/wrappers/models/security/security_type.js.map +1 -0
- package/node/wrappers/models/security/security_type.test.d.ts +1 -0
- package/node/wrappers/models/security/security_type.test.js +64 -0
- package/node/wrappers/models/security/security_type.test.js.map +1 -0
- package/node/wrappers/models/security/security_type.test.ts +70 -0
- package/node/wrappers/models/security/security_type.ts +47 -0
- package/package.json +1 -1
|
@@ -3,9 +3,11 @@ import { UUID } from '../utils/uuid';
|
|
|
3
3
|
|
|
4
4
|
import assert = require('assert');
|
|
5
5
|
import Security from './security';
|
|
6
|
+
import BondSecurity from './BondSecurity';
|
|
6
7
|
|
|
7
8
|
import { DecimalValueProto } from '../../../fintekkers/models/util/decimal_value_pb';
|
|
8
9
|
import { SecurityProto } from '../../../fintekkers/models/security/security_pb';
|
|
10
|
+
import { SecurityTypeProto } from '../../../fintekkers/models/security/security_type_pb';
|
|
9
11
|
import { CouponFrequencyProto } from '../../../fintekkers/models/security/coupon_frequency_pb';
|
|
10
12
|
import { CouponTypeProto } from '../../../fintekkers/models/security/coupon_type_pb';
|
|
11
13
|
import { SecurityQuantityTypeProto } from '../../../fintekkers/models/security/security_quantity_type_pb';
|
|
@@ -21,6 +23,52 @@ function testSerialization(): void {
|
|
|
21
23
|
assert(security.getMaturityDate().toDate().getFullYear() == 2026);
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
test('equity routes to base Security and isBond() returns false', () => {
|
|
27
|
+
const equity = dummyEquity();
|
|
28
|
+
expect(equity).toBeInstanceOf(Security);
|
|
29
|
+
expect(equity).not.toBeInstanceOf(BondSecurity);
|
|
30
|
+
expect(equity.isBond()).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('bond routes to BondSecurity and isBond() returns true (narrows type)', () => {
|
|
34
|
+
const bond = dummyBondSecurity();
|
|
35
|
+
expect(bond.isBond()).toBe(true);
|
|
36
|
+
if (bond.isBond()) {
|
|
37
|
+
// Inside the narrowed branch TS knows bond: BondSecurity.
|
|
38
|
+
// Calling a BondSecurity-only method here proves the narrowing works.
|
|
39
|
+
expect(bond.getCouponRate()).toBeDefined();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('Security.getIssueDate returns null on equity (no throw)', () => {
|
|
44
|
+
const equity = dummyEquity();
|
|
45
|
+
// Phase 1 behavior change: was throw "Issue date is required", now returns null.
|
|
46
|
+
// This is the symptom fix that motivated #205 — equity wrappers no longer
|
|
47
|
+
// explode on per-record post-processing in ui-service.
|
|
48
|
+
expect(equity.getIssueDate()).toBeNull();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('BondSecurity.getIssueDate returns LocalDate (non-nullable) on bond', () => {
|
|
52
|
+
const bond = dummyBondSecurity();
|
|
53
|
+
if (!bond.isBond()) throw new Error('test setup: expected bond');
|
|
54
|
+
const issueDate = bond.getIssueDate();
|
|
55
|
+
expect(issueDate).not.toBeNull();
|
|
56
|
+
expect(issueDate.toDate().getFullYear()).toBe(2021);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('Security.getMaturityDate still throws on equity (Phase 1 deprecation, not removal)', () => {
|
|
60
|
+
const equity = dummyEquity();
|
|
61
|
+
// Behavior preserved deliberately for Phase 1 — callers still get a
|
|
62
|
+
// loud error if they don't narrow first. Removal happens in Phase 2.
|
|
63
|
+
expect(() => equity.getMaturityDate()).toThrow('Maturity date is required');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('BondSecurity.getMaturityDate works on bond (inherited from Security)', () => {
|
|
67
|
+
const bond = dummyBondSecurity();
|
|
68
|
+
if (!bond.isBond()) throw new Error('test setup: expected bond');
|
|
69
|
+
expect(bond.getMaturityDate().toDate().getFullYear()).toBe(2026);
|
|
70
|
+
});
|
|
71
|
+
|
|
24
72
|
function dummySecurity() {
|
|
25
73
|
return Security.create(new SecurityProto()
|
|
26
74
|
.setObjectClass('Transaction').setVersion('0.0.1').setUuid(UUID.random().toUUIDProto())
|
|
@@ -39,3 +87,35 @@ function dummySecurity() {
|
|
|
39
87
|
);
|
|
40
88
|
}
|
|
41
89
|
|
|
90
|
+
function dummyBondSecurity() {
|
|
91
|
+
// Same dummy security but with securityType set so the factory routes
|
|
92
|
+
// to BondSecurity.
|
|
93
|
+
return Security.create(new SecurityProto()
|
|
94
|
+
.setObjectClass('Security').setVersion('0.0.1').setUuid(UUID.random().toUUIDProto())
|
|
95
|
+
.setSecurityType(SecurityTypeProto.BOND_SECURITY)
|
|
96
|
+
.setFaceValue(new DecimalValueProto().setArbitraryPrecisionValue('1000.00'))
|
|
97
|
+
.setQuantityType(SecurityQuantityTypeProto.ORIGINAL_FACE_VALUE)
|
|
98
|
+
.setAssetClass("Bond")
|
|
99
|
+
.setIssuerName("Dummy issuer")
|
|
100
|
+
.setCouponRate(new DecimalValueProto().setArbitraryPrecisionValue('0.05'))
|
|
101
|
+
.setCouponFrequency(CouponFrequencyProto.SEMIANNUALLY)
|
|
102
|
+
.setCouponType(CouponTypeProto.FIXED)
|
|
103
|
+
.setMaturityDate(new LocalDateProto().setYear(2026).setMonth(1).setDay(1))
|
|
104
|
+
.setIssueDate(new LocalDateProto().setYear(2021).setMonth(1).setDay(1))
|
|
105
|
+
.setDescription("Dummy bond")
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function dummyEquity() {
|
|
110
|
+
// Equity has no maturity / issue date in the proto, exercising the
|
|
111
|
+
// null-return behavior on getIssueDate and the throw-on-missing
|
|
112
|
+
// behavior on getMaturityDate.
|
|
113
|
+
return Security.create(new SecurityProto()
|
|
114
|
+
.setObjectClass('Security').setVersion('0.0.1').setUuid(UUID.random().toUUIDProto())
|
|
115
|
+
.setSecurityType(SecurityTypeProto.EQUITY_SECURITY)
|
|
116
|
+
.setAssetClass("Equity")
|
|
117
|
+
.setIssuerName("Dummy issuer Inc.")
|
|
118
|
+
.setDescription("Dummy equity")
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
@@ -29,6 +29,25 @@ class Security {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Type guard: true iff this Security is a BondSecurity (BOND_SECURITY,
|
|
34
|
+
* TIPS, or FRN). Use to narrow before calling bond-specific getters:
|
|
35
|
+
*
|
|
36
|
+
* if (sec.isBond()) {
|
|
37
|
+
* // sec: BondSecurity here — TS knows about getCouponRate(), etc.
|
|
38
|
+
* console.log(sec.getMaturityDate());
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* Implemented as a runtime check on the proto's securityType so it
|
|
42
|
+
* works regardless of how the wrapper was constructed.
|
|
43
|
+
*/
|
|
44
|
+
isBond(): this is import('./BondSecurity').default {
|
|
45
|
+
const t = this.proto.getSecurityType();
|
|
46
|
+
return t === SecurityTypeProto.BOND_SECURITY
|
|
47
|
+
|| t === SecurityTypeProto.TIPS
|
|
48
|
+
|| t === SecurityTypeProto.FRN;
|
|
49
|
+
}
|
|
50
|
+
|
|
32
51
|
|
|
33
52
|
toString(): string {
|
|
34
53
|
return `ID[${this.getID().toString()}], ${this.getSecurityID()}[${this.getIssuerName()}]`;
|
|
@@ -57,8 +76,11 @@ class Security {
|
|
|
57
76
|
case FieldProto.ADJUSTED_TENOR:
|
|
58
77
|
throw new Error('Not implemented yet');
|
|
59
78
|
case FieldProto.MATURITY_DATE:
|
|
60
|
-
|
|
79
|
+
// Maturity date is bond-only. Mirror Java's Security.getField:
|
|
80
|
+
// delegate to BondSecurity, return null for non-bonds.
|
|
81
|
+
return this.isBond() ? this.getMaturityDate() : null;
|
|
61
82
|
case FieldProto.ISSUE_DATE:
|
|
83
|
+
// getIssueDate already returns null on non-bonds; just forward.
|
|
62
84
|
return this.getIssueDate();
|
|
63
85
|
default:
|
|
64
86
|
throw new Error(`Field not mapped in Security wrapper: ${field}`);
|
|
@@ -109,14 +131,36 @@ class Security {
|
|
|
109
131
|
return identifier;
|
|
110
132
|
}
|
|
111
133
|
|
|
112
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Returns the issue date if set, else null. Per-type semantic:
|
|
136
|
+
* - Bond / TIPS / FRN: auction date.
|
|
137
|
+
* - Equity: IPO listing date (when present in source data).
|
|
138
|
+
* - CPI series: first observation date.
|
|
139
|
+
* - Cash / FX: typically null.
|
|
140
|
+
*
|
|
141
|
+
* Returns null on equities/cash/etc. that don't have an issue date set,
|
|
142
|
+
* rather than throwing — issue date is optional on the base Security.
|
|
143
|
+
* For bond-specific code paths, prefer narrowing first via isBond() and
|
|
144
|
+
* calling BondSecurity.getIssueDate() (which returns LocalDate, not null).
|
|
145
|
+
*/
|
|
146
|
+
getIssueDate(): LocalDate | null {
|
|
113
147
|
// Prefer oneof bond sub-message if available, fall back to flat fields
|
|
114
148
|
const bond = this.getBondLikeDetails();
|
|
115
149
|
const date = bond ? bond.getIssueDate() : this.proto.getIssueDate();
|
|
116
|
-
if (!date)
|
|
150
|
+
if (!date) return null;
|
|
117
151
|
return new LocalDate(date);
|
|
118
152
|
}
|
|
119
153
|
|
|
154
|
+
/**
|
|
155
|
+
* @deprecated Maturity date is a bond-only concept. On the base Security
|
|
156
|
+
* this still throws when unset for backwards compatibility. Prefer
|
|
157
|
+
* narrowing first:
|
|
158
|
+
*
|
|
159
|
+
* if (sec.isBond()) sec.getMaturityDate(); // BondSecurity, returns LocalDate
|
|
160
|
+
*
|
|
161
|
+
* In a future major version this method will move to BondSecurity only
|
|
162
|
+
* and TS will catch the misuse at compile time.
|
|
163
|
+
*/
|
|
120
164
|
getMaturityDate(): LocalDate {
|
|
121
165
|
// Prefer oneof bond sub-message if available, fall back to flat fields
|
|
122
166
|
const bond = this.getBondLikeDetails();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SecurityTypeProto } from '../../../fintekkers/models/security/security_type_pb';
|
|
2
|
+
/**
|
|
3
|
+
* Static helpers around the SecurityType proto enum, mirroring the
|
|
4
|
+
* Identifier wrapper pattern shipped in v0.1.133 (PR #188).
|
|
5
|
+
*
|
|
6
|
+
* Lets TS/JS consumers stop hand-typing literal unions and switch
|
|
7
|
+
* statements over `'BOND_SECURITY' | 'TIPS' | 'FRN' | ...` — adding a
|
|
8
|
+
* new variant on the proto side propagates automatically.
|
|
9
|
+
*/
|
|
10
|
+
export declare class SecurityType {
|
|
11
|
+
/**
|
|
12
|
+
* Returns the names of all known SecurityTypeProto values, EXCLUDING
|
|
13
|
+
* the sentinel `UNKNOWN_SECURITY_TYPE`. Drives UI dropdowns / pickers
|
|
14
|
+
* so a new proto enum variant auto-propagates to consumers without
|
|
15
|
+
* any UI-side code change.
|
|
16
|
+
*
|
|
17
|
+
* Order matches proto declaration order (Object.keys preserves
|
|
18
|
+
* insertion order on the generated JS enum object).
|
|
19
|
+
*/
|
|
20
|
+
static getAllTypeNames(): string[];
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a proto enum NAME (e.g., "BOND_SECURITY", "EQUITY_SECURITY")
|
|
23
|
+
* to its numeric SecurityTypeProto value. Throws on unknown name; the
|
|
24
|
+
* error lists the valid names so typos are fixable without grepping
|
|
25
|
+
* the proto.
|
|
26
|
+
*
|
|
27
|
+
* @param name proto enum key (e.g., "BOND_SECURITY")
|
|
28
|
+
* @returns the numeric SecurityTypeProto value
|
|
29
|
+
*/
|
|
30
|
+
static fromName(name: string): SecurityTypeProto;
|
|
31
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SecurityType = void 0;
|
|
4
|
+
const security_type_pb_1 = require("../../../fintekkers/models/security/security_type_pb");
|
|
5
|
+
/**
|
|
6
|
+
* Static helpers around the SecurityType proto enum, mirroring the
|
|
7
|
+
* Identifier wrapper pattern shipped in v0.1.133 (PR #188).
|
|
8
|
+
*
|
|
9
|
+
* Lets TS/JS consumers stop hand-typing literal unions and switch
|
|
10
|
+
* statements over `'BOND_SECURITY' | 'TIPS' | 'FRN' | ...` — adding a
|
|
11
|
+
* new variant on the proto side propagates automatically.
|
|
12
|
+
*/
|
|
13
|
+
class SecurityType {
|
|
14
|
+
/**
|
|
15
|
+
* Returns the names of all known SecurityTypeProto values, EXCLUDING
|
|
16
|
+
* the sentinel `UNKNOWN_SECURITY_TYPE`. Drives UI dropdowns / pickers
|
|
17
|
+
* so a new proto enum variant auto-propagates to consumers without
|
|
18
|
+
* any UI-side code change.
|
|
19
|
+
*
|
|
20
|
+
* Order matches proto declaration order (Object.keys preserves
|
|
21
|
+
* insertion order on the generated JS enum object).
|
|
22
|
+
*/
|
|
23
|
+
static getAllTypeNames() {
|
|
24
|
+
return Object.keys(security_type_pb_1.SecurityTypeProto).filter(k => k !== 'UNKNOWN_SECURITY_TYPE');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a proto enum NAME (e.g., "BOND_SECURITY", "EQUITY_SECURITY")
|
|
28
|
+
* to its numeric SecurityTypeProto value. Throws on unknown name; the
|
|
29
|
+
* error lists the valid names so typos are fixable without grepping
|
|
30
|
+
* the proto.
|
|
31
|
+
*
|
|
32
|
+
* @param name proto enum key (e.g., "BOND_SECURITY")
|
|
33
|
+
* @returns the numeric SecurityTypeProto value
|
|
34
|
+
*/
|
|
35
|
+
static fromName(name) {
|
|
36
|
+
const enumObj = security_type_pb_1.SecurityTypeProto;
|
|
37
|
+
const enumValue = enumObj[name];
|
|
38
|
+
if (enumValue === undefined) {
|
|
39
|
+
throw new Error(`Unknown SecurityType name: '${name}'. Valid names: ${SecurityType.getAllTypeNames().join(', ')}`);
|
|
40
|
+
}
|
|
41
|
+
return enumValue;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.SecurityType = SecurityType;
|
|
45
|
+
//# sourceMappingURL=security_type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security_type.js","sourceRoot":"","sources":["security_type.ts"],"names":[],"mappings":";;;AAAA,2FAAyF;AAEzF;;;;;;;GAOG;AACH,MAAa,YAAY;IAErB;;;;;;;;OAQG;IACH,MAAM,CAAC,eAAe;QAClB,OAAO,MAAM,CAAC,IAAI,CAAC,oCAAiB,CAAC,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,uBAAuB,CACrC,CAAC;IACN,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAY;QACxB,MAAM,OAAO,GAAG,oCAAsD,CAAC;QACvE,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,SAAS,KAAK,SAAS,EAAE;YACzB,MAAM,IAAI,KAAK,CACX,+BAA+B,IAAI,mBAAmB,YAAY,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACpG,CAAC;SACL;QACD,OAAO,SAA8B,CAAC;IAC1C,CAAC;CACJ;AApCD,oCAoCC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const security_type_1 = require("./security_type");
|
|
4
|
+
const security_type_pb_1 = require("../../../fintekkers/models/security/security_type_pb");
|
|
5
|
+
describe('SecurityType.fromName', () => {
|
|
6
|
+
// Round-trip: every name returned by getAllTypeNames must resolve to
|
|
7
|
+
// a numeric enum value that maps back to the same name.
|
|
8
|
+
test.each(security_type_1.SecurityType.getAllTypeNames())('fromName("%s") returns the matching numeric enum value', (name) => {
|
|
9
|
+
const value = security_type_1.SecurityType.fromName(name);
|
|
10
|
+
// The proto-generated enum is bidirectionally indexable
|
|
11
|
+
// (Object.keys / numeric-key lookups both work in google-protobuf JS).
|
|
12
|
+
const expected = security_type_pb_1.SecurityTypeProto[name];
|
|
13
|
+
expect(value).toBe(expected);
|
|
14
|
+
});
|
|
15
|
+
test('throws on unknown name and lists valid names in the error', () => {
|
|
16
|
+
let err;
|
|
17
|
+
try {
|
|
18
|
+
security_type_1.SecurityType.fromName('NOT_A_REAL_TYPE');
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
err = e;
|
|
22
|
+
}
|
|
23
|
+
expect(err).toBeDefined();
|
|
24
|
+
expect(err.message).toContain('NOT_A_REAL_TYPE');
|
|
25
|
+
// Error message should hint with known valid entries.
|
|
26
|
+
expect(err.message).toContain('BOND_SECURITY');
|
|
27
|
+
expect(err.message).toContain('EQUITY_SECURITY');
|
|
28
|
+
});
|
|
29
|
+
test('accepts UNKNOWN_SECURITY_TYPE — sentinel is a valid enum key', () => {
|
|
30
|
+
// It's excluded from getAllTypeNames (so it doesn't appear in
|
|
31
|
+
// dropdowns), but it IS a valid proto enum value, so fromName
|
|
32
|
+
// accepts it. Pinning the existing behavior — flip if policy
|
|
33
|
+
// ever tightens.
|
|
34
|
+
expect(security_type_1.SecurityType.fromName('UNKNOWN_SECURITY_TYPE')).toBe(security_type_pb_1.SecurityTypeProto.UNKNOWN_SECURITY_TYPE);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe('SecurityType.getAllTypeNames', () => {
|
|
38
|
+
test('returns the expected set in proto-declaration order, excluding UNKNOWN', () => {
|
|
39
|
+
// Proto-declared order in security_type.proto:
|
|
40
|
+
// UNKNOWN_SECURITY_TYPE = 0; (excluded)
|
|
41
|
+
// CASH_SECURITY = 1;
|
|
42
|
+
// EQUITY_SECURITY = 2;
|
|
43
|
+
// BOND_SECURITY = 3;
|
|
44
|
+
// TIPS = 4;
|
|
45
|
+
// FRN = 5;
|
|
46
|
+
// INDEX_SECURITY = 6;
|
|
47
|
+
// FX_SPOT = 7;
|
|
48
|
+
// EQUITY_INDEX_SECURITY = 8;
|
|
49
|
+
expect(security_type_1.SecurityType.getAllTypeNames()).toEqual([
|
|
50
|
+
'CASH_SECURITY',
|
|
51
|
+
'EQUITY_SECURITY',
|
|
52
|
+
'BOND_SECURITY',
|
|
53
|
+
'TIPS',
|
|
54
|
+
'FRN',
|
|
55
|
+
'INDEX_SECURITY',
|
|
56
|
+
'FX_SPOT',
|
|
57
|
+
'EQUITY_INDEX_SECURITY',
|
|
58
|
+
]);
|
|
59
|
+
});
|
|
60
|
+
test('excludes the UNKNOWN_SECURITY_TYPE sentinel', () => {
|
|
61
|
+
expect(security_type_1.SecurityType.getAllTypeNames()).not.toContain('UNKNOWN_SECURITY_TYPE');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=security_type.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security_type.test.js","sourceRoot":"","sources":["security_type.test.ts"],"names":[],"mappings":";;AAAA,mDAA+C;AAC/C,2FAAyF;AAEzF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACnC,qEAAqE;IACrE,wDAAwD;IACxD,IAAI,CAAC,IAAI,CAAC,4BAAY,CAAC,eAAe,EAAE,CAAC,CACrC,wDAAwD,EACxD,CAAC,IAAY,EAAE,EAAE;QACb,MAAM,KAAK,GAAG,4BAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1C,wDAAwD;QACxD,uEAAuE;QACvE,MAAM,QAAQ,GAAI,oCAAuD,CAAC,IAAI,CAAC,CAAC;QAChF,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC,CACJ,CAAC;IAEF,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,IAAI,GAAsB,CAAC;QAC3B,IAAI;YACA,4BAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;SAC5C;QAAC,OAAO,CAAC,EAAE;YACR,GAAG,GAAG,CAAU,CAAC;SACpB;QACD,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAClD,sDAAsD;QACtD,MAAM,CAAC,GAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAChD,MAAM,CAAC,GAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,8DAA8D;QAC9D,8DAA8D;QAC9D,6DAA6D;QAC7D,iBAAiB;QACjB,MAAM,CAAC,4BAAY,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CACvD,oCAAiB,CAAC,qBAAqB,CAC1C,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC1C,IAAI,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,+CAA+C;QAC/C,2CAA2C;QAC3C,uBAAuB;QACvB,yBAAyB;QACzB,uBAAuB;QACvB,cAAc;QACd,aAAa;QACb,wBAAwB;QACxB,iBAAiB;QACjB,+BAA+B;QAC/B,MAAM,CAAC,4BAAY,CAAC,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC;YAC3C,eAAe;YACf,iBAAiB;YACjB,eAAe;YACf,MAAM;YACN,KAAK;YACL,gBAAgB;YAChB,SAAS;YACT,uBAAuB;SAC1B,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,4BAAY,CAAC,eAAe,EAAE,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { SecurityType } from './security_type';
|
|
2
|
+
import { SecurityTypeProto } from '../../../fintekkers/models/security/security_type_pb';
|
|
3
|
+
|
|
4
|
+
describe('SecurityType.fromName', () => {
|
|
5
|
+
// Round-trip: every name returned by getAllTypeNames must resolve to
|
|
6
|
+
// a numeric enum value that maps back to the same name.
|
|
7
|
+
test.each(SecurityType.getAllTypeNames())(
|
|
8
|
+
'fromName("%s") returns the matching numeric enum value',
|
|
9
|
+
(name: string) => {
|
|
10
|
+
const value = SecurityType.fromName(name);
|
|
11
|
+
// The proto-generated enum is bidirectionally indexable
|
|
12
|
+
// (Object.keys / numeric-key lookups both work in google-protobuf JS).
|
|
13
|
+
const expected = (SecurityTypeProto as unknown as Record<string, number>)[name];
|
|
14
|
+
expect(value).toBe(expected);
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
test('throws on unknown name and lists valid names in the error', () => {
|
|
19
|
+
let err: Error | undefined;
|
|
20
|
+
try {
|
|
21
|
+
SecurityType.fromName('NOT_A_REAL_TYPE');
|
|
22
|
+
} catch (e) {
|
|
23
|
+
err = e as Error;
|
|
24
|
+
}
|
|
25
|
+
expect(err).toBeDefined();
|
|
26
|
+
expect(err!.message).toContain('NOT_A_REAL_TYPE');
|
|
27
|
+
// Error message should hint with known valid entries.
|
|
28
|
+
expect(err!.message).toContain('BOND_SECURITY');
|
|
29
|
+
expect(err!.message).toContain('EQUITY_SECURITY');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('accepts UNKNOWN_SECURITY_TYPE — sentinel is a valid enum key', () => {
|
|
33
|
+
// It's excluded from getAllTypeNames (so it doesn't appear in
|
|
34
|
+
// dropdowns), but it IS a valid proto enum value, so fromName
|
|
35
|
+
// accepts it. Pinning the existing behavior — flip if policy
|
|
36
|
+
// ever tightens.
|
|
37
|
+
expect(SecurityType.fromName('UNKNOWN_SECURITY_TYPE')).toBe(
|
|
38
|
+
SecurityTypeProto.UNKNOWN_SECURITY_TYPE
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('SecurityType.getAllTypeNames', () => {
|
|
44
|
+
test('returns the expected set in proto-declaration order, excluding UNKNOWN', () => {
|
|
45
|
+
// Proto-declared order in security_type.proto:
|
|
46
|
+
// UNKNOWN_SECURITY_TYPE = 0; (excluded)
|
|
47
|
+
// CASH_SECURITY = 1;
|
|
48
|
+
// EQUITY_SECURITY = 2;
|
|
49
|
+
// BOND_SECURITY = 3;
|
|
50
|
+
// TIPS = 4;
|
|
51
|
+
// FRN = 5;
|
|
52
|
+
// INDEX_SECURITY = 6;
|
|
53
|
+
// FX_SPOT = 7;
|
|
54
|
+
// EQUITY_INDEX_SECURITY = 8;
|
|
55
|
+
expect(SecurityType.getAllTypeNames()).toEqual([
|
|
56
|
+
'CASH_SECURITY',
|
|
57
|
+
'EQUITY_SECURITY',
|
|
58
|
+
'BOND_SECURITY',
|
|
59
|
+
'TIPS',
|
|
60
|
+
'FRN',
|
|
61
|
+
'INDEX_SECURITY',
|
|
62
|
+
'FX_SPOT',
|
|
63
|
+
'EQUITY_INDEX_SECURITY',
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('excludes the UNKNOWN_SECURITY_TYPE sentinel', () => {
|
|
68
|
+
expect(SecurityType.getAllTypeNames()).not.toContain('UNKNOWN_SECURITY_TYPE');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { SecurityTypeProto } from '../../../fintekkers/models/security/security_type_pb';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Static helpers around the SecurityType proto enum, mirroring the
|
|
5
|
+
* Identifier wrapper pattern shipped in v0.1.133 (PR #188).
|
|
6
|
+
*
|
|
7
|
+
* Lets TS/JS consumers stop hand-typing literal unions and switch
|
|
8
|
+
* statements over `'BOND_SECURITY' | 'TIPS' | 'FRN' | ...` — adding a
|
|
9
|
+
* new variant on the proto side propagates automatically.
|
|
10
|
+
*/
|
|
11
|
+
export class SecurityType {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Returns the names of all known SecurityTypeProto values, EXCLUDING
|
|
15
|
+
* the sentinel `UNKNOWN_SECURITY_TYPE`. Drives UI dropdowns / pickers
|
|
16
|
+
* so a new proto enum variant auto-propagates to consumers without
|
|
17
|
+
* any UI-side code change.
|
|
18
|
+
*
|
|
19
|
+
* Order matches proto declaration order (Object.keys preserves
|
|
20
|
+
* insertion order on the generated JS enum object).
|
|
21
|
+
*/
|
|
22
|
+
static getAllTypeNames(): string[] {
|
|
23
|
+
return Object.keys(SecurityTypeProto).filter(
|
|
24
|
+
k => k !== 'UNKNOWN_SECURITY_TYPE'
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a proto enum NAME (e.g., "BOND_SECURITY", "EQUITY_SECURITY")
|
|
30
|
+
* to its numeric SecurityTypeProto value. Throws on unknown name; the
|
|
31
|
+
* error lists the valid names so typos are fixable without grepping
|
|
32
|
+
* the proto.
|
|
33
|
+
*
|
|
34
|
+
* @param name proto enum key (e.g., "BOND_SECURITY")
|
|
35
|
+
* @returns the numeric SecurityTypeProto value
|
|
36
|
+
*/
|
|
37
|
+
static fromName(name: string): SecurityTypeProto {
|
|
38
|
+
const enumObj = SecurityTypeProto as unknown as Record<string, number>;
|
|
39
|
+
const enumValue = enumObj[name];
|
|
40
|
+
if (enumValue === undefined) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Unknown SecurityType name: '${name}'. Valid names: ${SecurityType.getAllTypeNames().join(', ')}`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return enumValue as SecurityTypeProto;
|
|
46
|
+
}
|
|
47
|
+
}
|