I have 4 functions, for 1st three functions, I can send the data in provide. For 4th function(
getViewApplicationDetails
), I am trying to fetch api and get application name, now I want that in mounted because, I want the application name as soon as component is rendered so I am trying to execute it in mounted but when I call the it, it's giving me error. Initially application name is empty and it should have the current application name when I fetch the api, the same application name will be used in provide and then I can use that in inject and then in any other component.
import { computed, inject, onMounted, provide, reactive } from "vue";
export const initStore = () => {
onMounted(()=>{
this.getViewApplicationDetails()
});
// State
const state = reactive({
name: "Bob Day",
email: "bob#martianmovers.com",
applicationName: "",
breadcrumbsData: [
{
name: "Home",
text: 'Home',
disabled: false,
href: '/'
}
]
});
// Getters
const getUsername = computed(() => state.name);
const getEmail = computed(() => console.log("state.email",state.email));
const getBreadcrumbsData=computed(()=>state.breadcrumbsData)
console.log("state.applicationName",state.applicationName)
//this is the temporary function
const getApplicationName=computed(()=>state.applicationName)
const getViewApplicationDetails=computed(()=> {
var viewApplicationDetailsParams = {
applicationId: this.$route.query.applicationId,
applicationStatus:this.$route.query.appStatus,
authType: "api",
clientId: process.env.VUE_APP_EXTERNAL_API_CLIENT_ID,
clientSecret: process.env.VUE_APP_EXTERNAL_API_CLIENT_SECRET
};
axios({
method: "post",
url: process.env.VUE_APP_BLUJ_BACKEND_URL + "/viewapplicationDefinition",
data: viewApplicationDetailsParams,
headers: {
"content-type": "application/json",
},
})
.then((response) =>{
this.viewDefinitionResponse = response.data.Definitions;
let applicationName = viewDefinitionResponse.application_display_name.en;
console.log("tyfgyhkjlfhgjklnm",applicationName)
setApplicationName(applicationName)
})
.catch((error) => {
console.log("error", error);
});
});
getViewApplicationDetails()
// Mutations
const setUsername = (name) => {
state.name = name;
};
const setEmail = (email) => {
state.email = email;
};
const setBreadCrumbsData=(breadcrumbsData)=>{
state.breadcrumbsData=breadcrumbsData;
}
const setApplicationName=(appName)=>{
state.applicationName=appName
}
// Actions
const updateUsername = (name) => {
setUsername(name);
};
const updateEmail = (email) => {
setEmail(email);
};
provide("getUsername", getUsername);
provide("getEmail", getEmail);
provide("updateUsername", updateUsername);
provide("updateEmail", updateEmail);
provide("getViewApplicationDetails", getViewApplicationDetails);
provide("getApplicationName", getApplicationName);
provide("getBreadcrumbsData", getBreadcrumbsData);
};
export const useStore = () => ({
getUsername: inject("getUsername"),
getEmail: inject("getEmail"),
updateUsername: inject("updateUsername"),
updateEmail: inject("updateEmail"),
viewApplicationDetails: inject("getViewApplicationDetails"),
getBreadcrumbsData: inject("getBreadcrumbsData"),
getApplicationName: inject("getApplicationName")
});
This is the code snippet.
const getUsername = computed(() => state.name);
const getEmail = computed(() => console.log("state.email",state.email));
const getBreadcrumbsData=computed(()=>state.breadcrumbsData)
I am getting data for this, but for getViewApplicationDetails, it's not working. While hovering over rest of the functions, it is showing "const getUsername: ComputedRef", like this. But, for getViewApplicationDetails, it shows "const getViewApplicationDetails: ComputedRef", this. I think it is not taking it as function or something. Error image is in the link.enter image description here
I have a function that returns other functions like so:
export const makeAudienceDb = () => {
async function insert({ ...params }: AudienceAttributes) {
const audience = await AudienceModel.create({ ...params })
const audienceToJson = audience.toJSON()
return audienceToJson
}
async function findById({ id }: { id: number }) {
const user = await AudienceModel.findByPk(id)
return user?.toJSON()
}
async function remove({ id }: { id: number }) {
return AudienceModel.destroy({ where: { id } })
}
async function update({
id,
...changes
}: { id: number } & AudienceAttributes) {
const updated = await AudienceModel.update(
{ ...changes },
{ where: { id } }
)
return updated
}
return Object.freeze({
insert,
findById,
remove,
update,
})
}
I have other models, e.g UserModel, PostModel which have the same database operations as makeAudienceDb. e.g
export const makeUsersDb = ({ hashPassword, createToken }: DBDeps) => {
async function insert({ ...params }: User) {
if (params.password) {
params.password = await hashPassword(params.password)
}
const newUser = await UserModel.create({ ...params })
const returnedUser = newUser.toJSON()
const { id } = newUser
const { name, username, email, password } = returnedUser as User
const payload = {
id,
email,
}
const token = createToken(payload)
const user = { id, name, username, password, email }
return { user, token }
}
async function findById({ id }: { id: number }) {
const user = await UserModel.findByPk(id)
return user?.toJSON()
}
async function findByEmail({ email }: { email: string }) {
const user = await UserModel.findOne({ where: { email } })
return user?.toJSON()
}
async function remove({ id }: { id: number }) {
return UserModel.destroy({ where: { id } })
}
async function update({ id, ...changes }: { id: number } & User) {
const updated = await UserModel.update({ ...changes }, { where: { id } })
return updated
}
return Object.freeze({
insert,
findByEmail,
findById,
remove,
update,
})
}
This leads to code duplication across various levels. I want to know how to create one major function that I can reuse for other database operations. So instead of me having makeAudienceDb, makeUsersDb, I could just have one major function e.g majorDatabaseOps where makeAudienceDb and makeUsersDb could just inherit from. I know this is possible with ES6 Classes and Interfaces but I was just wondering how I could implement the same in a functional way. Any contribution is welcome. Thank you very much!
It looks like what you are trying to do is bind shortcuts to particular sequelize methods. The shared functionality can be implemented using typescript generics. Overriding specific behaviors, like hashing a password for a User makes this a bit more complex.
My first instinct is to use a class-based approach. But you can do it with functions by copying all of the methods from the base and then overriding or adding specific ones, along these lines:
const userDb = Object.freeze({
...makeDb(UserModel),
findByEmail: async ({email}: {email: string}) => {
}
})
We want to create a function that takes the model as an argument. It will use typescript generics to describe the types associated with that model. The generics will be inferred from the model variable when calling the function.
A sequelize Model has two generic values: TModelAttributes and TCreationAttributes which is optional and defaults to TModelAttributes. We also want to require that all of our model attributes must include {id: number}.
You could potentially add additional typings to get better support for toJSON. The sequelize package just declares the return type from Model.toJSON as object which is vague and unhelpful.
Our general function looks like this:
import {Model, ModelCtor} from "sequelize";
export const makeDb = <TModelAttributes extends {id: number} = any, TCreationAttributes extends {} = TModelAttributes>(
model: ModelCtor<Model<TModelAttributes, TCreationAttributes>>
) => {
async function insert({ ...params }: TCreationAttributes) {
const created = await model.create({ ...params });
return created.toJSON();
}
async function findById({ id }: { id: number }) {
const found = await model.findByPk(id)
return found?.toJSON()
}
async function remove({ id }: { id: number }) {
return model.destroy({ where: { id } })
}
async function update({ ...changes }: { id: number } & Partial<TModelAttributes>) {
const { id } = changes; // I get a TS error when destructuring this in the args
const updated = await model.update(
{ ...changes },
{ where: { id } }
);
return updated;
}
return Object.freeze({
insert,
findById,
remove,
update,
});
}
For audience, you would simply call:
const audienceDb = makeDb(AudienceModel);
Or you could define it as a function if you wanted to:
const makeAudienceDb = () => makeDb(AudienceModel);
For the users database, we need to override insert, add findByEmail, and take additional arguments hashPassword and createToken.
This is not elegant, but it should work. I don't love that your return type for user insert is incompatible with the insert returned value from the general makeDb.
export const makeUsersDb = ({ hashPassword, createToken }: DBDeps) => {
// declaring this up top so that you could call methods on it in your overrides
const db = makeDb(UserModel);
async function insert({ ...params }: User) {
if (params.password) {
params.password = await hashPassword(params.password)
}
const newUser = await UserModel.create({ ...params })
const returnedUser = newUser.toJSON()
const { id } = newUser
const { name, username, email, password } = returnedUser as User
const payload = {
id,
email,
}
const token = createToken(payload)
const user = { id, name, username, password, email }
return { user, token }
}
async function findByEmail({ email }: { email: string }) {
const user = await UserModel.findOne({ where: { email } })
return user?.toJSON()
}
return Object.freeze({
...db,
insert,
findByEmail
})
}
How about defining the common functions outside of the majorDatabaseOps function? Will let you reuse them in different places.
//defined outside for reusability
function findById(model, id) {
return model.findByPk(id)
}
const majorDatabaseOps = model => {
function removeById(model, id) {
return model.remove(id);
}
return Object.freeze({
removeById: id => removeById(model, id),
findById: id => findById(model, id),
})
}
//mocking models for demonstration
const UserModel = {
modelName: "UserModel",
findByPk: function(id) {
return console.log(id + " was found in " + this.modelName)
},
remove: function(id) {
return console.log(id + " was removed from " + this.modelName)
}
}
const PostModel = {
modelName: "PostModel",
findByPk: function(id) {
return console.log(id + " was found in " + this.modelName)
},
remove: function(id) {
return console.log(id + " was removed from " + this.modelName)
}
}
const userDbOps = majorDatabaseOps(UserModel);
userDbOps.findById(1);
userDbOps.removeById(1);
const postDbOps = majorDatabaseOps(PostModel);
postDbOps.findById(2);
postDbOps.removeById(2);
I'm using apollo's HoCs to achieve my current mutation, but I'm a bit confused on a few errors I'm getting:
this is my query:
import gql from 'graphql-tag';
import { careTeamMember } from '../../fragments/careProvider';
const getFullMemberDetails = gql`
query getFullMemberDetails($id: ID!) {
member(id: $id) {
id
created_at
date_of_birth
first_name
last_name
name
email
phone
verified
informed_consent
// ....
}
}
${careTeamMember}`;
export default getFullMemberDetails;
these are my mutations:
import gql from 'graphql-tag';
const updateMember = gql`
mutation UpdateMember($input: UpdateMemberInput!) {
updateMember(input: $input) {
success
member {
id
name
first_name
last_name
email
phone
date_of_birth
informed_consent
hipaa_privacy_policy
check_in_frequency_days
}
}
}
`;
export default updateMember;
import gql from 'graphql-tag';
const updateMemberInsurancePolicy = gql`
mutation UpdateMemberInsurancePolicy(
$member_id: ID!,
$carrier_name: String,
$insurance_member_id: String,
$insurance_group_id: String,
$plan_name: String,
) {
updateMemberInsurancePolicy(
member_id: $member_id,
carrier_name: $carrier_name,
insurance_member_id: $insurance_member_id,
insurance_group_id: $insurance_group_id,
plan_name: $plan_name,
) {
member_insurance_policy {
id
carrier_name
insurance_group_id
insurance_member_id
plan_name
member {
id
previsit {
id
can_schedule
}
}
}
success
}
}
`;
export default updateMemberInsurancePolicy;
and being used like this
handleMemberSubmit = async (formData): Promise<any> => {
try {
const payload = {
id : this.props.data.member.id,
patch : {
first_name : formData.first_name,
last_name : formData.last_name,
date_of_birth : formData.date_of_birth,
phone : formData.phone,
// ....
payment_preference : formData.payment_preference ? 'OUT_OF_POCKET' : 'INSURANCE',
},
};
const insurancePayload = {
member_id : this.props.data.member.id,
carrier_name : formData.insurance_policy.carrier_name,
plan_name : formData.insurance_policy.plan_name,
insurance_group_id : formData.insurance_policy.insurance_group_id,
insurance_member_id : formData.insurance_policy.insurance_member_id,
};
const [
updateMemberResponse,
submitInsuranceResponse,
] = await Promise.all([
this.props.updateMember(payload),
this.props.submitInsurance(insurancePayload),
]);
const { data: { updateMember } } = updateMemberResponse;
const { data: { updateMemberInsurancePolicy } } = submitInsuranceResponse;
return this.props.addNotification('Member updated!', 'success');
} catch (err) {
return this.props.addNotification(getFirstError(err), 'error');
}
}
and the HoC
graphql(getFullMemberDetails, {
options: (ownProps): Object => ({
id: ownProps.id,
}),
}),
graphql(updateMember, {
props: ({ mutate }): {updateMember: (input: Object) => Promise<any> } => ({
updateMember: (input): Promise<any> => mutate({
variables : { input },
options : (props): Object => ({
refetchQueries: [{
query : getFullMemberDetails,
variables : { id: props.id },
}],
}),
}),
}),
}),
graphql(updateMemberInsurance, {
props: ({ mutate }): {submitInsurance: () => {}} => ({
submitInsurance: (input): Promise<any> => mutate({
variables: { ...input },
}),
}),
}),
This async method works fine, but the getFullMemberDetails query doesn't run after those two queries finish.
However, when I move refetchQueries outside of options in the HoC, like this:
graphql(updateMember, {
props: ({ mutate, ownProps }): {updateMember: (input: Object) => Promise<any> } => ({
updateMember: (input): Promise<any> => mutate({
variables : { input },
refetchQueries: [{
query : getFullMemberDetails,
variables : { id: ownProps.id },
}],
}),
}),
}),
my getFullMemberDetails does run, but i get an error like this:
{"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getFullMemberDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"member"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"created_at"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"date_of_birth"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"first_name"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"last_name"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"name"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"email"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"phone"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"verified"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"informed_consent"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"postal_address"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"street_address_1"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"street_address_2"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"city"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"state"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"zip_code"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"country"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"time_zone"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"calendar"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cohort"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"name"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"customer"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"name"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"basic_visits_covered"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"specialist_visits_covered"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"dependents_allowed"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"contract_term"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start_at"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"end_at"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"in_person_supported"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}},{"kind":"Field","name":{"kind":"Name","value":"care_team"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"},"arguments":[],"directives":[]},{"kind":"Field","name":{"kind":"Name","value":"care_navigator"},"arguments":[],"directives":[],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Frabundle.esm.js:63)
at bundle.esm.js:1246
at bundle.esm.js:1558
at Set.forEach (<anonymous>)
at bundle.esm.js:1556
at Map.forEach (<anonymous>)
at QueryManager.push.../../../node_modules/apollo-client/bundle.esm.js.QueryManager.broadcastQueries (bundle.esm.js:1554)
at bundle.esm.js:1160
and my cache/props doesn't get updated. Is there something I'm doing wrong?