Advertisement

#27 Adding Security Models Using Vuex Actions And Mutations

In this article we focus on adding the vuex actions and mutations that will allow us to add new security models to our store. We of course start by adding in the constants that we need in order to specify which action and mutation should be run as well as the required payload type. With those things in place we will create a couple of new fuctions, the first of which will help us add items to the store and the other will be used to sort those items. The last modification we will need to make is to update our security details view so that we invoke our new add actions when appropriate.

Code Snippets

store-constants.ts (1:29)

...
export const ACTION_ADD_SECURITY = "ACTION_ADD_SECURITY";
export const ACTION_ADD_SECURITY_CATEGORY = "ACTION_ADD_SECURITY_CATEGORY";
export const ACTION_ADD_SECURITY_MARKET = "ACTION_ADD_SECURITY_MARKET";
export const ACTION_ADD_SECURITY_SEGMENT = "ACTION_ADD_SECURITY_SEGMENT";
export const ACTION_ADD_SECURITY_TERRITORY = "ACTION_ADD_SECURITY_TERRITORY";
export const ACTION_ADD_SECURITY_TYPE = "ACTION_ADD_SECURITY_TYPE";
...
export const MUTATION_ADD_SECURITY = "MUTATION_ADD_SECURITY";
export const MUTATION_ADD_SECURITY_CATEGORY = "MUTATION_ADD_SECURITY_CATEGORY";
export const MUTATION_ADD_SECURITY_MARKET = "MUTATION_ADD_SECURITY_MARKET";
export const MUTATION_ADD_SECURITY_SEGMENT = "MUTATION_ADD_SECURITY_SEGMENT";
export const MUTATION_ADD_SECURITY_TERRITORY = "MUTATION_ADD_SECURITY_TERRITORY";
export const MUTATION_ADD_SECURITY_TYPE = "MUTATION_ADD_SECURITY_TYPE";
...
src ⟩ store ⟩ store-constants.ts

security-types.ts (2:14)

...
export type PayloadAddSecurity = SecurityModel;
export type PayloadAddSecurityCategory = SecurityCategoryModel;
export type PayloadAddSecurityMarket = SecurityMarketModel;
export type PayloadAddSecuritySegment = SecuritySegmentModel;
export type PayloadAddSecurityTerritory = SecurityTerritoryModel;
export type PayloadAddSecurityType = SecurityTypeModel;
...
src ⟩ store ⟩ security-types.ts

functions.ts (2:46)

...
export function add<T extends IStateItem>(state: IState<T>, item: T, func: (item: T) => string) {
    if (typeof item === "undefined") {
        throw new Error(`Cannot add 'undefined' item to the store.`);
    }
    if (item === null) {
        throw new Error(`Cannot add 'null' item to the store.`);
    }
    item.id = state.index;
    state.items = sort([...state.items, item], func);
    state.index += 1;
}
...
export function sort<T>(items: T[], func: (item: T) => string) {
    return items.sort((a, b) => {
        const aStr = func(a).toUpperCase();
        const bStr = func(b).toUpperCase();
        if (aStr < bStr) {
            return -1;
        }
        if (aStr > bStr) {
            return 1;
        }
        return 0;
    });
}
...
src ⟩ store ⟩ functions.ts

security-descriptor.ts (7:07)

export abstract class SecurityDescriptor {
    ...
    public set id(id: number) {
        this._id = id;
    }
    ...
    constructor(private _id: number, ...) {}
    ...
}
src ⟩ store ⟩ security-descriptor.ts

security-module.ts (7:34)

...
import {
    ACTION_ADD_SECURITY,
    ACTION_ADD_SECURITY_CATEGORY,
    ACTION_ADD_SECURITY_MARKET,
    ACTION_ADD_SECURITY_SEGMENT,
    ACTION_ADD_SECURITY_TERRITORY,
    ACTION_ADD_SECURITY_TYPE,
    ...
    MUTATION_ADD_SECURITY,
    MUTATION_ADD_SECURITY_MARKET,
    MUTATION_ADD_SECURITY_CATEGORY,
    MUTATION_ADD_SECURITY_SEGMENT,
    MUTATION_ADD_SECURITY_TERRITORY,
    MUTATION_ADD_SECURITY_TYPE,
    ...
} from "@/store/store-constants";

