Skip to content

Commit

Permalink
Merge pull request #335 from lenneTech/develop
Browse files Browse the repository at this point in the history
Release 10.2.0
  • Loading branch information
kaihaase authored Nov 19, 2023
2 parents c91756e + e94ca18 commit 8b0bc13
Show file tree
Hide file tree
Showing 12 changed files with 1,213 additions and 1,165 deletions.
2,137 changes: 1,043 additions & 1,094 deletions package-lock.json

Large diffs are not rendered by default.

75 changes: 37 additions & 38 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lenne.tech/nest-server",
"version": "10.1.1",
"version": "10.2.0",
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
"keywords": [
"node",
Expand Down Expand Up @@ -62,21 +62,21 @@
"node": ">= 16.13.0"
},
"dependencies": {
"@apollo/gateway": "2.5.6",
"@apollo/gateway": "2.5.7",
"@lenne.tech/mongoose-gridfs": "1.4.2",
"@lenne.tech/multer-gridfs-storage": "5.0.6",
"@nestjs/apollo": "12.0.9",
"@nestjs/common": "10.2.7",
"@nestjs/core": "10.2.7",
"@nestjs/graphql": "12.0.9",
"@nestjs/jwt": "10.1.1",
"@nestjs/mongoose": "10.0.1",
"@nestjs/apollo": "12.0.11",
"@nestjs/common": "10.2.9",
"@nestjs/core": "10.2.9",
"@nestjs/graphql": "12.0.11",
"@nestjs/jwt": "10.2.0",
"@nestjs/mongoose": "10.0.2",
"@nestjs/passport": "10.0.2",
"@nestjs/platform-express": "10.2.7",
"@nestjs/schedule": "3.0.4",
"@nestjs/platform-express": "10.2.9",
"@nestjs/schedule": "4.0.0",
"@nestjs/terminus": "10.1.1",
"apollo-server-core": "3.12.1",
"apollo-server-express": "3.11.1",
"apollo-server-core": "3.13.0",
"apollo-server-express": "3.13.0",
"bcrypt": "5.1.1",
"class-transformer": "0.5.1",
"class-validator": "0.14.0",
Expand All @@ -91,11 +91,11 @@
"json-to-graphql-query": "2.2.5",
"light-my-request": "5.11.0",
"lodash": "4.17.21",
"mongodb": "6.2.0",
"mongoose": "7.6.3",
"mongodb": "6.3.0",
"mongoose": "7.6.5",
"multer": "1.4.5-lts.1",
"node-mailjet": "6.0.4",
"nodemailer": "6.9.6",
"nodemailer": "6.9.7",
"nodemon": "3.0.1",
"passport": "0.6.0",
"passport-jwt": "4.0.1",
Expand All @@ -109,28 +109,27 @@
"@babel/plugin-proposal-private-methods": "7.18.6",
"@compodoc/compodoc": "1.1.22",
"@lenne.tech/eslint-config-ts": "0.0.10",
"@nestjs/cli": "10.1.18",
"@nestjs/schematics": "10.0.2",
"@nestjs/testing": "10.2.7",
"@swc/cli": "0.1.62",
"@swc/core": "1.3.93",
"@nestjs/cli": "10.2.1",
"@nestjs/schematics": "10.0.3",
"@nestjs/testing": "10.2.9",
"@swc/cli": "0.1.63",
"@swc/core": "1.3.96",
"@swc/jest": "0.2.29",
"@types/compression": "1.7.4",
"@types/cookie-parser": "1.4.5",
"@types/cron": "2.0.1",
"@types/ejs": "3.1.4",
"@types/express": "4.17.20",
"@types/jest": "29.5.6",
"@types/lodash": "4.14.200",
"@types/multer": "1.4.9",
"@types/node": "20.8.7",
"@types/nodemailer": "6.4.13",
"@types/passport": "1.0.14",
"@types/supertest": "2.0.15",
"@typescript-eslint/eslint-plugin": "6.8.0",
"@typescript-eslint/parser": "6.8.0",
"@types/compression": "1.7.5",
"@types/cookie-parser": "1.4.6",
"@types/ejs": "3.1.5",
"@types/express": "4.17.21",
"@types/jest": "29.5.8",
"@types/lodash": "4.14.201",
"@types/multer": "1.4.10",
"@types/node": "20.9.1",
"@types/nodemailer": "6.4.14",
"@types/passport": "1.0.15",
"@types/supertest": "2.0.16",
"@typescript-eslint/eslint-plugin": "6.11.0",
"@typescript-eslint/parser": "6.11.0",
"coffeescript": "2.7.0",
"eslint": "8.51.0",
"eslint": "8.54.0",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-unused-imports": "3.0.0",
"find-file-up": "2.0.1",
Expand All @@ -143,12 +142,12 @@
"jest": "29.7.0",
"npm-watch": "0.11.0",
"pm2": "5.3.0",
"prettier": "3.0.3",
"prettier": "3.1.0",
"pretty-quick": "3.1.3",
"supertest": "6.3.3",
"ts-jest": "29.1.1",
"ts-loader": "9.5.0",
"ts-morph": "19.0.0",
"ts-loader": "9.5.1",
"ts-morph": "20.0.0",
"ts-node": "10.9.1",
"tsconfig-paths": "4.2.0",
"typescript": "5.2.2",
Expand Down
2 changes: 1 addition & 1 deletion spectaql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ servers:
info:
title: lT Nest Server
description: Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).
version: 10.1.1
version: 10.2.0
contact:
name: lenne.Tech GmbH
url: https://lenne.tech
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { CronJobParams, CronOnCompleteCommand } from 'cron';
import { CronJobConfig } from './cron-job-config.interface';

