@media-quest/builder 0.0.24 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/package.json +15 -15
  2. package/src/Builder-option.ts +6 -8
  3. package/src/Builder-page.spec.ts +162 -320
  4. package/src/Builder-page.ts +182 -257
  5. package/src/Builder-question.spec.ts +57 -57
  6. package/src/Builder-question.ts +83 -82
  7. package/src/Builder-schema.spec.ts +96 -124
  8. package/src/Builder-schema.ts +25 -15
  9. package/src/Builder-text.spec.ts +11 -11
  10. package/src/Builder-text.ts +13 -13
  11. package/src/BuilderObject.ts +2 -33
  12. package/src/BuilderTag.ts +19 -20
  13. package/src/builder-compiler.ts +1 -1
  14. package/src/code-book/codebook-variable.ts +29 -0
  15. package/src/{codebook.ts → code-book/codebook.ts} +16 -16
  16. package/src/primitives/ID.spec.ts +39 -0
  17. package/src/primitives/ID.ts +138 -0
  18. package/src/primitives/page-prefix.ts +4 -3
  19. package/src/primitives/varID.ts +1 -0
  20. package/src/public-api.ts +28 -24
  21. package/src/rulebuilder/Builder-rule.spec.ts +3 -2
  22. package/src/rulebuilder/Builder-rule.ts +2 -1
  23. package/src/rulebuilder/RuleBuilder-test-utils.ts +12 -8
  24. package/src/rulebuilder/RuleInput.ts +30 -30
  25. package/src/rulebuilder/RuleVariable.ts +11 -26
  26. package/src/rulebuilder/SingleSelectItem.ts +9 -8
  27. package/src/rulebuilder/condition/Builder-condition-group.ts +14 -6
  28. package/src/rulebuilder/condition/Builder-condition.spec.ts +12 -12
  29. package/src/rulebuilder/condition/Builder-condition.ts +17 -13
  30. package/src/rulebuilder/index.ts +16 -3
  31. package/src/rulebuilder/page-action-manager.ts +4 -2
  32. package/src/rulebuilder/rule2/Rule2.ts +8 -8
  33. package/src/schema-config.ts +2 -2
  34. package/src/sum-score/sum-score-answer.ts +6 -0
  35. package/src/sum-score/sum-score-manager.spec.ts +189 -0
  36. package/src/sum-score/sum-score-manager.ts +154 -0
  37. package/src/sum-score/sum-score-membership.ts +45 -0
  38. package/src/sum-score/sum-score-variable.spec.ts +151 -0
  39. package/src/sum-score/sum-score-variable.ts +36 -0
  40. package/src/{variable → sum-score}/sum-score.ts +122 -138
  41. package/tsconfig.tsbuildinfo +1 -1
  42. package/src/variable/mq-variable.spec.ts +0 -146
  43. package/src/variable/mq-variable.ts +0 -68
@@ -1,4 +1,4 @@
1
- import { PredefinedVariable } from "./variable/mq-variable";
1
+ import { CodebookPredefinedVariable } from "./code-book/codebook-variable";
2
2
  import { BuilderSchemaDto } from "./Builder-schema";
3
3
 