import { add... sort, ... } from "@/store/functions";
...
import {
    ...
    PayloadAddSecurity,
    PayloadAddSecurityCategory,
    PayloadAddSecurityMarket,
    PayloadAddSecuritySegment,
    PayloadAddSecurityTerritory,
    PayloadAddSecurityType,
    ...
} from "@/store/security-types";
...
function formatSecurity(payload: PayloadAddSecurity | PayloadUpdateSecurity) {
    payload.symbol = payload.symbol.toUpperCase();
}

function formatSecurityDescriptor(
    payload:
        | PayloadAddSecuritySegment
        | PayloadAddSecurityTerritory
        | PayloadAddSecurityType
        | PayloadUpdateSecuritySegment
        | PayloadAddSecurityTerritory
        | PayloadUpdateSecurityType,
) {
    payload.text = payload.text
        .toLowerCase()
        .split(" ")
        .map((x) => `${x.charAt(0).toUpperCase()}${x.slice(1)}`)
        .join(" ");
}

function formatSecurityMarket(payload: PayloadAddSecurityMarket | PayloadUpdateSecurityMarket) {
    payload.text = payload.text.toUpperCase();
}

function hydrateSecurity(store: Store<IStoreState>, payload: PayloadAddSecurity | PayloadUpdateSecurity) {
    const category = (store.getters as ISecurityGetters)[GETTER_SECURITY_CATEGORY](payload.categoryId);
    const market = (store.getters as ISecurityGetters)[GETTER_SECURITY_MARKET](payload.marketId);

    payload.setCategory(category);
    payload.setMarket(market);
}

function hydrateSecurityCategory(
    store: Store<IStoreState>,
    payload: PayloadAddSecurityCategory | PayloadUpdateSecurityCategory,
) {
    const segment = (store.getters as ISecurityGetters)[GETTER_SECURITY_SEGMENT](payload.segmentId);
    const territory = (store.getters as ISecurityGetters)[GETTER_SECURITY_TERRITORY](payload.territoryId);
    const type = (store.getters as ISecurityGetters)[GETTER_SECURITY_TYPE](payload.typeId);

    payload.setSegment(segment);
    payload.setSegment(territory);
    payload.setType(type);
}
...
src ⟩ store ⟩ security-module.ts

security-module.ts (15:43)

...
export const securitiesActions: StoreActionTree = {
    [ACTION_ADD_SECURITY](this, { commit }, payload: PayloadAddSecurity) {
        hydrateSecurity(this, payload);
        formatSecurity(payload);
        commit(MUTATION_ADD_SECURITY, payload);
    },
    [ACTION_ADD_SECURITY_CATEGORY](this, { commit }, payload: PayloadAddSecurityCategory) {
        hydrateSecurityCategory(this, payload);
        commit(MUTATION_ADD_SECURITY_CATEGORY, payload);
    },
    [ACTION_ADD_SECURITY_MARKET](this, { commit }, payload: PayloadAddSecurityMarket) {
        formatSecurityMarket(payload);
        commit(MUTATION_ADD_SECURITY_MARKET, payload);
    },
    [ACTION_ADD_SECURITY_SEGMENT](this, { commit }, payload: PayloadAddSecuritySegment) {
        formatSecurityDescriptor
        commit(MUTATION_ADD_SECURITY_SEGMENT, payload);
    },
    [ACTION_ADD_SECURITY_TERRITORY](this, { commit }, payload: PayloadAddSecurityTerritory) {
        formatSecurityDescriptor
        commit(MUTATION_ADD_SECURITY_TERRITORY, payload);
    },
    [ACTION_ADD_SECURITY_TYPE](this, { commit }, payload: PayloadAddSecurityType) {
        formatSecurityDescriptor
        commit(MUTATION_ADD_SECURITY_TYPE, payload);
    },
    [ACTION_UPDATE_SECURITY](this, { commit }, payload: PayloadUpdateSecurity) {
        hydrateSecurity(this, payload);
        formatSecurity(payload);
        commit(MUTATION_UPDATE_SECURITY, payload);
    },
    [ACTION_UPDATE_SECURITY_CATEGORY](this, { commit }, payload: PayloadUpdateSecurityCategory) {
        hydrateSecurityCategory(this, payload);
        commit(MUTATION_UPDATE_SECURITY_CATEGORY, payload);
    },
    [ACTION_UPDATE_SECURITY_MARKET](this, { commit }, payload: PayloadUpdateSecurityMarket) {
        formatSecurityMarket(payload);
        commit(MUTATION_UPDATE_SECURITY_MARKET, payload);
    },
    [ACTION_UPDATE_SECURITY_SEGMENT](this, { commit }, payload: PayloadUpdateSecuritySegment) {
        formatSecurityDescriptor
        commit(MUTATION_UPDATE_SECURITY_SEGMENT, payload);
    },
    [ACTION_UPDATE_SECURITY_TERRITORY](this, { commit }, payload: PayloadUpdateSecurityTerritory) {
        formatSecurityDescriptor
        commit(MUTATION_UPDATE_SECURITY_TERRITORY, payload);
    },
    [ACTION_UPDATE_SECURITY_TYPE](this, { commit }, payload: PayloadUpdateSecurityType) {
        formatSecurityDescriptor(payload);
        commit(MUTATION_UPDATE_SECURITY_TYPE, payload);
    },
};
...
src ⟩ store ⟩ security-module.ts