/**
* Interface for cron job configuration
*
* This config can define timezone but not utcOffset,
* if you want to use utcOffset, you have to use the CronJobConfigWithUtcOffset
*/
export interface CronJobConfigWithTimeZone<OC extends CronOnCompleteCommand | null = null, C = null> extends CronJobConfig {
/**
* Specify the timezone for the execution. This will modify the actual time relative to your timezone.
* If the timezone is invalid, an error is thrown. Can be any string accepted by luxon's `DateTime.setZone()`
* (https://moment.github.io/luxon/api-docs/index.html#datetimesetzone).
*/
timeZone?: CronJobParams<OC, C>['timeZone'];

/**
* This allows you to specify the offset of the timezone rather than using the `timeZone` parameter.
* Probably don't use both `timeZone` and `utcOffset` together or weird things may happen.
*/
utcOffset?: null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { CronJobParams, CronOnCompleteCommand } from 'cron';
import { CronJobConfig } from './cron-job-config.interface';

/**
* Interface for cron job configuration
*
* This config can define utcOffset but not timezone,
* if you want to use timezone, you have to use the CronJobConfigWithTimezone
*/
export interface CronJobConfigWithUtcOffset<OC extends CronOnCompleteCommand | null = null, C = null> extends CronJobConfig {

/**
* Specify the timezone for the execution. This will modify the actual time relative to your timezone.
* If the timezone is invalid, an error is thrown. Can be any string accepted by luxon's `DateTime.setZone()`
* (https://moment.github.io/luxon/api-docs/index.html#datetimesetzone).
*/
timeZone?: null;

/**
* This allows you to specify the offset of the timezone rather than using the `timeZone` parameter.
* Probably don't use both `timeZone` and `utcOffset` together or weird things may happen.
*/
utcOffset?: CronJobParams<OC, C>['unrefTimeout'];
}
21 changes: 10 additions & 11 deletions src/core/common/interfaces/cron-job-config.interface.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import { CronExpression } from '@nestjs/schedule';
import { CronCommand } from 'cron';
import { Falsy } from '../types/falsy.type';
import { CronJobParams, CronOnCompleteCommand } from 'cron';

/**
* Interface for cron job configuration
* @deprecated Use CronJobConfigWithTimeZone or CronJobConfigWithUtcOffset instead
*/
export interface CronJobConfig {
export interface CronJobConfig<OC extends CronOnCompleteCommand | null = null, C = null> {
/**
* The context within which to execute the onTick method. This defaults to the cronjob itself allowing you to call
* `this.stop()`. However, if you change this you'll have access to the functions and values within your context
* object.
*/
context?: any;
context?: CronJobParams<OC, C>['context'];

/**
* The time to fire off your job. This can be in the form of cron syntax or a JS `Date` object.
*/
cronTime: CronExpression | string | Date | Falsy;
cronTime: CronJobParams<OC, C>['cronTime'];

/**
* Whether the cron job is disabled or not.
Expand All @@ -27,13 +26,13 @@ export interface CronJobConfig {
/**
* A function that will fire when the job is complete, when it is stopped.
*/
onComplete?: CronCommand | null;
onComplete?: CronJobParams<OC, C>['onComplete'];

/**
* This will immediately fire the `onTick` function as soon as the requisite initialization has happened.
* This option is set to `true` by default.
*/
runOnInit?: boolean;
runOnInit?: CronJobParams<OC, C>['runOnInit'];

/**
* Depending on how long the execution of a job takes, it may happen that several executions take place at the
Expand All @@ -53,19 +52,19 @@ export interface CronJobConfig {
* If the timezone is invalid, an error is thrown. Can be any string accepted by luxon's `DateTime.setZone()`
* (https://moment.github.io/luxon/api-docs/index.html#datetimesetzone).
*/
timeZone?: string;
timeZone?: CronJobParams<OC, C>['timeZone'] | null;

/**
* If you have code that keeps the event loop running and want to stop the node process when that finishes
* regardless of the state of your cronjob, you can do so making use of this parameter. This is off by default and
* cron will run as if it needs to control the event loop. For more information take a look at
* timers#timers_timeout_unref from the NodeJS docs.
*/
unrefTimeout?: boolean;
unrefTimeout?: CronJobParams<OC, C>['unrefTimeout'];

/**
* This allows you to specify the offset of the timezone rather than using the `timeZone` parameter.
* Probably don't use both `timeZone` and `utcOffset` together or weird things may happen.
*/
utcOffset?: string | number;
utcOffset?: CronJobParams<OC, C>['unrefTimeout'] | null;
}
5 changes: 3 additions & 2 deletions src/core/common/interfaces/server-options.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import * as SMTPTransport from 'nodemailer/lib/smtp-transport';
import { MongoosePingCheckSettings } from '@nestjs/terminus/dist/health-indicator/database/mongoose.health';
import { DiskHealthIndicatorOptions } from '@nestjs/terminus/dist/health-indicator/disk/disk-health-options.type';
import { Falsy } from '../types/falsy.type';
import { CronJobConfig } from './cron-job-config.interface';
import { CronJobConfigWithTimeZone } from './cron-job-config-with-time-zone.interface';
import { CronJobConfigWithUtcOffset } from './cron-job-config-with-utc-offset.interface';
import { MailjetOptions } from './mailjet-options.interface';

/**
Expand Down Expand Up @@ -85,7 +86,7 @@ export interface IServerOptions {
* Cron jobs configuration object with the name of the cron job function as key
* and the cron expression or config as value
*/
cronJobs?: Record<string, CronExpression | string | Date | Falsy | CronJobConfig>;
cronJobs?: Record<string, CronExpression | string | Date | Falsy | CronJobConfigWithTimeZone | CronJobConfigWithUtcOffset>;

/**
* SMTP and template configuration for sending emails
Expand Down
17 changes: 10 additions & 7 deletions src/core/common/services/core-cron-jobs.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { OnApplicationBootstrap } from '@nestjs/common';
import { CronExpression, SchedulerRegistry } from '@nestjs/schedule';
import { CronJob } from 'cron';
import { CronJobConfig } from '../interfaces/cron-job-config.interface';
import { CronJobConfigWithTimeZone } from '../interfaces/cron-job-config-with-time-zone.interface';
import { CronJobConfigWithUtcOffset } from '../interfaces/cron-job-config-with-utc-offset.interface';
import { Falsy } from '../types/falsy.type';

/**
Expand Down Expand Up @@ -30,7 +31,7 @@ export abstract class CoreCronJobs implements OnApplicationBootstrap {
*/
protected constructor(
protected schedulerRegistry: SchedulerRegistry,
protected cronJobs: Record<string, CronExpression | string | Date | Falsy | CronJobConfig>,
protected cronJobs: Record<string, CronExpression | string | Date | Falsy | CronJobConfigWithTimeZone | CronJobConfigWithUtcOffset>,
options?: { log?: boolean },
) {
this.config = {
Expand Down Expand Up @@ -64,27 +65,29 @@ export abstract class CoreCronJobs implements OnApplicationBootstrap {
// Check config
if (
!CronExpressionOrConfig
|| (typeof CronExpressionOrConfig === 'object' && (CronExpressionOrConfig as CronJobConfig).disabled)
|| (typeof CronExpressionOrConfig === 'object' && (CronExpressionOrConfig as CronJobConfigWithTimeZone).disabled)
) {
continue;
}

// Prepare config
let conf: CronJobConfig = (CronExpressionOrConfig as CronJobConfig);
let conf: CronJobConfigWithTimeZone | CronJobConfigWithUtcOffset
= CronExpressionOrConfig as CronJobConfigWithTimeZone | CronJobConfigWithUtcOffset;
if (typeof CronExpressionOrConfig === 'string' || CronExpressionOrConfig instanceof Date) {
conf = {
cronTime: CronExpressionOrConfig as string | Date,
};
}

// Set defaults
const config: CronJobConfig = {
// Declared as CronJobConfigWithTimeZone to avoid type errors, but it can also be CronJobConfigWithUtcOffset
const config: CronJobConfigWithTimeZone = {
runOnInit: true,
runParallel: true,
throwException: true,
timeZone: 'Europe/Berlin',
timeZone: conf.utcOffset ? null : 'Europe/Berlin',
...conf,
};
} as unknown as CronJobConfigWithTimeZone;

// Check if cron job should be activated
if (!config?.cronTime) {
Expand Down
42 changes: 40 additions & 2 deletions src/core/common/services/crud.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { NotFoundException } from '@nestjs/common';
import { FilterQuery, PipelineStage, QueryOptions } from 'mongoose';
import { Document, FilterQuery, Model as MongooseModel, PipelineStage, Query, QueryOptions } from 'mongoose';
import { FilterArgs } from '../args/filter.args';
import { getStringIds } from '../helpers/db.helper';
import { getStringIds, popAndMap } from '../helpers/db.helper';
import { convertFilterArgsToQuery } from '../helpers/filter.helper';
import { mergePlain, prepareServiceOptionsForCreate } from '../helpers/input.helper';
import { ServiceOptions } from '../interfaces/service-options.interface';
import { CoreModel } from '../models/core-model.model';
import { ArrayElement } from '../types/array-element.type';
import { FieldSelection } from '../types/field-selection.type';
import { PlainObject } from '../types/plain-object.type';
import { ConfigService } from './config.service';
import { ModuleService } from './module.service';
Expand Down Expand Up @@ -474,4 +476,40 @@ export abstract class CrudService<
serviceOptions.prepareOutput = null;
return this.deleteForce(id, serviceOptions);
}

/**
* Populate, exec and map Mongoose query or document(s) with serviceOptions
* Generic T is the type of the returned object(s)
*
* @example const user = await this.populateAndProcessQuery<User>(User.findById(id), serviceOptions);
* @example const users = await this.populateAndProcessQuery<User[]>(User.find({name: {'$regex': 'ma'}}), serviceOptions);
*/
async populateAndProcessQuery<T extends CoreModel | CoreModel[] = CoreModel>(
queryOrDocument: Query<unknown, unknown> | Document | Document[],
options?: {
fieldSelection?: FieldSelection;
ignoreSelections?: boolean;
modelClass?: new (...args: any[]) => ArrayElement<T>;
populate?: FieldSelection;
mongooseModel?: MongooseModel<any>;
},
): Promise<T> {
const config = {
modelClass: this.mainModelConstructor,
mongooseModel: this.mainDbModel,
...options,
};
let result: T;
if (config.fieldSelection || config.populate) {
result = (await popAndMap<ArrayElement<T>>(
queryOrDocument,
config.populate || config.fieldSelection,
config.modelClass as new (...args: any[]) => ArrayElement<T>,
config.mongooseModel)
) as T;
} else if (queryOrDocument instanceof Query) {
result = (await queryOrDocument.exec()) as T;
}
return result;
}
}
5 changes: 5 additions & 0 deletions src/core/common/types/array-element.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Get type of array elements
*/
export type ArrayElement<ArrayType extends (unknown | unknown[])> =
ArrayType extends readonly (infer ElementType)[] ? ElementType : ArrayType;
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export * from './core/common/interceptors/check-response.interceptor';
export * from './core/common/interceptors/check-security.interceptor';
export * from './core/common/interfaces/core-persistence-model.interface';
export * from './core/common/interfaces/cron-job-config.interface';
export * from './core/common/interfaces/cron-job-config-with-time-zone.interface';
export * from './core/common/interfaces/cron-job-config-with-utc-offset.interface';
export * from './core/common/interfaces/mailjet-options.interface';
export * from './core/common/interfaces/prepare-input-options.interface';
export * from './core/common/interfaces/prepare-output-options.interface';
Expand All @@ -67,6 +69,7 @@ export * from './core/common/services/mailjet.service';
export * from './core/common/services/model-doc.service';
export * from './core/common/services/module.service';
export * from './core/common/services/template.service';
export * from './core/common/types/array-element.type';
export * from './core/common/types/core-model-constructor.type';
export * from './core/common/types/falsy.type';
export * from './core/common/types/field-selection.type';
Expand Down
Loading

0 comments on commit 8b0bc13

Please sign in to comment.