mirror of
https://github.com/the-draupnir-project/Draupnir.git
synced 2026-08-28 13:24:04 +00:00
Make the node state delta authoritative in existing projections.
https://github.com/the-draupnir-project/planning/issues/123
This commit is contained in:
+33
-19
@@ -39,14 +39,17 @@ export type MemberBanInputProjectionNode = ProjectionNode<
|
||||
> &
|
||||
MembershipPolicyRevision;
|
||||
|
||||
export interface MemberBanIntentProjectionDelta {
|
||||
ban: StringUserID[];
|
||||
recall: StringUserID[];
|
||||
}
|
||||
|
||||
// use add/remove for steady state intents
|
||||
// When the intent becomes effectual, matches will be removed
|
||||
// upstream and so this model will remain consistent
|
||||
export interface MemberBanIntentProjectionDelta {
|
||||
export interface MemberBanIntentProjectionStateDelta {
|
||||
add: MemberPolicyMatch[];
|
||||
remove: MemberPolicyMatch[];
|
||||
ban: StringUserID[];
|
||||
recall: StringUserID[];
|
||||
}
|
||||
|
||||
function isPolicyRelevant(policy: LiteralPolicyRule | GlobPolicyRule): boolean {
|
||||
@@ -59,7 +62,7 @@ function isPolicyRelevant(policy: LiteralPolicyRule | GlobPolicyRule): boolean {
|
||||
export type MemberBanIntentProjectionNode = ProjectionNode<
|
||||
[MemberBanInputProjectionNode],
|
||||
MemberBanIntentProjectionDelta,
|
||||
undefined,
|
||||
MemberBanIntentProjectionStateDelta,
|
||||
{
|
||||
allMembersWithRules(): MemberPolicyMatches[];
|
||||
allRulesMatchingMember(
|
||||
@@ -71,8 +74,8 @@ export type MemberBanIntentProjectionNode = ProjectionNode<
|
||||
export const MemberBanIntentProjectionNodeHelper = Object.freeze({
|
||||
reduceMembershipPolicyDelta(
|
||||
input: MembershipPolicyRevisionDelta
|
||||
): Pick<MemberBanIntentProjectionDelta, "add" | "remove"> {
|
||||
const output: Pick<MemberBanIntentProjectionDelta, "add" | "remove"> = {
|
||||
): MemberBanIntentProjectionStateDelta {
|
||||
const output: MemberBanIntentProjectionStateDelta = {
|
||||
add: [],
|
||||
remove: [],
|
||||
};
|
||||
@@ -89,7 +92,7 @@ export const MemberBanIntentProjectionNodeHelper = Object.freeze({
|
||||
return output;
|
||||
},
|
||||
reduceIntentDelta(
|
||||
input: Pick<MemberBanIntentProjectionDelta, "add" | "remove">,
|
||||
input: MemberBanIntentProjectionStateDelta,
|
||||
policies: PersistentMap<
|
||||
StringUserID,
|
||||
List<LiteralPolicyRule | GlobPolicyRule>
|
||||
@@ -102,7 +105,6 @@ export const MemberBanIntentProjectionNodeHelper = Object.freeze({
|
||||
(rule) => rule.entity as StringUserID
|
||||
);
|
||||
return {
|
||||
...input,
|
||||
ban: intents.intend,
|
||||
recall: intents.recall,
|
||||
};
|
||||
@@ -138,23 +140,28 @@ export class StandardMemberBanIntentProjectionNode implements MemberBanIntentPro
|
||||
|
||||
reduceInput(
|
||||
input: ExtractInputDeltaShapes<[MemberBanInputProjectionNode]>
|
||||
): ProjectionNodeDelta<MemberBanIntentProjectionDelta, undefined> {
|
||||
): ProjectionNodeDelta<
|
||||
MemberBanIntentProjectionDelta,
|
||||
MemberBanIntentProjectionStateDelta
|
||||
> {
|
||||
const nodeStateDelta =
|
||||
MemberBanIntentProjectionNodeHelper.reduceMembershipPolicyDelta(input);
|
||||
return {
|
||||
downstreamDelta: MemberBanIntentProjectionNodeHelper.reduceIntentDelta(
|
||||
MemberBanIntentProjectionNodeHelper.reduceMembershipPolicyDelta(input),
|
||||
nodeStateDelta,
|
||||
this.intents
|
||||
),
|
||||
nodeStateDelta: undefined,
|
||||
nodeStateDelta,
|
||||
};
|
||||
}
|
||||
|
||||
reduceDelta(
|
||||
projectionNodeDelta: ProjectionNodeDelta<
|
||||
MemberBanIntentProjectionDelta,
|
||||
undefined
|
||||
MemberBanIntentProjectionStateDelta
|
||||
>
|
||||
): MemberBanIntentProjectionNode {
|
||||
const input = projectionNodeDelta.downstreamDelta;
|
||||
const input = projectionNodeDelta.nodeStateDelta;
|
||||
let nextIntents = this.intents;
|
||||
nextIntents = ListMultiMap.addValues(
|
||||
nextIntents,
|
||||
@@ -174,7 +181,10 @@ export class StandardMemberBanIntentProjectionNode implements MemberBanIntentPro
|
||||
|
||||
reduceInitialInputs([membershipPolicyRevision]: [
|
||||
MemberBanInputProjectionNode,
|
||||
]): ProjectionNodeDelta<MemberBanIntentProjectionDelta, undefined> {
|
||||
]): ProjectionNodeDelta<
|
||||
MemberBanIntentProjectionDelta,
|
||||
MemberBanIntentProjectionStateDelta
|
||||
> {
|
||||
if (!this.isEmpty()) {
|
||||
throw new TypeError(
|
||||
"This can only be called on an empty projection node"
|
||||
@@ -183,17 +193,21 @@ export class StandardMemberBanIntentProjectionNode implements MemberBanIntentPro
|
||||
const matches = membershipPolicyRevision
|
||||
.allMembersWithRules()
|
||||
.map((member) =>
|
||||
member.policies.map((policy) => ({ userID: member.userID, policy }))
|
||||
member.policies
|
||||
.filter(isPolicyRelevant)
|
||||
.map((policy) => ({ userID: member.userID, policy }))
|
||||
)
|
||||
.flat();
|
||||
const nodeStateDelta = {
|
||||
add: matches,
|
||||
remove: [],
|
||||
};
|
||||
return {
|
||||
downstreamDelta: {
|
||||
add: matches,
|
||||
ban: matches.map((match) => match.userID),
|
||||
remove: [],
|
||||
ban: [...new Set(matches.map((match) => match.userID))],
|
||||
recall: [],
|
||||
},
|
||||
nodeStateDelta: undefined,
|
||||
nodeStateDelta,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+27
-15
@@ -31,6 +31,9 @@ import { ListMultiMap } from "../../../Projection/ListMultiMap";
|
||||
export type ServerBanIntentProjectionDelta = {
|
||||
deny: StringServerName[];
|
||||
recall: StringServerName[];
|
||||
};
|
||||
|
||||
export type ServerBanIntentProjectionStateDelta = {
|
||||
add: (LiteralPolicyRule | GlobPolicyRule)[];
|
||||
remove: (LiteralPolicyRule | GlobPolicyRule)[];
|
||||
};
|
||||
@@ -41,7 +44,7 @@ export type ServerBanIntentProjectionDelta = {
|
||||
export type ServerBanIntentProjectionNode = ProjectionNode<
|
||||
[PolicyListBridgeProjectionNode],
|
||||
ServerBanIntentProjectionDelta,
|
||||
undefined,
|
||||
ServerBanIntentProjectionStateDelta,
|
||||
{
|
||||
deny: StringServerName[];
|
||||
}
|
||||
@@ -50,11 +53,11 @@ export type ServerBanIntentProjectionNode = ProjectionNode<
|
||||
export const ServerBanIntentProjectionHelper = Object.freeze({
|
||||
reducePolicyDelta(
|
||||
input: PolicyRuleChange[]
|
||||
): Pick<ServerBanIntentProjectionDelta, "add" | "remove"> {
|
||||
const output: Pick<ServerBanIntentProjectionDelta, "add" | "remove"> = {
|
||||
): ServerBanIntentProjectionStateDelta {
|
||||
const output: ServerBanIntentProjectionStateDelta = {
|
||||
add: [],
|
||||
remove: [],
|
||||
} satisfies Pick<ServerBanIntentProjectionDelta, "add" | "remove">;
|
||||
};
|
||||
for (const change of input) {
|
||||
if (change.rule.kind !== PolicyRuleType.Server) {
|
||||
continue;
|
||||
@@ -85,7 +88,7 @@ export const ServerBanIntentProjectionHelper = Object.freeze({
|
||||
},
|
||||
|
||||
reduceIntentDelta(
|
||||
input: Pick<ServerBanIntentProjectionDelta, "add" | "remove">,
|
||||
input: ServerBanIntentProjectionStateDelta,
|
||||
policies: PersistentMap<
|
||||
StringServerName,
|
||||
List<GlobPolicyRule | LiteralPolicyRule>
|
||||
@@ -98,7 +101,6 @@ export const ServerBanIntentProjectionHelper = Object.freeze({
|
||||
(rule) => rule.entity as StringServerName
|
||||
);
|
||||
return {
|
||||
...input,
|
||||
deny: intents.intend,
|
||||
recall: intents.recall,
|
||||
};
|
||||
@@ -128,19 +130,27 @@ export class StandardServerBanIntentProjectionNode implements ServerBanIntentPro
|
||||
|
||||
reduceInput(
|
||||
input: PolicyRuleChange[]
|
||||
): ProjectionNodeDelta<ServerBanIntentProjectionDelta, undefined> {
|
||||
): ProjectionNodeDelta<
|
||||
ServerBanIntentProjectionDelta,
|
||||
ServerBanIntentProjectionStateDelta
|
||||
> {
|
||||
const nodeStateDelta =
|
||||
ServerBanIntentProjectionHelper.reducePolicyDelta(input);
|
||||
return {
|
||||
downstreamDelta: ServerBanIntentProjectionHelper.reduceIntentDelta(
|
||||
ServerBanIntentProjectionHelper.reducePolicyDelta(input),
|
||||
nodeStateDelta,
|
||||
this.policies
|
||||
),
|
||||
nodeStateDelta: undefined,
|
||||
nodeStateDelta,
|
||||
};
|
||||
}
|
||||
|
||||
reduceInitialInputs([policyListRevision]: [
|
||||
PolicyListBridgeProjectionNode,
|
||||
]): ProjectionNodeDelta<ServerBanIntentProjectionDelta, undefined> {
|
||||
]): ProjectionNodeDelta<
|
||||
ServerBanIntentProjectionDelta,
|
||||
ServerBanIntentProjectionStateDelta
|
||||
> {
|
||||
if (!this.isEmpty()) {
|
||||
throw new TypeError("Cannot reduce initial inputs when inialised");
|
||||
}
|
||||
@@ -156,14 +166,16 @@ export class StandardServerBanIntentProjectionNode implements ServerBanIntentPro
|
||||
].filter((rule) => rule.matchType !== PolicyRuleMatchType.HashedLiteral);
|
||||
const names = new Set(serverPolicies.map((policy) => policy.entity));
|
||||
const downstreamDelta = {
|
||||
add: serverPolicies,
|
||||
deny: [...names] as StringServerName[],
|
||||
remove: [],
|
||||
recall: [],
|
||||
};
|
||||
const nodeStateDelta = {
|
||||
add: serverPolicies,
|
||||
remove: [],
|
||||
};
|
||||
return {
|
||||
downstreamDelta,
|
||||
nodeStateDelta: undefined,
|
||||
nodeStateDelta,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -172,10 +184,10 @@ export class StandardServerBanIntentProjectionNode implements ServerBanIntentPro
|
||||
}
|
||||
|
||||
reduceDelta({
|
||||
downstreamDelta: input,
|
||||
nodeStateDelta: input,
|
||||
}: ProjectionNodeDelta<
|
||||
ServerBanIntentProjectionDelta,
|
||||
undefined
|
||||
ServerBanIntentProjectionStateDelta
|
||||
>): ServerBanIntentProjectionNode {
|
||||
let nextPolicies = this.policies;
|
||||
nextPolicies = ListMultiMap.addValues(
|
||||
|
||||
Reference in New Issue
Block a user