Advertisement

security-module.ts (19:54)

...
export const securitiesGetters: StoreGetterTree = {
    [GETTER_SECURITIES]: (state, getters: ISecurityGetters) => {
        return state[STATE_SECURITIES].items.map((x) => getters[GETTER_SECURITY](x.id));
    },
    [GETTER_SECURITY]: (state, getters: ISecurityGetters) => {
        return (id: number) => {
            const security = findById(state[STATE_SECURITIES], id);

            storeActionValidator
                .begin()
                .while(StoreActions.Getting)
                .throwIf(security)
                .isUndefined(undefinedMessage("security", id, state[STATE_SECURITIES].index));

            const category = getters[GETTER_SECURITY_CATEGORY](security!.categoryId);
            const market = getters[GETTER_SECURITY_MARKET](security!.marketId);

            return security!.setCategory(category).setMarket(market);
        };
    },
    [GETTER_SECURITY_CATEGORIES]: (state, getters: ISecurityGetters) => {
        return state[STATE_SECURITY_CATEGORIES].items.map((x) => getters[GETTER_SECURITY_CATEGORY](x.id));
    },
    [GETTER_SECURITY_CATEGORY]: (state, getters: ISecurityGetters) => {
        return (id: number) => {
            const category = findById(state[STATE_SECURITY_CATEGORIES], id);

            storeActionValidator
                .begin()
                .while(StoreActions.Getting)
                .throwIf(category)
                .isUndefined(undefinedMessage("category", id, state[STATE_SECURITY_CATEGORIES].index));

            const segment = getters[GETTER_SECURITY_SEGMENT](category!.segmentId);
            const territory = getters[GETTER_SECURITY_TERRITORY](category!.territoryId);
            const type = getters[GETTER_SECURITY_TYPE](category!.typeId);

            return category!
                .setSegment(segment!)
                .setTerritory(territory!)
                .setType(type!);
        };
    },
    [GETTER_SECURITY_MARKET]: (state) => {
        return (id: number) => {
            const market = findById(state[STATE_SECURITY_MARKETS], id);

            storeActionValidator
                .begin()
                .while(StoreActions.Getting)
                .throwIf(market)
                .isUndefined(undefinedMessage("market", id, state[STATE_SECURITY_MARKETS].index));

            return market;
        };
    },
    [GETTER_SECURITY_MARKETS]: (state) => {
        return findAll(state[STATE_SECURITY_MARKETS]);
    },
    [GETTER_SECURITY_SEGMENT]: (state) => {
        return (id: number) => {
            const segment = findById(state[STATE_SECURITY_SEGMENTS], id);

            storeActionValidator
                .begin()
                .while(StoreActions.Getting)
                .throwIf(segment)
                .isUndefined(undefinedMessage("segment", id, state[STATE_SECURITY_SEGMENTS].index));

            return segment;
        };
    },
    [GETTER_SECURITY_SEGMENTS]: (state) => {
        return findAll(state[STATE_SECURITY_SEGMENTS]);
    },
    [GETTER_SECURITY_TERRITORIES]: (state) => {
        return findAll(state[STATE_SECURITY_TERRITORIES]);
    },
    [GETTER_SECURITY_TERRITORY]: (state) => {
        return (id: number) => {
            const territory = findById(state[STATE_SECURITY_TERRITORIES], id);

            storeActionValidator
                .begin()
                .while(StoreActions.Getting)
                .throwIf(territory)
                .isUndefined(undefinedMessage("territory", id, state[STATE_SECURITY_TERRITORIES].index));

            return territory;
        };
    },
    [GETTER_SECURITY_TYPE]: (state) => {
        return (id: number) => {
            const type = findById(state[STATE_SECURITY_TYPES], id);

            storeActionValidator
                .begin()
                .while(StoreActions.Getting)
                .throwIf(type)
                .isUndefined(undefinedMessage("type", id, state[STATE_SECURITY_TYPES].index));

            return type;
        };
    },
    [GETTER_SECURITY_TYPES]: (state) => {
        return findAll(state[STATE_SECURITY_TYPES]);
    },
};
...
src ⟩ store ⟩ security-module.ts