4
4
  /**
@@ -9,7 +9,7 @@ export interface SchemaConfig {
9
9
  readonly schemaName: string;
10
10
  readonly schemaId: string;
11
11
  readonly schemaPrefix: string;
12
- readonly variables: ReadonlyArray<Readonly<PredefinedVariable>>;
12
+ readonly variables: ReadonlyArray<CodebookPredefinedVariable>;
13
13
  }
14
14
 
15
15
  export const SchemaConfig = {
@@ -0,0 +1,6 @@
1
+ export interface SumScoreAnswer {
2
+ readonly varId: string;
3
+ readonly varLabel: string;
4
+ readonly value: number;
5
+ readonly valueLabel: string;
6
+ }
@@ -0,0 +1,189 @@
1
+ import { SumScoreVariableDto } from "./sum-score-variable";
2
+ import { SumScoreMemberShipID, SumScoreVariableID } from "../primitives/ID";
3
+ import { SumScoreAnswer } from "./sum-score-answer";
4
+ import { SumScoreManager } from "./sum-score-manager";
5
+ import { SumScoreMembershipDto } from "./sum-score-membership";
6
+
7
+ const createAnswer = (value: number): SumScoreAnswer => {
8
+ const varId = "v" + value;
9
+ const varLabel = "label for " + varId;
10
+ const valueLabel = "label for value " + value;
11
+ return {
12
+ varId,
13
+ varLabel,
14
+ value,
15
+ valueLabel,
16
+ };
17
+ };
18
+
19
+ const a0 = createAnswer(0);
20
+ const a1 = createAnswer(1);
21
+ const a2 = createAnswer(2);
22
+ const a3 = createAnswer(3);
23
+ const a4 = createAnswer(4);
24
+ const a5 = createAnswer(5);
25
+ const a6 = createAnswer(6);
26
+ const a7 = createAnswer(7);
27
+ const a8 = createAnswer(8);
28
+ const a9 = createAnswer(9);
29
+
30
+ const all = [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9];
31
+
32
+ const getData = () => {
33
+ const dep: SumScoreVariableDto = {
34
+ basedOn: [],
35
+ description: "Hvis depresjons index er høyere enn 20, så er det alvorlig.",
36
+ id: SumScoreVariableID.dummy.a,
37
+ name: "Depresjons index",
38
+ useAvg: false,
39
+ };
40
+
41
+ const angst: SumScoreVariableDto = {
42
+ basedOn: [],
43
+ description: "Index for angst. Grenseverdi 28.",
44
+ id: SumScoreVariableID.dummy.d,
45
+ name: "Angst",
46
+ useAvg: false,
47
+ };
48
+
49
+ const depA0: SumScoreMembershipDto = {
50
+ id: SumScoreMemberShipID.create(),
51
+ sumScoreId: dep.id,
52
+ varId: a0.varId,
53
+ weight: 1,
54
+ };
55
+
56
+ const depA1: SumScoreMembershipDto = {
57
+ id: SumScoreMemberShipID.create(),
58
+ sumScoreId: dep.id,
59
+ varId: a1.varId,
60
+ weight: 1,
61
+ };
62
+
63
+ const angstA0: SumScoreMembershipDto = {
64
+ id: SumScoreMemberShipID.create(),
65
+ sumScoreId: dep.id,
66
+ varId: a0.varId,
67
+ weight: 1,
68
+ };
69
+
70
+ const angstA1: SumScoreMembershipDto = {
71
+ id: SumScoreMemberShipID.create(),
72
+ sumScoreId: dep.id,
73
+ varId: a1.varId,
74
+ weight: 1,
75
+ };
76
+
77
+ const angstA5: SumScoreMembershipDto = {
78
+ id: SumScoreMemberShipID.create(),
79
+ sumScoreId: dep.id,
80
+ varId: a5.varId,
81
+ weight: 1,
82
+ };
83
+ return { dep, angst, depA1, depA0, angstA1, angstA0, angstA5 };
84
+ };
85
+
86
+ describe("Sum-score-manager", () => {
87
+ test("Crud for variables work", () => {
88
+ const d = getData();
89
+ const m = SumScoreManager.create([d.dep, d.angst], [d.depA0, d.depA1, d.angstA5]);
90
+ expect(m.memberShips.length).toBe(3);
91
+ expect(m.variables.length).toBe(2);
92
+ const newVar = m.variableAddNew({});
93
+ expect(m.variables.length).toBe(3);
94
+ const newVar2 = m.variableAddNew({
95
+ name: "var 2 name",
96
+ description: "var 2 description",
97
+ useAvg: true,
98
+ });
99
+ expect(m.variables.length).toBe(4);
100
+
101
+ // Will not delete a variable that is not there.
102
+ m.variableDeleteById(SumScoreVariableID.create());
103
+ expect(m.variables.length).toBe(4);
104
+ m.variableDeleteById(d.dep.id);
105
+ expect(m.variables.length).toBe(3);
106
+ });
107
+ test("Can not add same variable twice", () => {
108
+ const d = getData();
109
+ const m = SumScoreManager.create([d.dep, d.angst], [d.depA0, d.depA1, d.angstA5]);
110
+ expect(m.memberShips.length).toBe(3);
111
+ expect(m.variables.length).toBe(2);
112
+ const newVar = m.variableAddNew({});
113
+ expect(m.variables.length).toBe(3);
114
+ const newVar2 = m.variableAddNew({ name: "søvnløshet", description: "", useAvg: true });
115
+ expect(m.variables.length).toBe(4);
116
+
117
+ // Will not delete a variable that is not there.
118
+ m.variableDeleteById(SumScoreVariableID.create());
119
+ expect(m.variables.length).toBe(4);
120
+ m.variableDeleteById(d.dep.id);
121
+ expect(m.variables.length).toBe(3);
122
+ });
123
+
124
+ test("Can update variable", () => {
125
+ const m = SumScoreManager.create([], []);
126
+ const v = m.variableAddNew({});
127
+ expect(m.variables.length).toBe(1);
128
+ expect(v.useAvg).toBe(true);
129
+ // Will update dep
130
+ const updatedName = "Updated name";
131
+ const updatedDescription = "Updated description";
132
+ m.variableUpdate(v.id, {
133
+ name: updatedName,
134
+ description: updatedDescription,
135
+ useAvg: false,
136
+ });
137
+ const updatedVariable = m.variableGetById(v.id) as SumScoreVariableDto;
138
+
139
+ expect(updatedVariable.name).toBe(updatedName);
140
+ expect(updatedVariable.description).toBe(updatedDescription);
141
+ expect(updatedVariable.useAvg).toBe(false);
142
+ });
143
+
144
+ test("Crud membership works", () => {
145
+ const m = SumScoreManager.create([], []);
146
+ const v1 = m.variableAddNew({ name: "V1" });
147
+ const v2 = m.variableAddNew({ name: "V2" });
148
+ expect(m.variables.length).toBe(2);
149
+ const m1 = m.membershipAdd(v1.id, "a") as SumScoreMembershipDto;
150
+ expect(m1).toBeTruthy();
151
+ const m2 = m.membershipAdd(v1.id, "b") as SumScoreMembershipDto;
152
+ expect(m2).toBeTruthy();
153
+ expect(m.memberShips.length).toBe(2);
154
+ const m2_duplicate = m.membershipAdd(v1.id, "b");
155
+ expect(m.memberShips.length).toBe(2);
156
+ expect(m.membershipGetById(m1.id)).toEqual(m1);
157
+ expect(m.membershipGetById(m2.id)).toEqual(m2);
158
+ m.membershipDelete(m2.id);
159
+ expect(m.memberShips.length).toBe(1);
160
+ });
161
+
162
+ test("Get membership by varId works", () => {
163
+ const m = SumScoreManager.create([], []);
164
+ const v1 = m.variableAddNew({ name: "V1" });
165
+ const v2 = m.variableAddNew({ name: "V2" });
166
+ const membership1 = m.membershipAdd(v1.id, "a") as SumScoreMembershipDto;
167
+ const membership2 = m.membershipAdd(v2.id, "a") as SumScoreMembershipDto;
168
+ const membership3 = m.membershipAdd(v1.id, "c") as SumScoreMembershipDto;
169
+
170
+ expect(membership1).toBeTruthy();
171
+ expect(membership2).toBeTruthy();
172
+ expect(membership3).toBeTruthy();
173
+
174
+ expect(m.membershipGetByVarId("a")).toEqual([membership1, membership2]);
175
+ expect(m.membershipGetByVarId("c")).toEqual([membership3]);
176
+ });
177
+
178
+ test("When a variable is deleted, the memberships will be deleted too.", () => {
179
+ const m = SumScoreManager.create([], []);
180
+ const v1 = m.variableAddNew({ name: "V1" });
181
+ const v2 = m.variableAddNew({ name: "V2" });
182
+ const membership1 = m.membershipAdd(v1.id, "a") as SumScoreMembershipDto;
183
+ const membership2 = m.membershipAdd(v2.id, "a") as SumScoreMembershipDto;
184
+ const membership3 = m.membershipAdd(v1.id, "c") as SumScoreMembershipDto;
185
+ expect(m.memberShips.length).toBe(3);
186
+ m.variableDeleteById(v1.id);
187
+ expect(m.membershipGetByVarId("a")).toEqual([membership2]);
188
+ });
189
+ });
@@ -0,0 +1,154 @@
1
+ import { SumScoreVariableDto } from "./sum-score-variable";
2
+ import { SumScoreMemberShipID, SumScoreVariableID } from "../primitives/ID";
3
+ import { SumScoreMembershipDto } from "./sum-score-membership";
4
+ import { DUtil } from "@media-quest/engine";
5
+
6
+ const cloneItem = <const T extends object>(item: T): T => ({ ...item });
7
+
8
+ export class SumScoreManager implements Iterable<SumScoreVariableDto> {
9
+ public static readonly create = (
10
+ variables: Array<SumScoreVariableDto>,
11
+ memberships: Array<SumScoreMembershipDto>,
12
+ ): SumScoreManager => {
13
+ return new SumScoreManager(variables, memberships);
14
+ };
15
+
16
+ private _variables: SumScoreVariableDto[];
17
+ private _memberShips: SumScoreMembershipDto[];
18
+
19
+ private constructor(variables: SumScoreVariableDto[], memberships: SumScoreMembershipDto[]) {
20
+ this._variables = [...variables];
21
+ this._memberShips = [...memberships];
22
+ }
23
+
24
+ get variables(): ReadonlyArray<SumScoreVariableDto> {
25
+ return [...this._variables];
26
+ }
27
+ get memberShips(): ReadonlyArray<SumScoreMembershipDto> {
28
+ return [...this._memberShips];
29
+ }
30
+
31
+ toJson(): { variables: SumScoreVariableDto[]; memberShips: SumScoreMembershipDto[] } {
32
+ const variables = this._variables.map(cloneItem);
33
+ const memberShips = this._memberShips.map(cloneItem);
34
+ return { variables, memberShips };
35
+ }
36
+
37
+ /**
38
+ * Deletes a variable by its ID.
39
+ * @param {SumScoreVariableID} id - The ID of the variable to delete.
40
+ * @return An object containing the deleted variable and the deleted memberships.
41
+ */
42
+ variableDeleteById(id: SumScoreVariableID) {
43
+ const toDelete = this.variableGetById(id);
44
+ if (!toDelete) return false;
45
+
46
+ const keepMemberships: SumScoreMembershipDto[] = [];
47
+ const toDeleteMemberships: SumScoreMembershipDto[] = [];
48
+
49
+ this._memberShips.forEach((memberShip) => {
50
+ if (memberShip.sumScoreId === id) {
51
+ toDeleteMemberships.push(memberShip);
52
+ } else {
53
+ keepMemberships.push(memberShip);
54
+ }
55
+ });
56
+ this._variables = this._variables.filter((v) => v.id !== id);
57
+ this._memberShips = keepMemberships;
58
+ return { variableDeleted: toDelete, membershipsDeleted: toDeleteMemberships };
59
+ // this._memberShips = this._memberShips.filter((m) => m !== id);
60
+ }
61
+
62
+ variableAddNew(data: {
63
+ name?: string;
64
+ description?: string;
65
+ useAvg?: boolean;
66
+ }): SumScoreVariableDto {
67
+ const ssv: SumScoreVariableDto = {
68
+ id: SumScoreVariableID.create(),
69
+ basedOn: [],
70
+ description: "",
71
+ name: "",
72
+ useAvg: true,
73
+ };
74
+ this._variables.push(ssv);
75
+ return ssv;
76
+ }
77
+
78
+ variableGetById(id: SumScoreVariableID) {
79
+ return this._variables.find((variable) => variable.id === id) ?? false;
80
+ }
81
+
82
+ variableUpdate(
83
+ sumScoreVariableId: SumScoreVariableID,
84
+ changes: { name?: string; description?: string; useAvg?: boolean },
85
+ ) {
86
+ const maybeVariable = this.variableGetById(sumScoreVariableId);
87
+ if (!maybeVariable) {
88
+ return false;
89
+ }
90
+ if (typeof changes.name === "string") {
91
+ maybeVariable.name = changes.name;
92
+ }
93
+ if (typeof changes.description === "string") {
94
+ maybeVariable.description = changes.description;
95
+ }
96
+ if (typeof changes.useAvg === "boolean") {
97
+ maybeVariable.useAvg = changes.useAvg;
98
+ }
99
+ return true;
100
+ }
101
+
102
+ [Symbol.iterator](): Iterator<SumScoreVariableDto> {
103
+ return this._variables[Symbol.iterator]();
104
+ }
105
+
106
+ membershipAdd(
107
+ sumScoreVariableID: SumScoreVariableID,
108
+ varId: string,
109
+ weight?: number,
110
+ ): SumScoreMembershipDto | false {
111
+ let variableExist = false;
112
+ let memberShipIsMissing = false;
113
+
114
+ // const variableExists = this._variables.some((v) => {
115
+ //
116
+ // });
117
+ this._memberShips.forEach((m) => {
118
+ if (m.sumScoreId === sumScoreVariableID && m.varId === varId) {
119
+ variableExist = true;
120
+ }
121
+ });
122
+
123
+ if (variableExist) {
124
+ return false;
125
+ }
126
+ if (memberShipIsMissing) {
127
+ return false;
128
+ }
129
+
130
+ const membership: SumScoreMembershipDto = {
131
+ id: SumScoreMemberShipID.create(),
132
+ sumScoreId: sumScoreVariableID,
133
+ varId: varId,
134
+ weight: DUtil.isNumber(weight) ? weight : 1,
135
+ };
136
+
137
+ this._memberShips.push(membership);
138
+ return membership;
139
+ }
140
+
141
+ membershipGetById(id: SumScoreMemberShipID): SumScoreMembershipDto | false {
142
+ // return false;
143
+ return this._memberShips.find((m) => m.id === id) ?? false;
144
+ }
145
+
146
+ membershipDelete(id: SumScoreMemberShipID) {
147
+ this._memberShips = this._memberShips.filter((m) => m.id === id);
148
+ }
149
+
150
+ membershipGetByVarId(varId: string): SumScoreMembershipDto[] {
151
+ const filtered = this._memberShips.filter((m) => m.varId === varId);
152
+ return filtered.map(cloneItem);
153
+ }
154
+ }
@@ -0,0 +1,45 @@
1
+ import { SumScoreMemberShipID, SumScoreVariableID } from "../primitives/ID";
2
+ import { BuilderObject } from "../BuilderObject";
3
+ import { DUtil } from "@media-quest/engine";
4
+
5
+ export interface SumScoreMembershipDto {
6
+ id: SumScoreMemberShipID;
7
+ sumScoreId: SumScoreVariableID;
8
+ varId: string;
9
+ weight: number;
10
+ }
11
+
12
+ export class SumScoreMemberShip extends BuilderObject<
13
+ "builder-sum-score-membership",
14
+ SumScoreMembershipDto
15
+ > {
16
+ readonly objectType = "builder-sum-score-membership";
17
+ toJson(): SumScoreMembershipDto {
18
+ throw new Error("Method not implemented.");
19
+ }
20
+ clone(): SumScoreMembershipDto {
21
+ throw new Error("Method not implemented.");
22
+ }
23
+
24
+ static create = (
25
+ sumScoreVariableId: SumScoreVariableID,
26
+ varId: string,
27
+ weight?: number,
28
+ ): SumScoreMemberShip => {
29
+ const id = SumScoreMemberShipID.create();
30
+ const w = DUtil.isNumber(weight) ? weight : 1;
31
+ return new SumScoreMemberShip(id, sumScoreVariableId, varId, w);
32
+ };
33
+
34
+ get isValid() {
35
+ return true;
36
+ }
37
+ private constructor(
38
+ readonly id: SumScoreMemberShipID,
39
+ readonly sumScoreId: SumScoreVariableID,
40
+ readonly varId: string,
41
+ readonly weight: number,
42
+ ) {
43
+ super({ id, sumScoreId, varId, weight });
44
+ }
45
+ }
@@ -0,0 +1,151 @@
1
+ import { SumScore } from "./sum-score";
2
+ import { SumScoreVariableDto } from "./sum-score-variable";
3
+ import { SumScoreVariableID } from "../primitives/ID";
4
+ import { SumScoreAnswer } from "./sum-score-answer";
5
+
6
+ const createAnswer = (value: number): SumScoreAnswer => {
7
+ const varId = "v" + value;
8
+ const varLabel = "label for " + varId;
9
+ const valueLabel = "label for value " + value;
10
+ return {
11
+ varId,
12
+ varLabel,
13
+ value,
14
+ valueLabel,
15
+ };
16
+ };
17
+
18
+ const createSumScore = (basedOn: SumScoreVariableDto["basedOn"]) => {
19
+ const id = SumScoreVariableID.create();
20
+ const sumVar1: SumScoreVariableDto = {
21
+ id,
22
+ name: "",
23
+ description: "",
24
+ useAvg: true,
25
+ basedOn,
26
+ };
27
+ return sumVar1;
28
+ };
29
+
30
+ const a0 = createAnswer(0);
31
+ const a1 = createAnswer(1);
32
+ const a2 = createAnswer(2);
33
+ const a3 = createAnswer(3);
34
+ const a4 = createAnswer(4);
35
+ const a5 = createAnswer(5);
36
+ const a6 = createAnswer(6);
37
+ const a7 = createAnswer(7);
38
+ const a8 = createAnswer(8);
39
+ const a9 = createAnswer(9);
40
+
41
+ const all = [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9];
42
+
43
+ describe("Sum score sum-score.", () => {
44
+ test("Is allowed SumScoreValue", () => {
45
+ expect(SumScore.isAllowedValue(-1)).toBeFalsy();
46
+ expect(SumScore.isAllowedValue(0)).toBeTruthy();
47
+ expect(SumScore.isAllowedValue(1)).toBeTruthy();
48
+ expect(SumScore.isAllowedValue(2)).toBeTruthy();
49
+ expect(SumScore.isAllowedValue(3)).toBeTruthy();
50
+ expect(SumScore.isAllowedValue(4)).toBeTruthy();
51
+ expect(SumScore.isAllowedValue(5)).toBeTruthy();
52
+ expect(SumScore.isAllowedValue(6)).toBeTruthy();
53
+ expect(SumScore.isAllowedValue(7)).toBeTruthy();
54
+ expect(SumScore.isAllowedValue(8)).toBeTruthy();
55
+ expect(SumScore.isAllowedValue(9)).toBeFalsy();
56
+ expect(SumScore.isAllowedValue(999)).toBeFalsy();
57
+ });
58
+
59
+ test("Will calculate 2", () => {
60
+ const ss1 = createSumScore([
61
+ { varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
62
+ { varId: a2.varId, varLabel: a2.varLabel, weight: 1 },
63
+ { varId: a9.varId, varLabel: a9.varLabel, weight: 1 },
64
+ ]);
65
+ const score = SumScore.calculate(ss1, all);
66
+ expect(score.sumScore).toBe(3);
67
+ expect(score.basedOn.length).toBe(3);
68
+ expect(score.avg).toBe(1.5);
69
+ expect(score.skippedBy9Count).toBe(1);
70
+ });
71
+ test("Will calculate 5 values", () => {
72
+ const ss1 = createSumScore([
73
+ { varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
74
+ { varId: a2.varId, varLabel: a2.varLabel, weight: 1 },
75
+ { varId: a4.varId, varLabel: a4.varLabel, weight: 1 },
76
+ { varId: a5.varId, varLabel: a5.varLabel, weight: 1 },
77
+ { varId: a6.varId, varLabel: a6.varLabel, weight: 1 },
78
+ { varId: a9.varId, varLabel: a9.varLabel, weight: 0.5 },
79
+ ]);
80
+ const score = SumScore.calculate(ss1, all);
81
+ expect(score.sumScore).toBe(18);
82
+ expect(score.avg).toBe(3.6);
83
+ const basedOn1 = score.basedOn[0];
84
+ expect(basedOn1.value).toBe(a1.value);
85
+ expect(basedOn1.weight).toBe(1);
86
+ expect(basedOn1.varId).toBe(a1.varId);
87
+ expect(basedOn1.varLabel).toBe(a1.varLabel);
88
+ });
89
+ test("Will not include 9 in includedAnswersCount", () => {
90
+ const ss1 = createSumScore([
91
+ { varId: a0.varId, varLabel: a0.varLabel, weight: 1 },
92
+ { varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
93
+ { varId: a5.varId, varLabel: a5.varLabel, weight: 1 },
94
+ { varId: a9.varId, varLabel: a9.varLabel, weight: 1 },
95
+ ]);
96
+ const score = SumScore.calculate(ss1, all);
97
+ expect(score.sumScore).toBe(6);
98
+ expect(score.avg).toBe(2);
99
+ expect(score.includedAnswerCount).toBe(3);
100
+ });
101
+ test("Will calculate weight", () => {
102
+ const ss1 = createSumScore([
103
+ { varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
104
+ { varId: a8.varId, varLabel: a8.varLabel, weight: 0.5 },
105
+ ]);
106
+ const score = SumScore.calculate(ss1, all);
107
+ expect(score.sumScore).toBe(5);
108
+ });
109
+ test("Will calculate many weighted variables.", () => {
110
+ const ss1 = createSumScore([
111
+ { varId: a1.varId, varLabel: a1.varLabel, weight: 1 },
112
+ { varId: a2.varId, varLabel: a2.varLabel, weight: 0.5 },
113
+ { varId: a5.varId, varLabel: a5.varLabel, weight: 1.2 },
114
+ { varId: a8.varId, varLabel: a8.varLabel, weight: 2 },
115
+ ]);
116
+ const score = SumScore.calculate(ss1, all);
117
+ expect(score.sumScore).toBe(24);
118
+ });
119
+ test("Will count missing answers (missingAnswersCount)", () => {
120
+ const ss1 = createSumScore([
121
+ { varId: a1.varId, varLabel: a1.varLabel },
122
+ { varId: a2.varId, varLabel: a2.varLabel },
123
+ { varId: a3.varId, varLabel: a3.varLabel },
124
+ { varId: a5.varId, varLabel: a5.varLabel },
125
+ { varId: a9.varId, varLabel: a9.varLabel },
126
+ ]);
127
+ const missing5InDataSet = [a1, a2, a8];
128
+ const score = SumScore.calculate(ss1, missing5InDataSet);
129
+ expect(score.sumScore).toBe(3);
130
+ expect(score.includedAnswerCount).toBe(2);
131
+ expect(score.missingAnswerCount).toBe(3);
132
+ expect(score.avg).toBe(1.5);
133
+ expect(score.basedOn.length).toBe(2);
134
+ expect(score.avg).toBe(1.5);
135
+ expect(score.errorMessages.length).toBe(0);
136
+ });
137
+ test("includedAnswerCount + missingAnswerCount + skippedBy9Count = SumScoreVariable.basedOn.length", () => {
138
+ const ss1 = createSumScore([
139
+ { varId: a0.varId, varLabel: a0.varLabel },
140
+ { varId: a1.varId, varLabel: a1.varLabel },
141
+ { varId: a2.varId, varLabel: a2.varLabel },
142
+ { varId: a9.varId, varLabel: a9.varLabel },
143
+ ]);
144
+ const answers = [a1, a7, a8, a9];
145
+ const score = SumScore.calculate(ss1, answers);
146
+
147
+ expect(score.includedAnswerCount + score.missingAnswerCount + score.skippedBy9Count).toBe(
148
+ ss1.basedOn.length,
149
+ );
150
+ });
151
+ });
@@ -0,0 +1,36 @@
1
+ import { SumScoreVariableID } from "../primitives/ID";
2
+ import { BuilderObject } from "../BuilderObject";
3
+
4
+ export interface SumScoreVariableDto {
5
+ id: SumScoreVariableID;
6
+ name: string;
7
+ description: string;
8
+ useAvg: boolean;
9
+ /**
10
+ * All variables that the sum-score should be based on.
11
+ */
12
+ basedOn: Array<{ varId: string; varLabel: string; weight?: number }>;
13
+ }
14
+
15
+ export class SumScoreVariable extends BuilderObject<
16
+ "builder-sum-score-variable",
17
+ SumScoreVariableDto
18
+ > {
19
+ readonly objectType = "builder-sum-score-variable";
20
+ useAvg = true;
21
+ name = "";
22
+ description = "";
23
+ private _basedOn: Array<{ varId: string }> = [];
24
+ public static readonly create = () => {
25
+ const id = SumScoreVariableID.create();
26
+ };
27
+ private constructor(dto: SumScoreVariableDto) {
28
+ super(dto);
29
+ }
30
+ toJson(): SumScoreVariableDto {
31
+ throw new Error("Method not implemented.");
32
+ }
33
+ clone(): SumScoreVariableDto {
34
+ throw new Error("Method not implemented.");
35
+ }
36
+ }