@aneuhold/core-ts-db-lib 1.0.24 → 1.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.
- package/lib/documents/dashboard/Task.d.ts +10 -10
- package/lib/documents/dashboard/Task.d.ts.map +1 -1
- package/lib/documents/dashboard/Task.js +8 -47
- package/lib/index.d.ts +3 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -2
- package/lib/services/dashboard/TaskService.d.ts +27 -0
- package/lib/services/dashboard/TaskService.d.ts.map +1 -0
- package/lib/services/dashboard/TaskService.js +177 -0
- package/lib/services/dashboard/TaskService.spec.d.ts +2 -0
- package/lib/services/dashboard/TaskService.spec.d.ts.map +1 -0
- package/lib/services/dashboard/TaskService.spec.js +205 -0
- package/package.json +4 -1
|
@@ -4,10 +4,6 @@ import RequiredUserId from '../../schemas/required-refs/RequiredUserId';
|
|
|
4
4
|
import { DocumentValidator } from '../../schemas/validators/DocumentValidator';
|
|
5
5
|
import { RecurrenceInfo } from '../../embedded-types/dashboard/task/RecurrenceInfo';
|
|
6
6
|
export declare const validateDashboardTask: DocumentValidator<DashboardTask>;
|
|
7
|
-
/**
|
|
8
|
-
* Gets all the children task IDs for the given parent task IDs.
|
|
9
|
-
*/
|
|
10
|
-
export declare const getDashboardTaskChildrenIds: (allUserTasks: DashboardTask[], parentTaskIds: ObjectId[]) => ObjectId[];
|
|
11
7
|
/**
|
|
12
8
|
* When thinking about the logic of tasks, the following thoughts come to mind:
|
|
13
9
|
*
|
|
@@ -50,16 +46,20 @@ export default class DashboardTask extends BaseDocumentWithType implements Requi
|
|
|
50
46
|
*/
|
|
51
47
|
sharedWith: ObjectId[];
|
|
52
48
|
/**
|
|
53
|
-
* The recurrence info for this task if there is any.
|
|
54
|
-
* if {@link parentRecurringTask} is set.
|
|
49
|
+
* The recurrence info for this task if there is any.
|
|
55
50
|
*/
|
|
56
51
|
recurrenceInfo?: RecurrenceInfo;
|
|
57
52
|
/**
|
|
58
|
-
* The
|
|
59
|
-
*
|
|
60
|
-
*
|
|
53
|
+
* The recurring task info for the parent recurring task if there is one.
|
|
54
|
+
*
|
|
55
|
+
* If this is set, then the current tasks's recurrence info should be the
|
|
56
|
+
* same as the parent recurring task.
|
|
61
57
|
*/
|
|
62
|
-
|
|
58
|
+
parentRecurringTaskInfo?: {
|
|
59
|
+
taskId: ObjectId;
|
|
60
|
+
startDate?: Date;
|
|
61
|
+
dueDate?: Date;
|
|
62
|
+
};
|
|
63
63
|
title: string;
|
|
64
64
|
completed: boolean;
|
|
65
65
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../../src/documents/dashboard/Task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,oBAAoB,MAAM,yBAAyB,CAAC;AAC3D,OAAO,cAAc,MAAM,4CAA4C,CAAC;AAExE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC/E,OAAO,EACL,cAAc,EAEf,MAAM,oDAAoD,CAAC;AAE5D,eAAO,MAAM,qBAAqB,EAAE,iBAAiB,CAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../../src/documents/dashboard/Task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,oBAAoB,MAAM,yBAAyB,CAAC;AAC3D,OAAO,cAAc,MAAM,4CAA4C,CAAC;AAExE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC/E,OAAO,EACL,cAAc,EAEf,MAAM,oDAAoD,CAAC;AAE5D,eAAO,MAAM,qBAAqB,EAAE,iBAAiB,CAAC,aAAa,CAsBlE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,OAAO,OAAO,aACnB,SAAQ,oBACR,YAAW,cAAc;IAEzB,MAAM,CAAC,OAAO,SAAU;IAExB,OAAO,SAAyB;IAEhC;;OAEG;IACH,MAAM,EAAE,QAAQ,CAAC;IAEjB;;;;;;;;;;;OAWG;IACH,UAAU,EAAE,QAAQ,EAAE,CAAM;IAE5B;;OAEG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE;QACxB,MAAM,EAAE,QAAQ,CAAC;QACjB,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,OAAO,CAAC,EAAE,IAAI,CAAC;KAChB,CAAC;IAEF,KAAK,SAAM;IAEX,SAAS,UAAS;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,QAAQ,CAAC;IAExB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,OAAc;IAEzB;;OAEG;IACH,eAAe,OAAc;IAE7B,SAAS,CAAC,EAAE,IAAI,CAAC;IAEjB,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf;;OAEG;IACH,IAAI,EAAE,MAAM,EAAE,CAAM;IAEpB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAa;gBAEjB,OAAO,EAAE,QAAQ;CAI9B"}
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.validateDashboardTask = void 0;
|
|
7
7
|
const bson_1 = require("bson");
|
|
8
8
|
const BaseDocumentWithType_1 = __importDefault(require("../BaseDocumentWithType"));
|
|
9
9
|
const ValidateUtil_1 = __importDefault(require("../../schemas/validators/ValidateUtil"));
|
|
@@ -23,50 +23,11 @@ const validateDashboardTask = (task) => {
|
|
|
23
23
|
validate.object('lastUpdatedDate', exampleTask.lastUpdatedDate);
|
|
24
24
|
validate.optionalObject('startDate');
|
|
25
25
|
validate.optionalObject('dueDate');
|
|
26
|
+
validate.optionalObject('parentRecurringTaskInfo');
|
|
26
27
|
(0, RecurrenceInfo_1.validateRecurrenceInfo)(task, errors);
|
|
27
28
|
return { updatedDoc: task, errors };
|
|
28
29
|
};
|
|
29
30
|
exports.validateDashboardTask = validateDashboardTask;
|
|
30
|
-
/**
|
|
31
|
-
* Gets all the children task IDs for the given parent task IDs.
|
|
32
|
-
*/
|
|
33
|
-
const getDashboardTaskChildrenIds = (allUserTasks, parentTaskIds) => {
|
|
34
|
-
const parentToTaskIdsDict = {};
|
|
35
|
-
const taskIdToTaskDict = {};
|
|
36
|
-
allUserTasks.forEach((task) => {
|
|
37
|
-
taskIdToTaskDict[task._id.toString()] = task;
|
|
38
|
-
if (task.parentTaskId) {
|
|
39
|
-
if (!parentToTaskIdsDict[task.parentTaskId.toString()]) {
|
|
40
|
-
parentToTaskIdsDict[task.parentTaskId.toString()] = [];
|
|
41
|
-
}
|
|
42
|
-
parentToTaskIdsDict[task.parentTaskId.toString()].push(task._id.toString());
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
const childrenIds = [];
|
|
46
|
-
parentTaskIds.forEach((taskId) => {
|
|
47
|
-
const task = taskIdToTaskDict[taskId.toString()];
|
|
48
|
-
if (task) {
|
|
49
|
-
const childrenTaskIds = getChildrenTaskIds(taskIdToTaskDict, parentToTaskIdsDict, taskId.toString());
|
|
50
|
-
childrenIds.push(...childrenTaskIds.map((id) => new bson_1.ObjectId(id)));
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
return childrenIds;
|
|
54
|
-
};
|
|
55
|
-
exports.getDashboardTaskChildrenIds = getDashboardTaskChildrenIds;
|
|
56
|
-
function getChildrenTaskIds(taskIdToTaskDict, parentToTaskIdsDict, taskId) {
|
|
57
|
-
const childrenIds = parentToTaskIdsDict[taskId];
|
|
58
|
-
if (!childrenIds) {
|
|
59
|
-
return [];
|
|
60
|
-
}
|
|
61
|
-
childrenIds.forEach((childId) => {
|
|
62
|
-
const childTask = taskIdToTaskDict[childId];
|
|
63
|
-
if (childTask) {
|
|
64
|
-
const grandchildrenIds = getChildrenTaskIds(taskIdToTaskDict, parentToTaskIdsDict, childId);
|
|
65
|
-
childrenIds.push(...grandchildrenIds);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
return childrenIds;
|
|
69
|
-
}
|
|
70
31
|
/**
|
|
71
32
|
* When thinking about the logic of tasks, the following thoughts come to mind:
|
|
72
33
|
*
|
|
@@ -109,16 +70,16 @@ class DashboardTask extends BaseDocumentWithType_1.default {
|
|
|
109
70
|
*/
|
|
110
71
|
sharedWith = [];
|
|
111
72
|
/**
|
|
112
|
-
* The recurrence info for this task if there is any.
|
|
113
|
-
* if {@link parentRecurringTask} is set.
|
|
73
|
+
* The recurrence info for this task if there is any.
|
|
114
74
|
*/
|
|
115
75
|
recurrenceInfo;
|
|
116
76
|
/**
|
|
117
|
-
* The
|
|
118
|
-
*
|
|
119
|
-
*
|
|
77
|
+
* The recurring task info for the parent recurring task if there is one.
|
|
78
|
+
*
|
|
79
|
+
* If this is set, then the current tasks's recurrence info should be the
|
|
80
|
+
* same as the parent recurring task.
|
|
120
81
|
*/
|
|
121
|
-
|
|
82
|
+
parentRecurringTaskInfo;
|
|
122
83
|
title = '';
|
|
123
84
|
completed = false;
|
|
124
85
|
/**
|
package/lib/index.d.ts
CHANGED
|
@@ -2,11 +2,12 @@ import BaseDocument from './documents/BaseDocument';
|
|
|
2
2
|
import BaseDocumentWithType from './documents/BaseDocumentWithType';
|
|
3
3
|
import ApiKey, { validateApiKey } from './documents/common/ApiKey';
|
|
4
4
|
import User, { UserCTO, validateUser } from './documents/common/User';
|
|
5
|
-
import DashboardTask, {
|
|
5
|
+
import DashboardTask, { validateDashboardTask } from './documents/dashboard/Task';
|
|
6
6
|
import DashboardUserConfig, { validateDashboardUserConfig } from './documents/dashboard/UserConfig';
|
|
7
7
|
import { RecurrenceBasis, RecurrenceEffect, RecurrenceFrequency, RecurrenceFrequencyType, RecurrenceInfo } from './embedded-types/dashboard/task/RecurrenceInfo';
|
|
8
8
|
import RequiredUserId from './schemas/required-refs/RequiredUserId';
|
|
9
9
|
import { DocumentValidator } from './schemas/validators/DocumentValidator';
|
|
10
|
-
|
|
10
|
+
import DashboardTaskService from './services/dashboard/TaskService';
|
|
11
|
+
export { User, validateUser, ApiKey, validateApiKey, DashboardUserConfig, validateDashboardUserConfig, DashboardTask, RecurrenceFrequencyType, RecurrenceBasis, RecurrenceEffect, validateDashboardTask, DashboardTaskService, BaseDocument, BaseDocumentWithType, RequiredUserId };
|
|
11
12
|
export type { DocumentValidator, UserCTO, RecurrenceInfo, RecurrenceFrequency };
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,0BAA0B,CAAC;AACpD,OAAO,oBAAoB,MAAM,kCAAkC,CAAC;AACpE,OAAO,MAAM,EAAE,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,aAAa,EAAE,EACpB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,0BAA0B,CAAC;AACpD,OAAO,oBAAoB,MAAM,kCAAkC,CAAC;AACpE,OAAO,MAAM,EAAE,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,aAAa,EAAE,EACpB,qBAAqB,EACtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,mBAAmB,EAAE,EAC1B,2BAA2B,EAC5B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACf,MAAM,gDAAgD,CAAC;AACxD,OAAO,cAAc,MAAM,wCAAwC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,oBAAoB,MAAM,kCAAkC,CAAC;AAGpE,OAAO,EACL,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,cAAc,EACd,mBAAmB,EACnB,2BAA2B,EAC3B,aAAa,EACb,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACf,CAAC;AAGF,YAAY,EAAE,iBAAiB,EAAE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.RequiredUserId = exports.BaseDocumentWithType = exports.BaseDocument = exports.
|
|
29
|
+
exports.RequiredUserId = exports.BaseDocumentWithType = exports.BaseDocument = exports.DashboardTaskService = exports.validateDashboardTask = exports.RecurrenceEffect = exports.RecurrenceBasis = exports.RecurrenceFrequencyType = exports.DashboardTask = exports.validateDashboardUserConfig = exports.DashboardUserConfig = exports.validateApiKey = exports.ApiKey = exports.validateUser = exports.User = void 0;
|
|
30
30
|
const BaseDocument_1 = __importDefault(require("./documents/BaseDocument"));
|
|
31
31
|
exports.BaseDocument = BaseDocument_1.default;
|
|
32
32
|
const BaseDocumentWithType_1 = __importDefault(require("./documents/BaseDocumentWithType"));
|
|
@@ -39,7 +39,6 @@ exports.User = User_1.default;
|
|
|
39
39
|
Object.defineProperty(exports, "validateUser", { enumerable: true, get: function () { return User_1.validateUser; } });
|
|
40
40
|
const Task_1 = __importStar(require("./documents/dashboard/Task"));
|
|
41
41
|
exports.DashboardTask = Task_1.default;
|
|
42
|
-
Object.defineProperty(exports, "getDashboardTaskChildrenIds", { enumerable: true, get: function () { return Task_1.getDashboardTaskChildrenIds; } });
|
|
43
42
|
Object.defineProperty(exports, "validateDashboardTask", { enumerable: true, get: function () { return Task_1.validateDashboardTask; } });
|
|
44
43
|
const UserConfig_1 = __importStar(require("./documents/dashboard/UserConfig"));
|
|
45
44
|
exports.DashboardUserConfig = UserConfig_1.default;
|
|
@@ -50,3 +49,5 @@ Object.defineProperty(exports, "RecurrenceEffect", { enumerable: true, get: func
|
|
|
50
49
|
Object.defineProperty(exports, "RecurrenceFrequencyType", { enumerable: true, get: function () { return RecurrenceInfo_1.RecurrenceFrequencyType; } });
|
|
51
50
|
const RequiredUserId_1 = __importDefault(require("./schemas/required-refs/RequiredUserId"));
|
|
52
51
|
exports.RequiredUserId = RequiredUserId_1.default;
|
|
52
|
+
const TaskService_1 = __importDefault(require("./services/dashboard/TaskService"));
|
|
53
|
+
exports.DashboardTaskService = TaskService_1.default;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ObjectId } from 'bson';
|
|
2
|
+
import DashboardTask from '../../documents/dashboard/Task';
|
|
3
|
+
import { RecurrenceFrequency } from '../../embedded-types/dashboard/task/RecurrenceInfo';
|
|
4
|
+
export default class DashboardTaskService {
|
|
5
|
+
/**
|
|
6
|
+
* Gets all the children task IDs for the given parent task IDs.
|
|
7
|
+
*/
|
|
8
|
+
static getChildrenIds: (allUserTasks: DashboardTask[], parentTaskIds: ObjectId[]) => ObjectId[];
|
|
9
|
+
/**
|
|
10
|
+
* Gets the next frequency date from the provided basis date. Returns null
|
|
11
|
+
* if the provided frequency is in an invalid state.
|
|
12
|
+
*/
|
|
13
|
+
static getNextFrequencyDate(basisDate: Date, frequency: RecurrenceFrequency): Date | null;
|
|
14
|
+
/**
|
|
15
|
+
* Moves the start and due date forward by one frequency.
|
|
16
|
+
*
|
|
17
|
+
* This does not take into account the recurrence effect. That should be
|
|
18
|
+
* handled on the frontend.
|
|
19
|
+
*
|
|
20
|
+
* Makes no changes if the state of the task is invalid for recurrence or
|
|
21
|
+
* there isn't recurrence info.
|
|
22
|
+
*/
|
|
23
|
+
static updateDatesForRecurrence(task: DashboardTask): void;
|
|
24
|
+
private static getDiffForDateUpdate;
|
|
25
|
+
private static getChildrenTaskIds;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=TaskService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaskService.d.ts","sourceRoot":"","sources":["../../../src/services/dashboard/TaskService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEhC,OAAO,aAAa,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EACL,mBAAmB,EAEpB,MAAM,oDAAoD,CAAC;AAE5D,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC;;OAEG;IACH,MAAM,CAAC,cAAc,iBACL,aAAa,EAAE,iBACd,QAAQ,EAAE,KACxB,QAAQ,EAAE,CA2BX;IAEF;;;OAGG;IACH,MAAM,CAAC,oBAAoB,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB;IAsE3E;;;;;;;;OAQG;IACH,MAAM,CAAC,wBAAwB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IA+D1D,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAcnC,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAsBlC"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const bson_1 = require("bson");
|
|
4
|
+
const core_ts_lib_1 = require("@aneuhold/core-ts-lib");
|
|
5
|
+
const RecurrenceInfo_1 = require("../../embedded-types/dashboard/task/RecurrenceInfo");
|
|
6
|
+
class DashboardTaskService {
|
|
7
|
+
/**
|
|
8
|
+
* Gets all the children task IDs for the given parent task IDs.
|
|
9
|
+
*/
|
|
10
|
+
static getChildrenIds = (allUserTasks, parentTaskIds) => {
|
|
11
|
+
const parentToTaskIdsDict = {};
|
|
12
|
+
const taskIdToTaskDict = {};
|
|
13
|
+
allUserTasks.forEach((task) => {
|
|
14
|
+
taskIdToTaskDict[task._id.toString()] = task;
|
|
15
|
+
if (task.parentTaskId) {
|
|
16
|
+
if (!parentToTaskIdsDict[task.parentTaskId.toString()]) {
|
|
17
|
+
parentToTaskIdsDict[task.parentTaskId.toString()] = [];
|
|
18
|
+
}
|
|
19
|
+
parentToTaskIdsDict[task.parentTaskId.toString()].push(task._id.toString());
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const childrenIds = [];
|
|
23
|
+
parentTaskIds.forEach((taskId) => {
|
|
24
|
+
const task = taskIdToTaskDict[taskId.toString()];
|
|
25
|
+
if (task) {
|
|
26
|
+
const childrenTaskIds = this.getChildrenTaskIds(taskIdToTaskDict, parentToTaskIdsDict, taskId.toString());
|
|
27
|
+
childrenIds.push(...childrenTaskIds.map((id) => new bson_1.ObjectId(id)));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
return childrenIds;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Gets the next frequency date from the provided basis date. Returns null
|
|
34
|
+
* if the provided frequency is in an invalid state.
|
|
35
|
+
*/
|
|
36
|
+
static getNextFrequencyDate(basisDate, frequency) {
|
|
37
|
+
// Last day of month
|
|
38
|
+
if (frequency.type === RecurrenceInfo_1.RecurrenceFrequencyType.lastDayOfMonth) {
|
|
39
|
+
return core_ts_lib_1.DateService.getLastDayOfGivenMonth(basisDate);
|
|
40
|
+
}
|
|
41
|
+
// Every X Time Unit
|
|
42
|
+
if (frequency.type === RecurrenceInfo_1.RecurrenceFrequencyType.everyXTimeUnit) {
|
|
43
|
+
if (!frequency.everyXTimeUnit) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (frequency.everyXTimeUnit.timeUnit === 'day') {
|
|
47
|
+
return core_ts_lib_1.DateService.addDays(basisDate, frequency.everyXTimeUnit.x);
|
|
48
|
+
}
|
|
49
|
+
if (frequency.everyXTimeUnit.timeUnit === 'week') {
|
|
50
|
+
return core_ts_lib_1.DateService.addDays(basisDate, frequency.everyXTimeUnit.x * 7);
|
|
51
|
+
}
|
|
52
|
+
if (frequency.everyXTimeUnit.timeUnit === 'month') {
|
|
53
|
+
return core_ts_lib_1.DateService.addMonths(basisDate, frequency.everyXTimeUnit.x);
|
|
54
|
+
}
|
|
55
|
+
if (frequency.everyXTimeUnit.timeUnit === 'year') {
|
|
56
|
+
return core_ts_lib_1.DateService.addYears(basisDate, frequency.everyXTimeUnit.x);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Week Day Set
|
|
60
|
+
if (frequency.type === RecurrenceInfo_1.RecurrenceFrequencyType.weekDaySet) {
|
|
61
|
+
if (!frequency.weekDaySet) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const newDate = new Date(basisDate);
|
|
65
|
+
let daysToAdd = 0;
|
|
66
|
+
while (daysToAdd < 7) {
|
|
67
|
+
newDate.setDate(newDate.getDate() + 1);
|
|
68
|
+
if (frequency.weekDaySet.includes(newDate.getDay())) {
|
|
69
|
+
return newDate;
|
|
70
|
+
}
|
|
71
|
+
daysToAdd += 1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Every X Weekday of Month
|
|
75
|
+
if (frequency.type === RecurrenceInfo_1.RecurrenceFrequencyType.everyXWeekdayOfMonth) {
|
|
76
|
+
if (!frequency.everyXWeekdayOfMonth) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
// Start by adding one day
|
|
80
|
+
let newDate = core_ts_lib_1.DateService.getWeekDayOfXWeekOfMonth(core_ts_lib_1.DateService.addDays(basisDate, 1), frequency.everyXWeekdayOfMonth.weekDay, frequency.everyXWeekdayOfMonth.weekOfMonth);
|
|
81
|
+
let monthsPassed = 0;
|
|
82
|
+
while (!newDate ||
|
|
83
|
+
newDate < basisDate ||
|
|
84
|
+
newDate.getTime() === basisDate.getTime()) {
|
|
85
|
+
monthsPassed += 1;
|
|
86
|
+
newDate = core_ts_lib_1.DateService.getWeekDayOfXWeekOfMonth(core_ts_lib_1.DateService.addMonths(basisDate, monthsPassed), frequency.everyXWeekdayOfMonth.weekDay, frequency.everyXWeekdayOfMonth.weekOfMonth);
|
|
87
|
+
if (monthsPassed > 11) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return newDate;
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Moves the start and due date forward by one frequency.
|
|
97
|
+
*
|
|
98
|
+
* This does not take into account the recurrence effect. That should be
|
|
99
|
+
* handled on the frontend.
|
|
100
|
+
*
|
|
101
|
+
* Makes no changes if the state of the task is invalid for recurrence or
|
|
102
|
+
* there isn't recurrence info.
|
|
103
|
+
*/
|
|
104
|
+
static updateDatesForRecurrence(task) {
|
|
105
|
+
// Initial basic validation
|
|
106
|
+
if (!task.recurrenceInfo) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Validation for dates based on parent
|
|
110
|
+
if (task.parentRecurringTaskInfo) {
|
|
111
|
+
if (
|
|
112
|
+
// No dates to move forward
|
|
113
|
+
(!task.dueDate && !task.startDate) ||
|
|
114
|
+
// Invalid start date recurrence basis
|
|
115
|
+
(task.recurrenceInfo.recurrenceBasis === 'startDate' &&
|
|
116
|
+
!task.parentRecurringTaskInfo.startDate) ||
|
|
117
|
+
// Invalid due date recurrence basis
|
|
118
|
+
(task.recurrenceInfo.recurrenceBasis === 'dueDate' &&
|
|
119
|
+
!task.parentRecurringTaskInfo.dueDate)) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Validation for moving dates based on their own recurrence
|
|
123
|
+
}
|
|
124
|
+
else if (!task.recurrenceInfo ||
|
|
125
|
+
(task.recurrenceInfo.recurrenceBasis === 'startDate' &&
|
|
126
|
+
!task.startDate) ||
|
|
127
|
+
(task.recurrenceInfo.recurrenceBasis === 'dueDate' && !task.dueDate)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
let diff = 0;
|
|
131
|
+
if (task.parentRecurringTaskInfo) {
|
|
132
|
+
if (task.recurrenceInfo.recurrenceBasis === 'startDate') {
|
|
133
|
+
diff = this.getDiffForDateUpdate(task.parentRecurringTaskInfo.startDate, task.recurrenceInfo.frequency);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
diff = this.getDiffForDateUpdate(task.parentRecurringTaskInfo.dueDate, task.recurrenceInfo.frequency);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else if (task.recurrenceInfo.recurrenceBasis === 'startDate') {
|
|
140
|
+
diff = this.getDiffForDateUpdate(task.startDate, task.recurrenceInfo.frequency);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
diff = this.getDiffForDateUpdate(task.dueDate, task.recurrenceInfo.frequency);
|
|
144
|
+
}
|
|
145
|
+
if (task.startDate) {
|
|
146
|
+
task.startDate = new Date(task.startDate.getTime() + diff);
|
|
147
|
+
}
|
|
148
|
+
if (task.dueDate) {
|
|
149
|
+
task.dueDate = new Date(task.dueDate.getTime() + diff);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
static getDiffForDateUpdate(basisDate, frequency) {
|
|
153
|
+
if (!basisDate) {
|
|
154
|
+
return 0;
|
|
155
|
+
}
|
|
156
|
+
const nextFrequencyDate = this.getNextFrequencyDate(basisDate, frequency);
|
|
157
|
+
if (!nextFrequencyDate) {
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
return nextFrequencyDate.getTime() - basisDate.getTime();
|
|
161
|
+
}
|
|
162
|
+
static getChildrenTaskIds(taskIdToTaskDict, parentToTaskIdsDict, taskId) {
|
|
163
|
+
const childrenIds = parentToTaskIdsDict[taskId];
|
|
164
|
+
if (!childrenIds) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
childrenIds.forEach((childId) => {
|
|
168
|
+
const childTask = taskIdToTaskDict[childId];
|
|
169
|
+
if (childTask) {
|
|
170
|
+
const grandchildrenIds = this.getChildrenTaskIds(taskIdToTaskDict, parentToTaskIdsDict, childId);
|
|
171
|
+
childrenIds.push(...grandchildrenIds);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
return childrenIds;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.default = DashboardTaskService;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaskService.spec.d.ts","sourceRoot":"","sources":["../../../src/services/dashboard/TaskService.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const bson_1 = require("bson");
|
|
7
|
+
const Task_1 = __importDefault(require("../../documents/dashboard/Task"));
|
|
8
|
+
const RecurrenceInfo_1 = require("../../embedded-types/dashboard/task/RecurrenceInfo");
|
|
9
|
+
const TaskService_1 = __importDefault(require("./TaskService"));
|
|
10
|
+
describe('DashboardTaskService', () => {
|
|
11
|
+
describe('getNextFrequencyDate', () => {
|
|
12
|
+
it('should return a valid date for lastDayOfMonth', () => {
|
|
13
|
+
const basisDate = new Date(2024, 0, 1);
|
|
14
|
+
const frequency = {
|
|
15
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.lastDayOfMonth
|
|
16
|
+
};
|
|
17
|
+
const result = TaskService_1.default.getNextFrequencyDate(basisDate, frequency);
|
|
18
|
+
expect(result).toEqual(new Date(2024, 0, 31));
|
|
19
|
+
});
|
|
20
|
+
describe('every X time unit', () => {
|
|
21
|
+
it('should return a valid date for every X Day', () => {
|
|
22
|
+
const basisDate = new Date(2024, 0, 1);
|
|
23
|
+
const frequency = {
|
|
24
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXTimeUnit,
|
|
25
|
+
everyXTimeUnit: {
|
|
26
|
+
timeUnit: 'day',
|
|
27
|
+
x: 2
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const result = TaskService_1.default.getNextFrequencyDate(basisDate, frequency);
|
|
31
|
+
expect(result).toEqual(new Date(2024, 0, 3));
|
|
32
|
+
});
|
|
33
|
+
it('should return a valid date for every X Week', () => {
|
|
34
|
+
const basisDate = new Date(2024, 0, 1);
|
|
35
|
+
const frequency = {
|
|
36
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXTimeUnit,
|
|
37
|
+
everyXTimeUnit: {
|
|
38
|
+
timeUnit: 'week',
|
|
39
|
+
x: 2
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const result = TaskService_1.default.getNextFrequencyDate(basisDate, frequency);
|
|
43
|
+
expect(result).toEqual(new Date(2024, 0, 15));
|
|
44
|
+
});
|
|
45
|
+
it('should return a valid date for every X Month', () => {
|
|
46
|
+
const basisDate = new Date(2024, 0, 1);
|
|
47
|
+
const frequency = {
|
|
48
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXTimeUnit,
|
|
49
|
+
everyXTimeUnit: {
|
|
50
|
+
timeUnit: 'month',
|
|
51
|
+
x: 2
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const result = TaskService_1.default.getNextFrequencyDate(basisDate, frequency);
|
|
55
|
+
expect(result).toEqual(new Date(2024, 2, 1));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
it('should return a valid date for weekDaySet', () => {
|
|
59
|
+
const basisDate = new Date(2024, 0, 1);
|
|
60
|
+
const frequency = {
|
|
61
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.weekDaySet,
|
|
62
|
+
weekDaySet: [0, 6]
|
|
63
|
+
};
|
|
64
|
+
const result = TaskService_1.default.getNextFrequencyDate(basisDate, frequency);
|
|
65
|
+
expect(result).toEqual(new Date(2024, 0, 6));
|
|
66
|
+
});
|
|
67
|
+
describe('Every X Weekday of Month', () => {
|
|
68
|
+
it('should return a valid date for every 2nd Sunday of Month', () => {
|
|
69
|
+
const basisDate = new Date(2024, 0, 1);
|
|
70
|
+
// Every second sunday
|
|
71
|
+
const frequency = {
|
|
72
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXWeekdayOfMonth,
|
|
73
|
+
everyXWeekdayOfMonth: {
|
|
74
|
+
weekDay: 0,
|
|
75
|
+
weekOfMonth: 2
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const result = TaskService_1.default.getNextFrequencyDate(basisDate, frequency);
|
|
79
|
+
expect(result).toEqual(new Date(2024, 0, 14));
|
|
80
|
+
});
|
|
81
|
+
it('should return a valid date across year change', () => {
|
|
82
|
+
const basisDate = new Date(2023, 11, 30);
|
|
83
|
+
// Every 1st Saturday
|
|
84
|
+
const frequency = {
|
|
85
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXWeekdayOfMonth,
|
|
86
|
+
everyXWeekdayOfMonth: {
|
|
87
|
+
weekDay: 6,
|
|
88
|
+
weekOfMonth: 1
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const result = TaskService_1.default.getNextFrequencyDate(basisDate, frequency);
|
|
92
|
+
expect(result).toEqual(new Date(2024, 0, 6));
|
|
93
|
+
});
|
|
94
|
+
it('should return a valid next date when the basis is the same as the recurrence', () => {
|
|
95
|
+
const basisDate = new Date(2024, 0, 14);
|
|
96
|
+
// Every second sunday
|
|
97
|
+
const frequency = {
|
|
98
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXWeekdayOfMonth,
|
|
99
|
+
everyXWeekdayOfMonth: {
|
|
100
|
+
weekDay: 0,
|
|
101
|
+
weekOfMonth: 2
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const result = TaskService_1.default.getNextFrequencyDate(basisDate, frequency);
|
|
105
|
+
expect(result).toEqual(new Date(2024, 1, 11));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('updateDatesForRecurrence', () => {
|
|
110
|
+
describe('Start date basis', () => {
|
|
111
|
+
it('should update the start date correctly for a daily recurrence', () => {
|
|
112
|
+
const task = new Task_1.default(new bson_1.ObjectId());
|
|
113
|
+
task.startDate = new Date(2024, 0, 1);
|
|
114
|
+
task.recurrenceInfo = {
|
|
115
|
+
frequency: {
|
|
116
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXTimeUnit,
|
|
117
|
+
everyXTimeUnit: {
|
|
118
|
+
timeUnit: 'day',
|
|
119
|
+
x: 1
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
recurrenceBasis: RecurrenceInfo_1.RecurrenceBasis.startDate,
|
|
123
|
+
recurrenceEffect: RecurrenceInfo_1.RecurrenceEffect.rollOnBasis
|
|
124
|
+
};
|
|
125
|
+
TaskService_1.default.updateDatesForRecurrence(task);
|
|
126
|
+
expect(task.startDate).toEqual(new Date(2024, 0, 2));
|
|
127
|
+
});
|
|
128
|
+
it('should update the start date correctly for daily recurrence on subtask', () => {
|
|
129
|
+
const task = new Task_1.default(new bson_1.ObjectId());
|
|
130
|
+
task.startDate = new Date(2024, 0, 8);
|
|
131
|
+
task.dueDate = new Date(2024, 0, 13);
|
|
132
|
+
task.recurrenceInfo = {
|
|
133
|
+
frequency: {
|
|
134
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXTimeUnit,
|
|
135
|
+
everyXTimeUnit: {
|
|
136
|
+
timeUnit: 'day',
|
|
137
|
+
x: 1
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
recurrenceBasis: RecurrenceInfo_1.RecurrenceBasis.startDate,
|
|
141
|
+
recurrenceEffect: RecurrenceInfo_1.RecurrenceEffect.rollOnBasis
|
|
142
|
+
};
|
|
143
|
+
task.parentRecurringTaskInfo = {
|
|
144
|
+
taskId: new bson_1.ObjectId(),
|
|
145
|
+
startDate: new Date(2024, 0, 1)
|
|
146
|
+
};
|
|
147
|
+
TaskService_1.default.updateDatesForRecurrence(task);
|
|
148
|
+
expect(task.startDate).toEqual(new Date(2024, 0, 9));
|
|
149
|
+
expect(task.dueDate).toEqual(new Date(2024, 0, 14));
|
|
150
|
+
});
|
|
151
|
+
it('should update the start date correctly for a weekly recurrence', () => {
|
|
152
|
+
const task = new Task_1.default(new bson_1.ObjectId());
|
|
153
|
+
task.startDate = new Date(2024, 0, 1);
|
|
154
|
+
task.recurrenceInfo = {
|
|
155
|
+
frequency: {
|
|
156
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXTimeUnit,
|
|
157
|
+
everyXTimeUnit: {
|
|
158
|
+
timeUnit: 'week',
|
|
159
|
+
x: 1
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
recurrenceBasis: RecurrenceInfo_1.RecurrenceBasis.startDate,
|
|
163
|
+
recurrenceEffect: RecurrenceInfo_1.RecurrenceEffect.rollOnBasis
|
|
164
|
+
};
|
|
165
|
+
TaskService_1.default.updateDatesForRecurrence(task);
|
|
166
|
+
expect(task.startDate).toEqual(new Date(2024, 0, 8));
|
|
167
|
+
});
|
|
168
|
+
it('should update the start and due date correctly for a weekDaySet reccurence', () => {
|
|
169
|
+
const task = new Task_1.default(new bson_1.ObjectId());
|
|
170
|
+
task.startDate = new Date(2024, 0, 1, 11);
|
|
171
|
+
task.dueDate = new Date(2024, 0, 4, 23, 59);
|
|
172
|
+
task.recurrenceInfo = {
|
|
173
|
+
frequency: {
|
|
174
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.weekDaySet,
|
|
175
|
+
weekDaySet: [0, 5]
|
|
176
|
+
},
|
|
177
|
+
recurrenceBasis: RecurrenceInfo_1.RecurrenceBasis.startDate,
|
|
178
|
+
recurrenceEffect: RecurrenceInfo_1.RecurrenceEffect.rollOnBasis
|
|
179
|
+
};
|
|
180
|
+
TaskService_1.default.updateDatesForRecurrence(task);
|
|
181
|
+
expect(task.startDate).toEqual(new Date(2024, 0, 5, 11));
|
|
182
|
+
expect(task.dueDate).toEqual(new Date(2024, 0, 8, 23, 59));
|
|
183
|
+
});
|
|
184
|
+
it('should update the start and due date correctly for a everyXWeekdayOfMonth reccurence', () => {
|
|
185
|
+
const task = new Task_1.default(new bson_1.ObjectId());
|
|
186
|
+
task.startDate = new Date(2024, 0, 1, 11);
|
|
187
|
+
task.dueDate = new Date(2024, 0, 4, 23, 59);
|
|
188
|
+
task.recurrenceInfo = {
|
|
189
|
+
frequency: {
|
|
190
|
+
type: RecurrenceInfo_1.RecurrenceFrequencyType.everyXWeekdayOfMonth,
|
|
191
|
+
everyXWeekdayOfMonth: {
|
|
192
|
+
weekDay: 0,
|
|
193
|
+
weekOfMonth: 1
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
recurrenceBasis: RecurrenceInfo_1.RecurrenceBasis.startDate,
|
|
197
|
+
recurrenceEffect: RecurrenceInfo_1.RecurrenceEffect.rollOnBasis
|
|
198
|
+
};
|
|
199
|
+
TaskService_1.default.updateDatesForRecurrence(task);
|
|
200
|
+
expect(task.startDate).toEqual(new Date(2024, 0, 7, 11));
|
|
201
|
+
expect(task.dueDate).toEqual(new Date(2024, 0, 10, 23, 59));
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aneuhold/core-ts-db-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.26",
|
|
4
4
|
"description": "A core database library used for personal projects",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -26,12 +26,15 @@
|
|
|
26
26
|
"build": "tsc",
|
|
27
27
|
"watch": "tsc -w",
|
|
28
28
|
"link:local": "cd lib && yarn link",
|
|
29
|
+
"link:core-ts-lib": "yarn link @aneuhold/core-ts-lib",
|
|
29
30
|
"unlink:local": "cd lib && yarn unlink",
|
|
31
|
+
"unlink:core-ts-lib": "yarn unlink @aneuhold/core-ts-lib && yarn install --force",
|
|
30
32
|
"upgrade:all": "yarn upgrade --latest",
|
|
31
33
|
"upgrade:core": "yarn upgrade --latest --pattern @aneuhold",
|
|
32
34
|
"test": "jest"
|
|
33
35
|
},
|
|
34
36
|
"dependencies": {
|
|
37
|
+
"@aneuhold/core-ts-lib": "^1.1.10",
|
|
35
38
|
"bson": "^6.2.0"
|
|
36
39
|
},
|
|
37
40
|
"devDependencies": {
|