-
Notifications
You must be signed in to change notification settings - Fork 649
POC: Dynamically generated Backend service #9503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
1 Skipped Deployment
|
Create the hooks dynamically out of the query definitions and expose them from a singleton class. The rules service consumes this
ed502e6
to
b4fda64
Compare
function getMutationEndpointMap(builder: CustomBuilder) { | ||
return { | ||
createWorkspaceRule: createMutationEndpoint< | ||
WorkspaceRule, | ||
{ projectId: string; request: CreateRuleRequest } | ||
>(builder, 'create_workspace_rule', () => [invalidatesList(ReduxTag.WorkspaceRules)]), | ||
deleteWorkspaceRule: createMutationEndpoint< | ||
void, | ||
{ projectId: string; ruleId: WorkspaceRuleId } | ||
>(builder, 'delete_workspace_rule', () => [invalidatesList(ReduxTag.WorkspaceRules)]), | ||
updateWorkspaceRule: createMutationEndpoint< | ||
WorkspaceRule, | ||
{ projectId: string; request: UpdateRuleRequest } | ||
>(builder, 'update_workspace_rule', (result) => | ||
result | ||
? [ | ||
invalidatesItem(ReduxTag.WorkspaceRules, result.id), | ||
invalidatesList(ReduxTag.WorkspaceRules) | ||
] | ||
: [] | ||
) | ||
} satisfies EndpointMap; | ||
} | ||
|
||
function getQueryEndpointMap(builder: CustomBuilder) { | ||
return { | ||
listWorkspaceRules: createQueryEndpointWithTransform< | ||
WorkspaceRule[], | ||
{ projectId: string }, | ||
EntityState<WorkspaceRule, WorkspaceRuleId> | ||
>( | ||
builder, | ||
'list_workspace_rules', | ||
(response: WorkspaceRule[]) => { | ||
return workspaceRulesAdapter.addMany(workspaceRulesAdapter.getInitialState(), response); | ||
}, | ||
(result) => providesItems(ReduxTag.WorkspaceRules, result?.ids ?? []) | ||
) | ||
} satisfies EndpointMap; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So first we defined the endpoints.
The injection happens for queries and mutations separately in order to preserve the type safety when iterating over the entries
private constructor(backendApi: BackendApi) { | ||
this.mutationApi = injectMutationEndpoints(backendApi); | ||
this.queryApi = injectQueryEndpoints(backendApi); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We then store them in private properties
get() { | ||
// Mutations | ||
type MutationEndpoints = typeof this.mutationApi.endpoints; | ||
|
||
type MutateMap = { | ||
[K in keyof MutationEndpoints as `${K}Mutate`]: MutationEndpoints[K]['mutate']; | ||
}; | ||
|
||
type UseMutationMap = { | ||
[K in keyof MutationEndpoints as `${K}UseMutation`]: MutationEndpoints[K]['useMutation']; | ||
}; | ||
|
||
const mutate = typedFromEntries( | ||
typedEntries(this.mutationApi.endpoints).map( | ||
([key, value]) => [`${key}Mutate`, value.mutate] as const | ||
) | ||
) as MutateMap; | ||
|
||
const useMutation = typedFromEntries( | ||
typedEntries(this.mutationApi.endpoints).map( | ||
([key, value]) => [`${key}UseMutation`, value.useMutation] as const | ||
) | ||
) as UseMutationMap; | ||
|
||
// Queries | ||
type QueryEndpoints = typeof this.queryApi.endpoints; | ||
|
||
type UseQueryMap = { | ||
[K in keyof QueryEndpoints as `${K}UseQuery`]: (typeof this.queryApi.endpoints)[K]['useQuery']; | ||
}; | ||
|
||
type FetchMap = { | ||
[K in keyof QueryEndpoints as `${K}Fetch`]: (typeof this.queryApi.endpoints)[K]['fetch']; | ||
}; | ||
|
||
const useQuery = typedFromEntries( | ||
typedEntries(this.queryApi.endpoints).map( | ||
([key, value]) => [`${key}UseQuery`, value.useQuery] as const | ||
) | ||
) as UseQueryMap; | ||
|
||
const fetchMap = typedFromEntries( | ||
typedEntries(this.queryApi.endpoints).map( | ||
([key, value]) => [`${key}Fetch`, value.fetch] as const | ||
) | ||
) as FetchMap; | ||
|
||
return { | ||
...mutate, | ||
...useMutation, | ||
...useQuery, | ||
...fetchMap | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And then, out of the endpoint entries, we generate the map of functions
this.api = injectEndpoints(backendApi); | ||
this.backendService = BackendService.getInstance(backendApi); | ||
this.apis = this.backendService.get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The backend service here is consumed as a singleton
return this.apis.listWorkspaceRulesUseQuery( | ||
{ projectId }, | ||
{ transform: (result) => workspaceRulesSelectors.selectAll(result) } | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the result is transformed into an entity state instance, we need to select it when consuming it.
Create the hooks dynamically out of the query definitions and expose them from a singleton class. The rules service consumes this