security-module.ts (20:29)

...
export const securitiesMutations: StoreMutationTree = {
    [MUTATION_ADD_SECURITY](state, payload: PayloadAddSecurity) {
        add(state[STATE_SECURITIES], payload, (x) => x.symbol);
    },
    [MUTATION_ADD_SECURITY_CATEGORY](state, payload: PayloadAddSecurityCategory) {
        add(state[STATE_SECURITY_CATEGORIES], payload, (x) => x.text);
    },
    [MUTATION_ADD_SECURITY_MARKET](state, payload: PayloadAddSecurityMarket) {
        add(state[STATE_SECURITY_MARKETS], payload, (x) => x.text);
    },
    [MUTATION_ADD_SECURITY_SEGMENT](state, payload: PayloadAddSecuritySegment) {
        add(state[STATE_SECURITY_SEGMENTS], payload, (x) => x.text);
    },
    [MUTATION_ADD_SECURITY_TERRITORY](state, payload: PayloadAddSecurityTerritory) {
        add(state[STATE_SECURITY_TERRITORIES], payload, (x) => x.text);
    },
    [MUTATION_ADD_SECURITY_TYPE](state, payload: PayloadAddSecurityType) {
        add(state[STATE_SECURITY_TYPES], payload, (x) => x.text);
    },
    [MUTATION_UPDATE_SECURITY](storeState, payload: PayloadUpdateSecurity) {
        const state = storeState[STATE_SECURITIES];
        const security = findById(state, payload.id)!;

        storeActionValidator
            .begin()
            .while(StoreActions.Updating)
            .throwIf(security)
            .isUndefined(undefinedMessage("security", payload.id, state.index));

        security.categoryId = payload.categoryId;
        security.last = payload.last;
        security.marketId = payload.marketId;
        security.recommendation = payload.recommendation;
        security.symbol = payload.symbol;

        formatSecurity(security);
        state.items = sort(state.items, (x) => x.symbol);
    },
    [MUTATION_UPDATE_SECURITY_CATEGORY](storeState, payload: PayloadUpdateSecurityCategory) {
        const state = storeState[STATE_SECURITY_CATEGORIES];
        const category = findById(state, payload.id)!;

        storeActionValidator
            .begin()
            .while(StoreActions.Updating)
            .throwIf(category)
            .isUndefined(undefinedMessage("category", payload.id, state.index));

        category.segmentId = payload.segmentId;
        category.territoryId = payload.territoryId;
        category.typeId = payload.typeId;

        state.items = sort(state.items, (x) => x.text);
    },
    [MUTATION_UPDATE_SECURITY_MARKET](storeState, payload: PayloadUpdateSecurityMarket) {
        const state = storeState[STATE_SECURITY_MARKETS];
        const market = findById(state, payload.id)!;

        storeActionValidator
            .begin()
            .while(StoreActions.Updating)
            .throwIf(market)
            .isUndefined(undefinedMessage("market", payload.id, state.index));

        market.text = payload.text;

        formatSecurityMarket(market);
        state.items = sort(state.items, (x) => x.text);
    },
    [MUTATION_UPDATE_SECURITY_SEGMENT](storeState, payload: PayloadUpdateSecuritySegment) {
        const state = storeState[STATE_SECURITY_SEGMENTS];
        const segment = findById(state, payload.id)!;

        storeActionValidator
            .begin()
            .while(StoreActions.Updating)
            .throwIf(segment)
            .isUndefined(undefinedMessage("segment", payload.id, state.index));

        segment.text = payload.text;

        state.items = sort(state.items, (x) => x.text);
    },
    [MUTATION_UPDATE_SECURITY_TERRITORY](storeState, payload: PayloadUpdateSecurityTerritory) {
        const state = storeState[STATE_SECURITY_TERRITORIES];
        const territory = findById(state, payload.id)!;

        storeActionValidator
            .begin()
            .while(StoreActions.Updating)
            .throwIf(territory)
            .isUndefined(undefinedMessage("territory", payload.id, state.index));

        territory.text = payload.text;

        state.items = sort(state.items, (x) => x.text);
    },
    [MUTATION_UPDATE_SECURITY_TYPE](storeState, payload: PayloadUpdateSecurityType) {
        const state = storeState[STATE_SECURITY_TYPES];
        const type = findById(state, payload.id)!;

        storeActionValidator
            .begin()
            .while(StoreActions.Updating)
            .throwIf(type)
            .isUndefined(undefinedMessage("type", payload.id, state.index));

        type.text = payload.text;

        state.items = sort(state.items, (x) => x.text);
    },
};
...
src ⟩ store ⟩ security-module.ts

