zync-nest-data-module 1.0.0 → 1.1.38
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/.prettierrc.json +23 -0
- package/README.md +226 -439
- package/dist/backup/backup.module.d.ts +1 -1
- package/dist/backup/backup.module.js +6 -6
- package/dist/backup/backup.module.js.map +1 -1
- package/dist/backup/backup.service.d.ts +1 -0
- package/dist/backup/backup.service.js +41 -18
- package/dist/backup/backup.service.js.map +1 -1
- package/dist/backup/backup.worker.d.ts +1 -0
- package/dist/backup/backup.worker.js +43 -0
- package/dist/backup/backup.worker.js.map +1 -0
- package/dist/base/dto.d.ts +19 -0
- package/dist/base/dto.js +86 -0
- package/dist/base/dto.js.map +1 -0
- package/dist/base/index.d.ts +2 -0
- package/dist/base/index.js +19 -0
- package/dist/base/index.js.map +1 -0
- package/dist/base/resolver.d.ts +6 -0
- package/dist/base/resolver.js +54 -0
- package/dist/base/resolver.js.map +1 -0
- package/dist/database/database.module.d.ts +5 -1
- package/dist/database/database.module.js +24 -19
- package/dist/database/database.module.js.map +1 -1
- package/dist/database/database.repository.d.ts +3 -2
- package/dist/database/database.repository.js +32 -25
- package/dist/database/database.repository.js.map +1 -1
- package/dist/database/database.scheme.d.ts +2 -8
- package/dist/database/database.scheme.js +2 -2
- package/dist/database/database.scheme.js.map +1 -1
- package/dist/database/database.service.d.ts +5 -3
- package/dist/database/database.service.js +44 -17
- package/dist/database/database.service.js.map +1 -1
- package/dist/database/database.transaction.d.ts +7 -7
- package/dist/database/database.transaction.js +61 -50
- package/dist/database/database.transaction.js.map +1 -1
- package/dist/database/database.uniqueId.d.ts +8 -3
- package/dist/database/database.uniqueId.js +26 -7
- package/dist/database/database.uniqueId.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/redis/index.d.ts +2 -0
- package/dist/redis/index.js +19 -0
- package/dist/redis/index.js.map +1 -0
- package/dist/redis/redis.module.d.ts +2 -0
- package/dist/redis/redis.module.js +43 -0
- package/dist/redis/redis.module.js.map +1 -0
- package/dist/redis/redis.service.d.ts +27 -0
- package/dist/redis/redis.service.js +126 -0
- package/dist/redis/redis.service.js.map +1 -0
- package/dist/service/service.d.ts +2 -2
- package/dist/service/service.js +42 -56
- package/dist/service/service.js.map +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/libs/src/app.controller.ts +53 -46
- package/libs/src/app.module.ts +13 -10
- package/libs/src/backup/backup.module.ts +2 -2
- package/libs/src/backup/backup.service.ts +60 -69
- package/libs/src/backup/backup.worker.ts +35 -0
- package/libs/src/base/dto.ts +46 -0
- package/libs/src/base/index.ts +2 -0
- package/libs/src/base/resolver.ts +20 -0
- package/libs/src/database/database.module.ts +24 -22
- package/libs/src/database/database.repository.ts +47 -50
- package/libs/src/database/database.scheme.ts +2 -2
- package/libs/src/database/database.service.ts +61 -22
- package/libs/src/database/database.transaction.ts +62 -64
- package/libs/src/database/database.uniqueId.ts +39 -8
- package/libs/src/index.ts +3 -1
- package/libs/src/main.ts +8 -18
- package/libs/src/redis/index.ts +2 -0
- package/libs/src/redis/redis.interface.ts +34 -0
- package/libs/src/redis/redis.module.ts +30 -0
- package/libs/src/redis/redis.service.ts +137 -0
- package/libs/src/service/service.ts +48 -68
- package/libs/src/test/test.controller.ts +59 -0
- package/libs/src/test/test.module.ts +8 -4
- package/libs/src/test/test.redis.ts +19 -0
- package/libs/src/test/test.resolver.ts +10 -19
- package/package.json +45 -26
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/redis/redis.module.ts
|
|
2
|
+
import { Global, Module } from "@nestjs/common";
|
|
3
|
+
import Redis from "ioredis";
|
|
4
|
+
import { ConfigModule } from "@nestjs/config";
|
|
5
|
+
import { RedisService } from "./redis.service";
|
|
6
|
+
|
|
7
|
+
@Global()
|
|
8
|
+
@Module({
|
|
9
|
+
imports: [ConfigModule],
|
|
10
|
+
providers: [
|
|
11
|
+
{
|
|
12
|
+
provide: "REDIS_CLIENT",
|
|
13
|
+
useFactory: async () => {
|
|
14
|
+
const client = new Redis({
|
|
15
|
+
host: process.env.redis_host || "127.0.0.1",
|
|
16
|
+
port: Number(process.env.redis_port) || 6379,
|
|
17
|
+
password: process.env.redis_password || undefined,
|
|
18
|
+
db: Number(process.env.redis_database) || 0
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
client.on("connect", () => console.log("✅ Redis connected"));
|
|
22
|
+
client.on("error", (err) => console.error("❌ Redis error:", err));
|
|
23
|
+
|
|
24
|
+
return client;
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
exports: ["REDIS_CLIENT", RedisService]
|
|
29
|
+
})
|
|
30
|
+
export class RedisModule { }
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Injectable, Logger } from "@nestjs/common";
|
|
2
|
+
import { RedisPubSub } from "graphql-redis-subscriptions";
|
|
3
|
+
import { EntityData, Client as RedisOmClient, Repository, Schema, SchemaDefinition, Search } from "redis-om";
|
|
4
|
+
import { IPageParams } from "../database/database.scheme";
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export abstract class RedisService<T extends EntityData> extends RedisPubSub {
|
|
8
|
+
private readonly logger = new Logger(RedisService.name);
|
|
9
|
+
public readonly baseKey = `${process.env.redis_prefix || "zync_redis_data"}:`;
|
|
10
|
+
private redisOmClient: RedisOmClient | null = null;
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
super({
|
|
14
|
+
connection: {
|
|
15
|
+
host: process.env.redis_host || "localhost",
|
|
16
|
+
port: Number(process.env.redis_port) || 6379,
|
|
17
|
+
username: process.env.redis_username || undefined,
|
|
18
|
+
password: process.env.redis_password || undefined,
|
|
19
|
+
db: Number(process.env.redis_database) || 0
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public abstract cacheKey: string;
|
|
25
|
+
|
|
26
|
+
protected abstract buildQuery(search: Search, query: any): Search;
|
|
27
|
+
|
|
28
|
+
protected abstract mapSchema(): Record<string, any>;
|
|
29
|
+
|
|
30
|
+
protected async repository(): Promise<Repository<T>> {
|
|
31
|
+
const schema = this.createSchema(this.cacheKey, this.mapSchema());
|
|
32
|
+
const repository = await this.getRepository(schema);
|
|
33
|
+
try {
|
|
34
|
+
await repository.createIndex();
|
|
35
|
+
} catch (error) {
|
|
36
|
+
this.logger.error(`Error creating index for ${this.cacheKey}: ${error}`);
|
|
37
|
+
}
|
|
38
|
+
return repository;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private createSchema<M extends EntityData>(name: string, fields: Record<string, any>): Schema<M> {
|
|
42
|
+
return new Schema<M>(`${this.baseKey}${name}`, fields as SchemaDefinition<M>, {
|
|
43
|
+
dataStructure: "JSON",
|
|
44
|
+
indexName: `${this.baseKey}${name}:idx`
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private async getRedisOmClient(): Promise<RedisOmClient> {
|
|
49
|
+
if (this.redisOmClient) return this.redisOmClient;
|
|
50
|
+
|
|
51
|
+
const host = process.env.redis_host || "127.0.0.1";
|
|
52
|
+
const port = Number(process.env.redis_port) || 6379;
|
|
53
|
+
const password = process.env.redis_password;
|
|
54
|
+
const db = Number(process.env.redis_database) || 0;
|
|
55
|
+
|
|
56
|
+
const authSegment = password ? `:${password}@` : "";
|
|
57
|
+
const url = `redis://${authSegment}${host}:${port}/${db}`;
|
|
58
|
+
|
|
59
|
+
const client = new RedisOmClient();
|
|
60
|
+
await client.open(url);
|
|
61
|
+
this.redisOmClient = client;
|
|
62
|
+
return client;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async getRepository(schema: Schema<any>): Promise<Repository<any>> {
|
|
66
|
+
return (await this.getRedisOmClient()).fetchRepository(schema);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
public async create(data: Partial<T> | T): Promise<T> {
|
|
71
|
+
const repository = await this.repository();
|
|
72
|
+
const _id = (data as any)._id as string;
|
|
73
|
+
const existing = _id ? await this.findById(_id) : null;
|
|
74
|
+
if (existing) {
|
|
75
|
+
return await this.update(_id, data);
|
|
76
|
+
}
|
|
77
|
+
return await repository.save(JSON.parse(JSON.stringify(data)));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public async update(_id: string, data: Partial<T> | T): Promise<T> {
|
|
81
|
+
const repository = await this.repository();
|
|
82
|
+
const entityId = await this.getEntityId(_id);
|
|
83
|
+
|
|
84
|
+
// Fetch the entity with its internal metadata (including entityId)
|
|
85
|
+
const entity = await repository.fetch(entityId);
|
|
86
|
+
|
|
87
|
+
// Update the entity properties
|
|
88
|
+
Object.assign(entity, JSON.parse(JSON.stringify(data)));
|
|
89
|
+
|
|
90
|
+
return await repository.save(entity);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public async delete(id: string): Promise<boolean> {
|
|
94
|
+
const repository = await this.repository();
|
|
95
|
+
await repository.remove(await this.getEntityId(id));
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public async findById(_id: string): Promise<T> {
|
|
100
|
+
const repository = await this.repository();
|
|
101
|
+
return await repository
|
|
102
|
+
.search()
|
|
103
|
+
.where("_id" as any)
|
|
104
|
+
.eq(_id)
|
|
105
|
+
.return.first();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
public async getEntityId(_id: string): Promise<string> {
|
|
110
|
+
const repository = await this.repository();
|
|
111
|
+
return await repository
|
|
112
|
+
.search()
|
|
113
|
+
.where("_id" as any)
|
|
114
|
+
.eq(_id)
|
|
115
|
+
.return.firstId();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public async findOne(query: Partial<T>): Promise<T> {
|
|
119
|
+
const repository = await this.repository();
|
|
120
|
+
const search = this.buildQuery(repository.search(), query);
|
|
121
|
+
return (await search.return.first()) as T;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public async find(query: Partial<T>): Promise<T[]> {
|
|
125
|
+
const repository = await this.repository();
|
|
126
|
+
const search = this.buildQuery(repository.search(), query);
|
|
127
|
+
return (await search.return.all()) as T[];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public async page(query: Partial<T> & IPageParams): Promise<{ totalRecords: number; data: Array<Partial<T>> }> {
|
|
131
|
+
const repository = await this.repository();
|
|
132
|
+
const search = this.buildQuery(repository.search(), query);
|
|
133
|
+
const totalRecords = await search.return.count();
|
|
134
|
+
const data = (await search.return.page(query.skip, query.take)) as T[];
|
|
135
|
+
return { totalRecords, data };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { forwardRef, Inject } from "@nestjs/common";
|
|
1
|
+
import { forwardRef, Inject, Logger } from "@nestjs/common";
|
|
2
2
|
import { AbstractBaseRepository, IPageParams, TransactionManager, TransactionSession } from "../database";
|
|
3
3
|
|
|
4
4
|
class BaseService<T> {
|
|
5
5
|
constructor(
|
|
6
6
|
@Inject(forwardRef(() => AbstractBaseRepository))
|
|
7
7
|
protected readonly repository: AbstractBaseRepository<any>
|
|
8
|
-
) {}
|
|
8
|
+
) { }
|
|
9
9
|
|
|
10
10
|
public async create(data: Partial<T> | T): Promise<T> {
|
|
11
11
|
return await this.repository.create(data);
|
|
@@ -57,7 +57,7 @@ class BaseService<T> {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export abstract class AbstractBaseService<T> extends BaseService<T> {
|
|
60
|
-
|
|
60
|
+
protected readonly logger: Logger = new Logger(AbstractBaseService.name);
|
|
61
61
|
constructor(
|
|
62
62
|
@Inject(forwardRef(() => AbstractBaseRepository))
|
|
63
63
|
protected readonly repository: AbstractBaseRepository<any>,
|
|
@@ -69,60 +69,53 @@ export abstract class AbstractBaseService<T> extends BaseService<T> {
|
|
|
69
69
|
|
|
70
70
|
protected abstract setSession(session: any): void;
|
|
71
71
|
|
|
72
|
-
public get session(): TransactionSession {
|
|
73
|
-
return this._session;
|
|
74
|
-
}
|
|
75
72
|
|
|
76
|
-
public
|
|
77
|
-
|
|
78
|
-
this.repository.session = this._session;
|
|
73
|
+
public get session(): TransactionSession {
|
|
74
|
+
return TransactionManager.getCurrentSession();
|
|
79
75
|
}
|
|
80
76
|
|
|
81
77
|
public get sessionName(): string {
|
|
82
78
|
return this.transactionManager.sessionName;
|
|
83
79
|
}
|
|
84
80
|
|
|
85
|
-
public async withRetryTransaction(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
await this.startSession(sessionName, true);
|
|
109
|
-
} else {
|
|
110
|
-
await this.abortSession();
|
|
111
|
-
throw error;
|
|
81
|
+
public async withRetryTransaction(sessionName: string, operations: () => Promise<T>, retries: number = 3): Promise<T> {
|
|
82
|
+
if (process.env.mongodb_transaction_enable !== "true") return await operations();
|
|
83
|
+
|
|
84
|
+
return this.transactionManager.run(async () => {
|
|
85
|
+
try {
|
|
86
|
+
await this.startSession(sessionName);
|
|
87
|
+
|
|
88
|
+
let attempt = 0;
|
|
89
|
+
while (attempt < retries) {
|
|
90
|
+
try {
|
|
91
|
+
const op = await operations();
|
|
92
|
+
await this.commitSession(sessionName);
|
|
93
|
+
return op;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (this.isRetryableError(error)) {
|
|
96
|
+
this.logger.log(`[TransactionManager] Retrying transaction...`);
|
|
97
|
+
await this.delay(1000 * (attempt + 1)); // Exponential backoff
|
|
98
|
+
await this.transactionManager.abortTransaction();
|
|
99
|
+
await this.startSession(sessionName, true);
|
|
100
|
+
} else {
|
|
101
|
+
await this.abortSession();
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
112
104
|
}
|
|
105
|
+
attempt++;
|
|
106
|
+
}
|
|
107
|
+
} catch (error) {
|
|
108
|
+
this.logger.error(`[TransactionManager] Error in transaction`, error);
|
|
109
|
+
await this.abortSession();
|
|
110
|
+
throw error;
|
|
111
|
+
} finally {
|
|
112
|
+
this.logger.log(`[TransactionManager] Finally block`);
|
|
113
|
+
if (this.transactionManager.sessionName == sessionName) {
|
|
114
|
+
await this.endSession();
|
|
113
115
|
}
|
|
114
|
-
attempt++;
|
|
115
|
-
}
|
|
116
|
-
} catch (error) {
|
|
117
|
-
console.log(`[TransactionManager] Error in transaction`, error);
|
|
118
|
-
await this.abortSession();
|
|
119
|
-
throw error;
|
|
120
|
-
} finally {
|
|
121
|
-
console.log(`[TransactionManager] Finally block`);
|
|
122
|
-
if (this.transactionManager.sessionName == sessionName) {
|
|
123
|
-
await this.endSession();
|
|
124
116
|
}
|
|
125
|
-
}
|
|
117
|
+
});
|
|
118
|
+
|
|
126
119
|
}
|
|
127
120
|
|
|
128
121
|
private isRetryableError(error: any): boolean {
|
|
@@ -137,51 +130,38 @@ export abstract class AbstractBaseService<T> extends BaseService<T> {
|
|
|
137
130
|
|
|
138
131
|
protected async startSession(sessionName: string, force: boolean = false) {
|
|
139
132
|
if (this.transactionManager.sessionName && !force) {
|
|
140
|
-
this.
|
|
141
|
-
this.repository.session = this._session;
|
|
142
|
-
console.log(
|
|
143
|
-
`[TransactionManager] startSession ${this.transactionManager.sessionName} - ${sessionName} is already active`
|
|
144
|
-
);
|
|
133
|
+
this.logger.log(`[TransactionManager] startSession ${this.transactionManager.sessionName} - ${sessionName} is already active`);
|
|
145
134
|
return;
|
|
146
135
|
}
|
|
147
136
|
|
|
148
|
-
|
|
137
|
+
this.logger.log(`[TransactionManager] startSession ${sessionName} is started`);
|
|
149
138
|
|
|
150
|
-
|
|
151
|
-
this.repository.session = this._session;
|
|
139
|
+
await this.transactionManager.startTransaction();
|
|
152
140
|
this.transactionManager.sessionName = sessionName;
|
|
153
|
-
|
|
141
|
+
|
|
154
142
|
}
|
|
155
143
|
|
|
156
144
|
protected async commitSession(sessionName: string) {
|
|
157
145
|
if (this.transactionManager.sessionName !== sessionName) {
|
|
158
|
-
|
|
159
|
-
`[TransactionManager] Session ${this.transactionManager.sessionName} - ${sessionName} is not active`
|
|
160
|
-
);
|
|
146
|
+
this.logger.log(`[TransactionManager] Session ${this.transactionManager.sessionName} - ${sessionName} is not active`);
|
|
161
147
|
return;
|
|
162
148
|
}
|
|
163
149
|
|
|
164
150
|
await this.transactionManager.commitTransaction();
|
|
165
|
-
this._session = null;
|
|
166
|
-
this.repository.session = null;
|
|
167
151
|
this.transactionManager.sessionName = undefined;
|
|
168
|
-
|
|
152
|
+
|
|
169
153
|
}
|
|
170
154
|
|
|
171
155
|
public async abortSession() {
|
|
172
156
|
await this.transactionManager.abortTransaction();
|
|
173
|
-
this._session = null;
|
|
174
|
-
this.repository.session = null;
|
|
175
157
|
this.transactionManager.sessionName = undefined;
|
|
176
|
-
|
|
158
|
+
|
|
177
159
|
}
|
|
178
160
|
|
|
179
161
|
public async endSession() {
|
|
180
162
|
await this.transactionManager.endTransaction();
|
|
181
|
-
this._session = null;
|
|
182
|
-
this.repository.session = null;
|
|
183
163
|
this.transactionManager.sessionName = undefined;
|
|
184
|
-
|
|
164
|
+
|
|
185
165
|
}
|
|
186
166
|
|
|
187
167
|
protected getObjectId(): string | any {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Body, Controller, Delete, Get, Param, Post, Put, Query } from "@nestjs/common";
|
|
2
|
+
import { ApiOperation, ApiParam, ApiQuery, ApiResponse, ApiTags } from "@nestjs/swagger";
|
|
3
|
+
import { CreateTestInput, Test, TestPageInput, TestPageResult, TestQueryInput, UpdateTestInput } from "./test.dto";
|
|
4
|
+
import { TestRedisService } from "./test.redis";
|
|
5
|
+
|
|
6
|
+
@ApiTags("Test")
|
|
7
|
+
@Controller("test")
|
|
8
|
+
export class TestController {
|
|
9
|
+
constructor(private readonly testRedisSvc: TestRedisService) {}
|
|
10
|
+
|
|
11
|
+
@Post()
|
|
12
|
+
@ApiOperation({ summary: "Create Test" })
|
|
13
|
+
@ApiResponse({ status: 201, description: "Test created successfully", type: Test })
|
|
14
|
+
public async create(@Body() test: CreateTestInput): Promise<Test> {
|
|
15
|
+
return this.testRedisSvc.create(test as any);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@Put(":id")
|
|
19
|
+
@ApiOperation({ summary: "Update Test" })
|
|
20
|
+
@ApiParam({ name: "id", description: "Test ID" })
|
|
21
|
+
@ApiResponse({ status: 200, description: "Test updated", type: Test })
|
|
22
|
+
public async update(@Param("id") id: string, @Body() test: UpdateTestInput): Promise<Test> {
|
|
23
|
+
return this.testRedisSvc.update(id, { ...test } as any);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Delete(":id")
|
|
27
|
+
@ApiOperation({ summary: "Delete Test" })
|
|
28
|
+
@ApiParam({ name: "id", description: "Test ID" })
|
|
29
|
+
@ApiResponse({ status: 200, description: "Test deleted" })
|
|
30
|
+
public async delete(@Param("id") id: string): Promise<{ success: boolean }> {
|
|
31
|
+
await this.testRedisSvc.delete(id);
|
|
32
|
+
return { success: true };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Get("findOne")
|
|
36
|
+
@ApiOperation({ summary: "Find one Test" })
|
|
37
|
+
@ApiQuery({ name: "_id", required: false, description: "Test ID" })
|
|
38
|
+
@ApiResponse({ status: 200, description: "Returns the found test", type: Test })
|
|
39
|
+
public async findOne(@Query() query: TestQueryInput): Promise<Test> {
|
|
40
|
+
return this.testRedisSvc.findOne(query as any);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Get("find")
|
|
44
|
+
@ApiOperation({ summary: "Find Tests" })
|
|
45
|
+
@ApiQuery({ name: "query", required: false, description: "Test query" })
|
|
46
|
+
@ApiResponse({ status: 200, description: "Returns the found tests", type: [Test] })
|
|
47
|
+
public async find(@Query() query: TestQueryInput): Promise<Test[]> {
|
|
48
|
+
return this.testRedisSvc.find(query as any);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Get("page")
|
|
52
|
+
@ApiOperation({ summary: "Get paginated list of Tests" })
|
|
53
|
+
@ApiQuery({ name: "page", type: "number", required: false })
|
|
54
|
+
@ApiQuery({ name: "limit", type: "number", required: false })
|
|
55
|
+
@ApiResponse({ status: 200, description: "Returns a page of tests", type: TestPageResult })
|
|
56
|
+
public async page(@Query() pageQuery: TestPageInput): Promise<{ totalRecords: number; data: Array<Partial<Test>> }> {
|
|
57
|
+
return this.testRedisSvc.page({ ...pageQuery } as any);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { forwardRef, Module } from "@nestjs/common";
|
|
2
2
|
import { MongooseModule } from "@nestjs/mongoose";
|
|
3
|
+
import { DatabaseModule } from "../database";
|
|
3
4
|
import { TestRepository } from "./test.repository";
|
|
4
5
|
import { TestResolver } from "./test.resolver";
|
|
5
6
|
import { Test, TestSchema } from "./test.schema";
|
|
6
7
|
import { TestService } from "./test.service";
|
|
8
|
+
import { TestController } from "./test.controller";
|
|
9
|
+
import { TestRedisService } from "./test.redis";
|
|
7
10
|
|
|
8
11
|
const TestMongooseModule = MongooseModule.forFeature([
|
|
9
12
|
{
|
|
10
13
|
name: Test.name,
|
|
11
|
-
schema: TestSchema
|
|
12
|
-
}
|
|
14
|
+
schema: TestSchema
|
|
15
|
+
}
|
|
13
16
|
]);
|
|
14
17
|
|
|
15
18
|
@Module({
|
|
16
|
-
imports: [TestMongooseModule],
|
|
17
|
-
providers: [TestRepository, TestService, TestResolver],
|
|
19
|
+
imports: [TestMongooseModule, DatabaseModule.forFeature([{ name: Test.name, schema: TestSchema }])],
|
|
20
|
+
providers: [TestRepository, TestService, TestResolver, TestRedisService],
|
|
18
21
|
exports: [TestService],
|
|
22
|
+
controllers: [TestController]
|
|
19
23
|
})
|
|
20
24
|
export class TestModule {}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EntityData } from "redis-om";
|
|
2
|
+
import { RedisService } from "../redis/redis.service";
|
|
3
|
+
import { Test } from "./test.schema";
|
|
4
|
+
|
|
5
|
+
export class TestRedisService extends RedisService<Test & EntityData & { _id: string }> {
|
|
6
|
+
public cacheKey = "test";
|
|
7
|
+
|
|
8
|
+
public mapSchema(): Record<string, any> {
|
|
9
|
+
return {
|
|
10
|
+
name: { type: "string", index: true },
|
|
11
|
+
createdAt: { type: "number" },
|
|
12
|
+
updatedAt: { type: "number" }
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public buildQuery(query: any): any {
|
|
17
|
+
return query;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -1,44 +1,35 @@
|
|
|
1
1
|
import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
|
|
2
|
-
import {
|
|
3
|
-
CreateTestInput,
|
|
4
|
-
Test,
|
|
5
|
-
TestPageInput,
|
|
6
|
-
TestPageResult,
|
|
7
|
-
TestQueryInput,
|
|
8
|
-
UpdateTestInput,
|
|
9
|
-
} from "./test.dto";
|
|
2
|
+
import { CreateTestInput, Test, TestPageInput, TestPageResult, TestQueryInput, UpdateTestInput } from "./test.dto";
|
|
10
3
|
import { TestService } from "./test.service";
|
|
4
|
+
import { TestRedisService } from "./test.redis";
|
|
11
5
|
|
|
12
6
|
@Resolver(() => Test)
|
|
13
7
|
export class TestResolver {
|
|
14
|
-
constructor(private readonly testSvc: TestService) {}
|
|
8
|
+
constructor(private readonly testSvc: TestService, private readonly testRedisSvc: TestRedisService) {}
|
|
15
9
|
|
|
16
10
|
@Mutation((returns) => Test, { name: "createTest" })
|
|
17
|
-
public async create(@Args("test")
|
|
18
|
-
return this.
|
|
11
|
+
public async create(@Args("test") test: CreateTestInput) {
|
|
12
|
+
return this.testRedisSvc.create(test as any);
|
|
19
13
|
}
|
|
20
14
|
|
|
21
15
|
@Mutation((returns) => Test, { name: "updateTest" })
|
|
22
|
-
public async update(
|
|
23
|
-
|
|
24
|
-
@Args("test") test: UpdateTestInput
|
|
25
|
-
) {
|
|
26
|
-
return this.testSvc.update(id, { ...test } as any);
|
|
16
|
+
public async update(@Args("_id") id: string, @Args("test") test: UpdateTestInput) {
|
|
17
|
+
return this.testRedisSvc.update(id, { ...test } as any);
|
|
27
18
|
}
|
|
28
19
|
|
|
29
20
|
@Mutation((returns) => Boolean, { name: "deleteTest" })
|
|
30
21
|
public async delete(@Args("_id") id: string) {
|
|
31
|
-
await this.
|
|
22
|
+
await this.testRedisSvc.delete(id);
|
|
32
23
|
return true;
|
|
33
24
|
}
|
|
34
25
|
|
|
35
26
|
@Query((returns) => Test, { name: "findOneTest" })
|
|
36
27
|
public async findOne(@Args("test") test: TestQueryInput) {
|
|
37
|
-
return this.
|
|
28
|
+
return this.testRedisSvc.findOne(test as any);
|
|
38
29
|
}
|
|
39
30
|
|
|
40
31
|
@Query((returns) => TestPageResult, { name: "testPage" })
|
|
41
32
|
public async page(@Args("page") page: TestPageInput) {
|
|
42
|
-
return this.
|
|
33
|
+
return this.testRedisSvc.page({ ...page } as any);
|
|
43
34
|
}
|
|
44
35
|
}
|
package/package.json
CHANGED
|
@@ -1,41 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zync-nest-data-module",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.38",
|
|
4
4
|
"description": "NestJS database module with database backup and file upload utilities",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"nestjs",
|
|
7
|
+
"database",
|
|
8
|
+
"backup",
|
|
9
|
+
"upload",
|
|
10
|
+
"utilities"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/zynctech/zync-nest-data-module.git"
|
|
15
|
+
},
|
|
16
|
+
"license": "ISC",
|
|
17
|
+
"author": "sabiridwan",
|
|
5
18
|
"main": "dist/index.js",
|
|
6
19
|
"types": "dist/index.d.ts",
|
|
7
20
|
"scripts": {
|
|
8
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
21
|
"build": "tsc -p libs/tsconfig.lib.json",
|
|
10
22
|
"build:lib": "rimraf dist && tsc -p libs/tsconfig.lib.json",
|
|
11
23
|
"build:watch": "tsc -p libs/tsconfig.lib.json --watch",
|
|
12
24
|
"clean": "rimraf dist",
|
|
13
25
|
"prepublishOnly": "npm run build",
|
|
26
|
+
"publish:update": "npm publish --registry https://registry.asynctechs.com/",
|
|
14
27
|
"start": "npm run build && node dist/main.js",
|
|
15
28
|
"start:dev": "npm run build:watch & nodemon dist/main.js",
|
|
29
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
16
30
|
"update-links": "node update-links.js",
|
|
17
|
-
"update-links:minor": "node update-links.js minor",
|
|
18
31
|
"update-links:major": "node update-links.js major",
|
|
32
|
+
"update-links:minor": "node update-links.js minor",
|
|
19
33
|
"update-links:no-build": "node update-links.js --skip-build",
|
|
20
34
|
"update-links:no-version": "node update-links.js --skip-version --skip-build"
|
|
21
35
|
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"nestjs",
|
|
24
|
-
"database",
|
|
25
|
-
"backup",
|
|
26
|
-
"upload",
|
|
27
|
-
"utilities"
|
|
28
|
-
],
|
|
29
|
-
"author": "sabiridwan",
|
|
30
|
-
"license": "ISC",
|
|
31
|
-
"repository": {
|
|
32
|
-
"type": "git",
|
|
33
|
-
"url": "https://github.com/zynctech/zync-nest-data-module.git"
|
|
34
|
-
},
|
|
35
|
-
"publishConfig": {
|
|
36
|
-
"access": "public"
|
|
37
|
-
},
|
|
38
|
-
"packageManager": "pnpm@10.14.0",
|
|
39
36
|
"dependencies": {
|
|
40
37
|
"@apollo/server": "^5.0.0",
|
|
41
38
|
"@as-integrations/express5": "^1.1.2",
|
|
@@ -47,7 +44,6 @@
|
|
|
47
44
|
"@nestjs/config": "^4.0.2",
|
|
48
45
|
"@nestjs/event-emitter": "^3.0.1",
|
|
49
46
|
"@nestjs/graphql": "^13.1.0",
|
|
50
|
-
"@nestjs/mongoose": "^11.0.3",
|
|
51
47
|
"@nestjs/swagger": "^11.2.0",
|
|
52
48
|
"aws-sdk": "^2.1692.0",
|
|
53
49
|
"axios": "^1.11.0",
|
|
@@ -60,30 +56,53 @@
|
|
|
60
56
|
"firebase-admin": "^13.5.0",
|
|
61
57
|
"googleapis": "^159.0.0",
|
|
62
58
|
"graphql": "^16.11.0",
|
|
59
|
+
"graphql-redis-subscriptions": "^2.7.0",
|
|
63
60
|
"graphql-upload-ts": "^2.1.3",
|
|
61
|
+
"ioredis": "^5.8.2",
|
|
64
62
|
"moment": "^2.30.1",
|
|
65
63
|
"mongodb": "^6.20.0",
|
|
66
|
-
"mongoose": "^8.19.2",
|
|
67
64
|
"mongoose-delete": "^1.0.2",
|
|
68
65
|
"puppeteer": "^24.19.0",
|
|
69
66
|
"qs": "^6.14.0",
|
|
70
67
|
"razorpay": "^2.9.6",
|
|
71
68
|
"rxjs": "^7.8.2",
|
|
72
|
-
"sharp": "^0.34.3",
|
|
73
69
|
"shortid": "^2.2.17",
|
|
74
70
|
"slugify": "^1.6.6",
|
|
75
71
|
"uuid": "^11.1.0",
|
|
76
72
|
"xlsx": "^0.18.5",
|
|
77
|
-
"zync-nest-library": "^1.0.
|
|
73
|
+
"zync-nest-library": "^1.0.30"
|
|
78
74
|
},
|
|
79
75
|
"devDependencies": {
|
|
80
76
|
"@nestjs/cli": "^11.0.10",
|
|
81
77
|
"@nestjs/core": "^11.1.6",
|
|
78
|
+
"@nestjs/mongoose": "^11.0.3",
|
|
82
79
|
"@nestjs/platform-express": "^11.1.6",
|
|
80
|
+
"@nestjs/schedule": "^6.0.1",
|
|
81
|
+
"@types/nanoid": "^3.0.0",
|
|
83
82
|
"@types/node": "^24.3.1",
|
|
83
|
+
"mongoose": "^8.19.2",
|
|
84
|
+
"nanoid": "^5.1.6",
|
|
85
|
+
"nest-winston": "^1.10.2",
|
|
84
86
|
"nodemon": "^3.0.2",
|
|
87
|
+
"randomatic": "^3.1.1",
|
|
88
|
+
"redis-om": "^0.4.7",
|
|
85
89
|
"rimraf": "^6.0.1",
|
|
86
90
|
"ts-morph": "^24.0.0",
|
|
87
91
|
"typescript": "^5.7.2"
|
|
88
|
-
}
|
|
89
|
-
|
|
92
|
+
},
|
|
93
|
+
"peerDependencies": {
|
|
94
|
+
"@nestjs/mongoose": "^11.0.3",
|
|
95
|
+
"@nestjs/schedule": "^6.0.1",
|
|
96
|
+
"@types/nanoid": "^3.0.0",
|
|
97
|
+
"mongoose": "^8.19.2",
|
|
98
|
+
"nanoid": "^5.1.6",
|
|
99
|
+
"nest-winston": "^1.10.2",
|
|
100
|
+
"randomatic": "^3.1.1",
|
|
101
|
+
"redis-om": "^0.4.7"
|
|
102
|
+
},
|
|
103
|
+
"packageManager": "pnpm@10.14.0",
|
|
104
|
+
"publishConfig": {
|
|
105
|
+
"access": "public"
|
|
106
|
+
},
|
|
107
|
+
"registry": "https://registry.asynctechs.com"
|
|
108
|
+
}
|