aboutsummaryrefslogtreecommitdiff
path: root/lib/model.ts
diff options
context:
space:
mode:
authoreug-vs <eug-vs@keemail.me>2020-12-02 00:29:25 +0300
committereug-vs <eug-vs@keemail.me>2020-12-02 00:29:25 +0300
commit972e0578f999aadb5924d84768e59445c92f167b (patch)
tree7ec9a8c09f33b8a6f2aa0b3db5fb93889f410a29 /lib/model.ts
parentfc3701733fca3fccd8330aaa5095fdcd82daf2b7 (diff)
downloadmongo-cronjob-972e0578f999aadb5924d84768e59445c92f167b.tar.gz
feat: add schema and model
Diffstat (limited to 'lib/model.ts')
-rw-r--r--lib/model.ts87
1 files changed, 87 insertions, 0 deletions
diff --git a/lib/model.ts b/lib/model.ts
new file mode 100644
index 0000000..77fede0
--- /dev/null
+++ b/lib/model.ts
@@ -0,0 +1,87 @@
+import { model, Schema, Model } from 'mongoose';
+import createEventSchema, { EventDocument } from './schema';
+import cron from 'cron';
+
+interface Event<Context> extends EventDocument<Context> {
+ log(message: string): void;
+ start(): void;
+ complete(): void;
+ fail(): void;
+ computeNextRunAt(): Date;
+}
+
+const CronJob = cron.CronJob;
+
+const createEventModel = <Context extends Schema>(name: string, contextSchema: Context) => {
+ const schema = createEventSchema(contextSchema);
+
+ // Schema methods
+ schema.method('log', function(message: string) {
+ // TODO: Actually create logs
+ console.log(message);
+ });
+
+ schema.method('start', function() {
+ this.log('Event started')
+ this.lastRunAt = new Date();
+ this.status = 'running';
+ return this.save();
+ });
+
+ schema.method('complete', function() {
+ this.log('Event complete')
+ this.status = 'complete';
+ return this.save();
+ });
+
+ schema.method('fail', function(error: Error) {
+ this.log(error);
+ this.error = error;
+ this.status = 'failed';
+ return this.save();
+ });
+
+ schema.method('computeNextRunAt', function() {
+ const job = new CronJob(this.schedule);
+ const nextRunAt = job.nextDates();
+ return nextRunAt.toDate();
+ });
+
+ // Statics
+ schema.static('findMissedEvents', async function () {
+ return this.find({
+ nextRunAt: {
+ // TODO: skip single-fire events
+ $lt: new Date()
+ },
+ });
+ });
+
+ schema.static('findNextEvents', function(limit = 10) {
+ return this.find(
+ {
+ nextRunAt: {
+ $gt: new Date()
+ },
+ },
+ null,
+ {
+ sort: {
+ nextRunAt: 1
+ },
+ limit
+ }
+ )
+ });
+
+ // Hooks
+ schema.pre<Event<Context>>('save', async function() {
+ this.nextRunAt = this.computeNextRunAt();
+ });
+
+ return model<Event<Context>>(name, schema);
+};
+
+
+export default createEventModel;
+