SecuritiesDetails.vue (23:07)

<script lang="ts">
...
import {
    ACTION_ADD_SECURITY,
    ACTION_ADD_SECURITY_CATEGORY,
    ACTION_ADD_SECURITY_MARKET,
    ACTION_ADD_SECURITY_SEGMENT,
    ACTION_ADD_SECURITY_TERRITORY,
    ACTION_ADD_SECURITY_TYPE,
    ...
    PayloadAddSecurity,
    PayloadAddSecurityCategory,
    PayloadAddSecurityMarket,
    PayloadAddSecuritySegment,
    PayloadAddSecurityTerritory,
    PayloadAddSecurityType,
    ...
} from "@/store";
...
export default class SecuritiesDetails extends Vue {
    @Action(ACTION_ADD_SECURITY) private readonly addSecurity!: ActionFn<PayloadAddSecurity>;
    @Action(ACTION_ADD_SECURITY_CATEGORY) private readonly addCategory!: ActionFn<PayloadAddSecurityCategory>;
    @Action(ACTION_ADD_SECURITY_MARKET) private readonly addMarket!: ActionFn<PayloadAddSecurityMarket>;
    @Action(ACTION_ADD_SECURITY_SEGMENT) private readonly addSegment!: ActionFn<PayloadAddSecuritySegment>;
    @Action(ACTION_ADD_SECURITY_TERRITORY) private readonly addTerritory!: ActionFn<PayloadAddSecurityTerritory>;
    @Action(ACTION_ADD_SECURITY_TYPE) private readonly addType!: ActionFn<PayloadAddSecurityType>;
    ...
    private save() {
        switch (this.which) {
            case SecurityDescriptors.Categories:
                ...
                switch (this.id) {
                    case 0:
                        this.addCategory(category);
                        return;
                    ...
                }
                return;
            case SecurityDescriptors.Markets:
                ...
                switch (this.id) {
                    case 0:
                        this.addMarket(market);
                        return;
                    ...
                }
                return;
            case SecurityDescriptors.Securities:
                ...
                switch (this.id) {
                    case 0:
                        this.addSecurity(security);
                        return;
                    ...
                }
                return;
            case SecurityDescriptors.Segments:
                ...
                switch (this.id) {
                    case 0:
                        this.addSegment(segment);
                        return;
                    ...
                }
                return;
            case SecurityDescriptors.Territories:
                ...
                switch (this.id) {
                    case 0:
                        this.addTerritory(territory);
                        return;
                    ...
                }
                return;
            case SecurityDescriptors.Types:
                ...
                switch (this.id) {
                    case 0:
                        this.addType(type);
                        return;
                    ...
                }
                return;
        }
    }
}
</script>
src ⟩ views ⟩ SecuritiesDetails.vue

Exciton Interactive LLC
Advertisement