#17 Completing Securities Domain Modeling And Updating Our State
Saturday, September 28, 2019
In this article we will create the last couple of descriptors that we need before we can create the security category model and the security model itself. Once that is done we will finish up by creating a module for our security states and use it to make adding them to the overall store state very simple.
Parts
- Part 45: Adjusting Shares
- Part 44: Plan Percentages
- Part 43: Home Securities
- Part 42: Updating Plans
- Part 41: Plan Details View
- Part 40: Portfolio Getters
- Part 39: Portfolio Plan
- Part 38: Portfolio Category
- Part 37: Account Securities
- Part 36: Account Transfer
- Part 35: View Account Security
- Part 34: Updating Deposit
- Part 33: View Account Deposit
- Part 32: Display Account Details
- Part 31: Account Getters
- Part 30: Deposits And Securities
- Part 29: Add Accounts Details
- Part 28: Refactoring Accounts
- Part 27: Add Security Models
- Part 26: Edit Security Details
- Part 25: View Security Details
- Part 24: Navigating To Details
- Part 23: Getters Validation
- Part 22: Query Parameters
- Part 21: Tab Entries
- Part 20: Tab Header
- Part 19: List View
- Part 18: Vuex Getters
- Part 17: End Domain Model
- Part 16: Start Domain Model
- Part 15: Pop Routes
- Part 14: Push Routes
- Part 13: Removing Accounts
- Part 12: Vuex (Decorators)
- Part 11: Vuex (Accounts)
- Part 10: The App Bar (Settings)
- Part 9: Remove Consumer Rxjs
- Part 8: The App Bar (Back)
- Part 7: Structuring Our App
- Part 6: Animation Between Views
- Part 5: Navigation Fade
- Part 4: Navigation Requests
- Part 3: Fade Animations (cont.)
- Part 2: Fade Animations
- Part 1: Splash Screen
Territory Model
- root
- src
- store
- security-territory-model.ts
- store
- src
Creating a territory model is just as simple as creating the other security descriptors that we created in the previous article. We just need to create a class and inherit from the base class (a).
security-territory-model.ts
import { SecurityDescriptor } from "@/store/security-descriptor";
export class SecurityTerritoryModel extends SecurityDescriptor { }
Territory Constants
- root
- src
- store
- security-constants.ts
- store
- src
Following the pattern next up is to define the constants that represent the text for our initial territories (b).
security-constants.ts
...
export const SECURITY_TERRITORY_DOMESTIC = "Domestic";
export const SECURITY_TERRITORY_INTERNATIONAL = "International";
Territory Types
- root
- src
- store
- security-types.ts
- store
- src
Now we need to define the interface for our territory state and add it to the overall security state (c).
security-types.ts
...
import { SecurityTerritoryModel } from "@/store/security-territory-model";
...
export interface ISecurityTerritoryModelState {
index: number;
items: SecurityTerritoryModel[];
}
export interface ISecurityState {
...
[STATE_SECURITY_TERRITORIES]: ISecurityTerritoryModelState;
}
Territory Initial State
- root
- src
- store
- security-territory-initial-state.ts
- store
- src
Creating our initial state for the territories state is exactly the same as we have done in the past. We start by importing the text constants, the model type, and the appropriate state interface. Next we create an empty typed array and a function to create new territories and finish up by adding territories to the array and exporting the state (d).
security-territory-initial-state.ts
import {
SECURITY_TERRITORY_DOMESTIC,
SECURITY_TERRITORY_INTERNATIONAL,
} from "@/store/security-constants";
import { SecurityTerritoryModel } from "@/store/security-territory-model";
import { ISecurityTerritoryModelState } from "@/store/security-types";
const territories: SecurityTerritoryModel[] = [];
function createTerritory(id: number, text: string) {
territories.push(new SecurityTerritoryModel(id, text));
return id += 1;
}
let index = 1;
index = createTerritory(index, SECURITY_TERRITORY_DOMESTIC);
index = createTerritory(index, SECURITY_TERRITORY_INTERNATIONAL);
export const initialState: ISecurityTerritoryModelState = {
index,
items: territories,
};
Type model
- root
- src
- store
- security-type-model.ts
- store
- src
Adding a type descriptor (e).
security-type-model.ts
import { SecurityDescriptor } from "@/store/security-descriptor";
export class SecurityTypeModel extends SecurityDescriptor { }
Type constants
- root
- src
- store
- security-constants.ts
- store
- src
Initially our type descriptor can have three values for the text property (f).
security-constants.ts
export const SECURITY_TYPE_EQUITY = "Equity";
export const SECURITY_TYPE_FIXED_INCOME = "Fixed Income";
export const SECURITY_TYPE_SPECIALTY = "Specialty";
Type types (now there's a heading)
- root
- src
- store
- security-types.ts
- store
- src
Adding the interface and including it in the security state is exactly the same pattern as we have seen previously (g).
security-types.ts
...
import { SecurityTypeModel } from "@/store/security-type-model";
...
export interface ISecurityTypeModelState {
index: number;
items: SecurityTypeModel[];
}
export interface ISecurityState {
...
[STATE_SECURITY_TYPES]: ISecurityTypeModelState;
}
Type initial state
- root
- src
- store
- security-type-initial-state.ts
- store
- src
Populating our initial type model state (h).
security-type-initial-state.ts
import {
SECURITY_TYPE_EQUITY,
SECURITY_TYPE_FIXED_INCOME,
SECURITY_TYPE_SPECIALTY,
} from "@/store/security-constants";
import { SecurityTypeModel } from "@/store/security-type-model";
import { ISecurityTypeModelState } from "@/store/security-types";
const types: SecurityTypeModel[] = [];
function createType(id: number, text: string) {
types.push(new SecurityTypeModel(id, text));
return id += 1;
}
let index = 1;
index = createType(index, SECURITY_TYPE_EQUITY);
index = createType(index, SECURITY_TYPE_FIXED_INCOME);
index = createType(index, SECURITY_TYPE_SPECIALTY);
export const initialState: ISecurityTypeModelState = {
index,
items: types,
};
Category model
- root
- src
- store
- security-category-model.ts
- store
- src
The category model is our first interesting model in that it is not just a descriptor. The category itself contains three of the descriptors that we have already created (i). To create a category we will need to pass in a configuration object that contains the id values that point to the appropriate descriptor. The descriptors themselves will be initialized to null and we provide several setter methods to set the fields to the corresponding value.
security-category-model.ts
import { SecuritySegmentModel } from "@/store/security-segment-model";
import { SecurityTerritoryModel } from "@/store/security-territory-model";
import { SecurityTypeModel } from "@/store/security-type-model";
export interface ISecurityCategoryModelConfig {
id: number;
segmentId: number;
territoryId: number;
typeId: number;
}
export class SecurityCategoryModel {
private _id: number;
private _segment: SecuritySegmentModel | null = null;
private _segmentId: number;
private _territory: SecurityTerritoryModel | null = null;
private _territoryId: number;
private _type: SecurityTypeModel | null = null;
private _typeId: number;
public get id() { return this._id; }
public get segment() { return this._segment; }
public get segmentId() { return this._segmentId; }
public get territory() { return this._territory; }
public get territoryId() { return this._territoryId; }
public get text() {
const text = { text: "undefined"};
const territory = (this.territory || text).text;
const type = (this.type || text).text;
const segment = (this.segment || text).text;
return `${territory} ${type} ${segment}`; }
public get type() { return this._type; }
public get typeId() { return this._typeId; }
constructor(config: ISecurityCategoryModelConfig) {
this._id = config.id;
this._segmentId = config.segmentId;
this._territoryId = config.territoryId;
this._typeId = config.typeId;
}
public setSegment = (segment: SecuritySegmentModel) => {
this._segment = segment;
return this;
}
public setTerritory = (territory: SecurityTerritoryModel) => {
this._territory = territory;
return this;
}
public setType = (type: SecurityTypeModel) => {
this._type = type;
return this;
}
public toPersistObj = (): ISecurityCategoryModelConfig => {
return {
id: this._id,
segmentId: this._segmentId,
territoryId: this._territoryId,
typeId: this._typeId,
};
}
}
Category and Security State Constants
- root
- src
- store
- store-constants.ts
- store
- src
In the last article we added the state constants for our descriptors and now we need to add once for the categories and while we are at it we might as well add one for the securities (j).
store-constants.ts
...
export const STATE_SECURITIES = "STATE_SECURITIES";
export const STATE_SECURITY_CATEGORIES = "STATE_SECURITY_CATEGORIES";
...
Category Types
- root
- src
- store
- security-types.ts
- store
- src
As you can probably guess we need to export an interface for our category state and add it to our security state (k). We are also going to take the opportunity to add a new enum that we will need when defining a security which we will do shortly.
security-types.ts
import {
STATE_SECURITY_CATEGORIES,
...
STATE_SECURITIES,
...
} from "@/store/store-constants";
...
import { SecurityCategoryModel } from "@/store/security-category-model";
export enum SecurityRecommendations {
Buy,
Sell,
Hold,
}
export interface ISecurityCategoryModelState {
index: number;
items: SecurityCategoryModel[];
}
...
export interface ISecurityState {
[STATE_SECURITY_CATEGORIES]: ISecurityCategoryModelState;
...
}
Category initial state
- root
- src
- store
- security-category-initial-state.ts
- store
- src
Although it is a bit more complicated to create the initial state for our categories it follows the same basic pattern (l). Here we see why we took the time to define the the constants for the segments, territories, and types. Since we used the same constants when we created the initial states for all of them we can use the same constants to find individual elements of each now that we need them to create our categories.
security-category-initial-state.ts
import { ISecurityCategoryModelConfig, SecurityCategoryModel } from "@/store/security-category-model";
import { ISecurityCategoryModelState } from "@/store/security-types";
import {
SECURITY_SEGMENT_DEVELOPED_TEXT,
SECURITY_SEGMENT_EMERGING_TEXT,
SECURITY_SEGMENT_LARGE_CAP_TEXT,
SECURITY_SEGMENT_MID_CAP_TEXT,
SECURITY_SEGMENT_SMALL_CAP_TEXT,
SECURITY_TERRITORY_DOMESTIC,
SECURITY_TERRITORY_INTERNATIONAL,
SECURITY_TYPE_EQUITY,
SECURITY_TYPE_FIXED_INCOME,
SECURITY_TYPE_SPECIALTY,
} from "@/store/security-constants";
import { initialState as segments } from "@/store/security-segment-initial-state";
import { initialState as territories } from "@/store/security-territory-initial-state";
import { initialState as types } from "@/store/security-type-initial-state";
const largeCap = segments.items.find((x) => x.text === SECURITY_SEGMENT_LARGE_CAP_TEXT)!;
const midCap = segments.items.find((x) => x.text === SECURITY_SEGMENT_MID_CAP_TEXT)!;
const smallCap = segments.items.find((x) => x.text === SECURITY_SEGMENT_SMALL_CAP_TEXT)!;
const developed = segments.items.find((x) => x.text === SECURITY_SEGMENT_DEVELOPED_TEXT)!;
const emerging = segments.items.find((x) => x.text === SECURITY_SEGMENT_EMERGING_TEXT)!;
const domestic = territories.items.find((x) => x.text === SECURITY_TERRITORY_DOMESTIC)!;
const international = territories.items.find((x) => x.text === SECURITY_TERRITORY_INTERNATIONAL)!;
const equity = types.items.find((x) => x.text === SECURITY_TYPE_EQUITY)!;
const fixedIncome = types.items.find((x) => x.text === SECURITY_TYPE_FIXED_INCOME)!;
const specialty = types.items.find((x) => x.text === SECURITY_TYPE_SPECIALTY)!;
const categories: SecurityCategoryModel[] = [];
function createCategory(config: ISecurityCategoryModelConfig) {
categories.push(new SecurityCategoryModel(config));
return config.id += 1;
}
let index = 1;
index = createCategory({ id: index, segmentId: largeCap.id, territoryId: domestic.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: midCap.id, territoryId: domestic.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: smallCap.id, territoryId: domestic.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: developed.id, territoryId: international.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: emerging.id, territoryId: international.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: developed.id, territoryId: domestic.id, typeId: fixedIncome.id });
index = createCategory({ id: index, segmentId: developed.id, territoryId: international.id, typeId: fixedIncome.id });
index = createCategory({ id: index, segmentId: developed.id, territoryId: domestic.id, typeId: specialty.id });
export const initialState: ISecurityCategoryModelState = {
index,
items: categories,
};
Security Model
- root
- src
- store
- security-model.ts
- store
- src
That last model that we should need for a little while is our security model (m). This model is a little less complicated than the category in that it only contains one descriptor and a category. Again we start by passing the configuration object into the constructor which contains only values for the scalar properties. We then also add the appropriate setter methods.
security-model.ts
import { SecurityCategoryModel } from "@/store/security-category-model";
import { SecurityMarketModel } from "@/store/security-market-model";
import { SecurityRecommendations } from "@/store/security-types";
export interface ISecurityModelConfig {
categoryId: number;
id: number;
last: number;
marketId: number;
recommendation: SecurityRecommendations;
symbol: string;
}
export class SecurityModel {
private _category: SecurityCategoryModel | null = null;
private _categoryId: number;
private _id: number;
private _last: number;
private _market: SecurityMarketModel | null = null;
private _marketId: number;
private _recommendation: SecurityRecommendations;
private _symbol: string;
public get category() { return this._category; }
public get categoryId() { return this._categoryId; }
public get id() { return this._id; }
public get last() { return this._last; }
public get market() { return this._market; }
public get marketId() { return this._marketId; }
public get recommendation() { return this._recommendation; }
public get symbol() { return this._symbol; }
constructor(config: ISecurityModelConfig) {
this._categoryId = config.categoryId;
this._id = config.id;
this._last = config.last;
this._marketId = config.marketId;
this._recommendation = config.recommendation;
this._symbol = config.symbol;
}
public setCategory = (category: SecurityCategoryModel) => {
this._category = category;
return this;
}
public setMarket = (market: SecurityMarketModel) => {
this._market = market;
return this;
}
public toPersistObj = (): ISecurityModelConfig => {
return {
categoryId: this._categoryId,
id: this._id,
last: this._last,
marketId: this._marketId,
recommendation: this._recommendation,
symbol: this._symbol,
};
}
}
Security Types
- root
- src
- store
- security-types.ts
- store
- src
Back to our security types file to export the security model interface and add it to the overall state (n).
security-types.ts
...
import { SecurityModel } from "@/store/security-model";
...
export interface ISecurityModelState {
index: number;
items: SecurityModel[];
}
...
export interface ISecurityState {
...
[STATE_SECURITIES]: ISecurityModelState;
...
}
Security Initial State
- root
- src
- store
- security-model-initial-state.ts
- store
- src
Just as before we need to create some data for our initial state (o).
security-model-initial-state.ts
import { ISecurityModelConfig, SecurityModel } from "@/store/security-model";
import { ISecurityModelState, SecurityRecommendations } from "@/store/security-types";
import {
SECURITY_MARKET_CBOE,
SECURITY_MARKET_NASDAQ,
SECURITY_MARKET_NYSE,
} from "@/store/security-constants";
import { initialState as categories } from "@/store/security-category-initial-state";
import { initialState as markets } from "@/store/security-market-initial-state";
const buy = SecurityRecommendations.Buy;
const hold = SecurityRecommendations.Hold;
const sell = SecurityRecommendations.Sell;
const delc = categories.items[0];
const demc = categories.items[1];
const desc = categories.items[2];
const iedm = categories.items[3];
const ieem = categories.items[4];
const fid = categories.items[5];
const fii = categories.items[6];
const spec = categories.items[7];
const cboe = markets.items.find((x) => x.text === SECURITY_MARKET_CBOE)!;
const nasdaq = markets.items.find((x) => x.text === SECURITY_MARKET_NASDAQ)!;
const nyse = markets.items.find((x) => x.text === SECURITY_MARKET_NYSE)!;
const securities: SecurityModel[] = [];
function createSecurity(id: number, config: Omit<ISecurityModelConfig, "id">) {
securities.push(new SecurityModel({ id, ...config }));
return id += 1;
}
const acwv = { categoryId: delc.id, last: 90.27, marketId: cboe.id, recommendation: buy, symbol: "ACWV" };
const bnd = { categoryId: fid.id, last: 83.84, marketId: nyse.id, recommendation: hold, symbol: "BND" };
const bndx = { categoryId: fii.id, last: 58.27, marketId: nasdaq.id, recommendation: buy, symbol: "BNDX" };
const embh = { categoryId: fii.id, last: 24.43, marketId: nyse.id, recommendation: hold, symbol: "EMBH" };
const esgd = { categoryId: iedm.id, last: 60.89, marketId: nasdaq.id, recommendation: hold, symbol: "ESGD" };
const fnde = { categoryId: iedm.id, last: 26.55, marketId: nyse.id, recommendation: buy, symbol: "FNDE" };
const ftec = { categoryId: spec.id, last: 59.49, marketId: nyse.id, recommendation: buy, symbol: "FTEC" };
const lkor = { categoryId: fid.id, last: 56.05, marketId: nasdaq.id, recommendation: hold, symbol: "LKOR" };
const mdyg = { categoryId: demc.id, last: 52.31, marketId: nyse.id, recommendation: sell, symbol: "MDYG" };
const mgk = { categoryId: delc.id, last: 126.26, marketId: nyse.id, recommendation: hold, symbol: "MGK" };
const mlqd = { categoryId: fid.id, last: 51.73, marketId: cboe.id, recommendation: buy, symbol: "MLQD" };
const pcy = { categoryId: fii.id, last: 29.06, marketId: nyse.id, recommendation: hold, symbol: "PCY" };
const qemm = { categoryId: ieem.id, last: 54.64, marketId: nyse.id, recommendation: hold, symbol: "QEMM" };
const schg = { categoryId: delc.id, last: 79.76, marketId: nyse.id, recommendation: buy, symbol: "SCHG" };
const slyg = { categoryId: desc.id, last: 58.70, marketId: nyse.id, recommendation: sell, symbol: "SLYG" };
const vbk = { categoryId: desc.id, last: 179.79, marketId: nyse.id, recommendation: buy, symbol: "VBK" };
const vea = { categoryId: iedm.id, last: 39.35, marketId: nyse.id, recommendation: hold, symbol: "VEA" };
const vis = { categoryId: spec.id, last: 139.01, marketId: nyse.id, recommendation: buy, symbol: "VIS" };
const vot = { categoryId: demc.id, last: 143.52, marketId: nyse.id, recommendation: buy, symbol: "VOT" };
const vwo = { categoryId: ieem.id, last: 39.10, marketId: nyse.id, recommendation: hold, symbol: "VWO" };
const xcem = { categoryId: ieem.id, last: 24.48, marketId: nyse.id, recommendation: hold, symbol: "XCEM" };
const xsoe = { categoryId: ieem.id, last: 26.64, marketId: nyse.id, recommendation: hold, symbol: "XSOE" };
let index = 1;
index = createSecurity(index, acwv);
index = createSecurity(index, bnd);
index = createSecurity(index, bndx);
index = createSecurity(index, embh);
index = createSecurity(index, esgd);
index = createSecurity(index, fnde);
index = createSecurity(index, ftec);
index = createSecurity(index, lkor);
index = createSecurity(index, mdyg);
index = createSecurity(index, mgk);
index = createSecurity(index, mlqd);
index = createSecurity(index, pcy);
index = createSecurity(index, qemm);
index = createSecurity(index, schg);
index = createSecurity(index, slyg);
index = createSecurity(index, vbk);
index = createSecurity(index, vea);
index = createSecurity(index, vis);
index = createSecurity(index, vot);
index = createSecurity(index, vwo);
index = createSecurity(index, xcem);
index = createSecurity(index, xsoe);
export const initialState: ISecurityModelState = {
index,
items: securities,
};
Exporting the models
- root
- src
- store
- index.ts
- store
- src
With them all defined we can just export them all at one time (p).
index.ts
...
export * from "@/store/security-category-model";
export * from "@/store/security-market-model";
export * from "@/store/security-model";
export * from "@/store/security-segment-model";
export * from "@/store/security-territory-model";
export * from "@/store/security-type-model";
...
Extending the store state
- root
- src
- store
- store-types.ts
- store
- src
Since we have already created an interface that represents all the security models we can use it to extend our store state (q).
store-types.ts
...
import { ISecurityState } from "@/store/security-types";
export interface IStoreState extends ISecurityState {
...
}
...
Security Module
- root
- src
- store
- security-module.ts
- store
- src
Just like with our accounts and routes we will create a new file that will define the module for the security states that we have just created (r).
security-module.ts
import {
STATE_SECURITIES,
STATE_SECURITY_CATEGORIES,
STATE_SECURITY_MARKETS,
STATE_SECURITY_SEGMENTS,
STATE_SECURITY_TERRITORIES,
STATE_SECURITY_TYPES,
} from "@/store/store-constants";
import { ISecurityState } from "@/store/security-types";
import { initialState as categoryState } from "@/store/security-category-initial-state";
import { initialState as marketState } from "@/store/security-market-initial-state";
import { initialState as securityState } from "@/store/security-model-initial-state";
import { initialState as segmentState } from "@/store/security-segment-initial-state";
import { initialState as territoryState } from "@/store/security-territory-initial-state";
import { initialState as typeState } from "@/store/security-type-initial-state";
export const securitiesState: ISecurityState = {
[STATE_SECURITIES]: securityState,
[STATE_SECURITY_CATEGORIES]: categoryState,
[STATE_SECURITY_MARKETS]: marketState,
[STATE_SECURITY_SEGMENTS]: segmentState,
[STATE_SECURITY_TERRITORIES]: territoryState,
[STATE_SECURITY_TYPES]: typeState,
};
Adding the security state to the store
- root
- src
- store
- store.ts
- store
- src
Adding all of the security states to our store state is once again a simple use of the spread operator away (s).
store.ts
...
import {
securitiesState,
} from "@/store/security-module";
...
const state: IStoreState = {
...
...securitiesState,
};
...