zync-nest-data-module 1.1.38 → 1.1.39

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 (44) hide show
  1. package/dist/redis/redis.module.js +2 -3
  2. package/dist/redis/redis.module.js.map +1 -1
  3. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  4. package/package.json +4 -5
  5. package/dist/index.js.map +0 -1
  6. package/libs/src/app.controller.ts +0 -91
  7. package/libs/src/app.module.ts +0 -34
  8. package/libs/src/backup/backup.config.ts +0 -45
  9. package/libs/src/backup/backup.interface.ts +0 -21
  10. package/libs/src/backup/backup.module.ts +0 -11
  11. package/libs/src/backup/backup.service.ts +0 -274
  12. package/libs/src/backup/backup.worker.ts +0 -35
  13. package/libs/src/backup/index.ts +0 -4
  14. package/libs/src/base/dto.ts +0 -46
  15. package/libs/src/base/index.ts +0 -2
  16. package/libs/src/base/resolver.ts +0 -20
  17. package/libs/src/database/database.module.ts +0 -28
  18. package/libs/src/database/database.repository.ts +0 -355
  19. package/libs/src/database/database.scheme.ts +0 -128
  20. package/libs/src/database/database.service.ts +0 -75
  21. package/libs/src/database/database.sync.ts +0 -61
  22. package/libs/src/database/database.transaction.ts +0 -99
  23. package/libs/src/database/database.uniqueId.ts +0 -90
  24. package/libs/src/database/database.utils.ts +0 -99
  25. package/libs/src/database/index.ts +0 -8
  26. package/libs/src/index.ts +0 -5
  27. package/libs/src/main.ts +0 -52
  28. package/libs/src/redis/index.ts +0 -2
  29. package/libs/src/redis/redis.interface.ts +0 -34
  30. package/libs/src/redis/redis.module.ts +0 -30
  31. package/libs/src/redis/redis.service.ts +0 -137
  32. package/libs/src/service/index.ts +0 -1
  33. package/libs/src/service/service.ts +0 -181
  34. package/libs/src/test/test.controller.ts +0 -59
  35. package/libs/src/test/test.dto.ts +0 -41
  36. package/libs/src/test/test.module.ts +0 -24
  37. package/libs/src/test/test.redis.ts +0 -19
  38. package/libs/src/test/test.repository.ts +0 -44
  39. package/libs/src/test/test.resolver.ts +0 -35
  40. package/libs/src/test/test.schema.ts +0 -21
  41. package/libs/src/test/test.service.ts +0 -19
  42. package/libs/tsconfig.lib.json +0 -19
  43. package/tsconfig.json +0 -29
  44. package/update-links.js +0 -159
@@ -1,99 +0,0 @@
1
- import { Injectable, Scope, Logger } from "@nestjs/common";
2
- import { InjectConnection } from "@nestjs/mongoose";
3
- import mongodb, { ClientSession, Connection } from "mongoose";
4
- import { AsyncLocalStorage } from "async_hooks";
5
-
6
- export type TransactionSession = mongodb.ClientSession;
7
-
8
- @Injectable({ scope: Scope.DEFAULT })
9
- export class TransactionManager {
10
- private readonly logger = new Logger(TransactionManager.name);
11
- private static readonly storage = new AsyncLocalStorage<{ session: ClientSession; sessionName?: string }>();
12
-
13
- constructor(@InjectConnection() private readonly connection: Connection) { }
14
-
15
- public run<T>(callback: () => Promise<T>): Promise<T> {
16
- return TransactionManager.storage.run({ session: null }, callback);
17
- }
18
-
19
- public static getCurrentSession(): ClientSession | null {
20
- const store = TransactionManager.storage.getStore();
21
- return store?.session || null;
22
- }
23
-
24
- private async getSession(): Promise<ClientSession> {
25
- const store = TransactionManager.storage.getStore();
26
- if (!store) {
27
- throw new Error("[TransactionManager] Context not initialized. Use run() method.");
28
- }
29
-
30
- if (store.session) return store.session;
31
-
32
- store.session = await this.connection.startSession();
33
- store.session.startTransaction({
34
- readConcern: { level: "snapshot" },
35
- writeConcern: { w: "majority" },
36
- });
37
- return store.session as TransactionSession;
38
- }
39
-
40
- public async startTransaction(): Promise<TransactionSession> {
41
- return await this.getSession();
42
- }
43
-
44
- public async commitTransaction(): Promise<void> {
45
- const store = TransactionManager.storage.getStore();
46
- if (!store?.session) {
47
- throw new Error("[TransactionManager] No session available");
48
- }
49
-
50
- if (!store.session.transaction.isActive) {
51
- this.logger.warn("[TransactionManager] No active transaction to commit"); // Changed to warn
52
- return;
53
- }
54
-
55
- try {
56
- await store.session.commitTransaction();
57
- this.logger.log("[TransactionManager] Transaction committed successfully.");
58
- } catch (error) {
59
- await this.abortTransaction();
60
- throw error;
61
- } finally {
62
- this.logger.log("[TransactionManager] Ending transaction...");
63
- await this.endTransaction();
64
- }
65
- }
66
-
67
- public async abortTransaction(): Promise<void> {
68
- const store = TransactionManager.storage.getStore();
69
- if (store?.session && store.session.transaction.isActive) {
70
- try {
71
- await store.session.abortTransaction();
72
- } catch (error) {
73
- } finally {
74
- await this.endTransaction();
75
- }
76
- }
77
- }
78
-
79
- public async endTransaction(): Promise<void> {
80
- const store = TransactionManager.storage.getStore();
81
- if (store?.session) {
82
- try {
83
- await store.session.endSession();
84
- } catch (error) { }
85
- store.session = null;
86
- }
87
- }
88
-
89
- public get sessionName(): string {
90
- return TransactionManager.storage.getStore()?.sessionName;
91
- }
92
-
93
- public set sessionName(name: string) {
94
- const store = TransactionManager.storage.getStore();
95
- if (store) {
96
- store.sessionName = name;
97
- }
98
- }
99
- }
@@ -1,90 +0,0 @@
1
- import { Inject, Injectable, OnModuleInit } from "@nestjs/common";
2
- import { getModelToken, InjectModel, Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
3
- import { Document, Types } from "mongoose";
4
- import { SoftDeleteModel } from "mongoose-delete";
5
- import { CONNECTION_NAME } from "./database.module";
6
- import { ModuleRef } from "@nestjs/core";
7
-
8
- @Schema({ collection: "unique_ids" })
9
- export class UniqueId {
10
- _id: string;
11
- @Prop({ unique: true })
12
- key: string;
13
- @Prop()
14
- sequence_value: number;
15
- }
16
- export type UniqueIdDocument = UniqueId & Document;
17
-
18
- export const UniqueIdSchema = SchemaFactory.createForClass(UniqueId);
19
-
20
- export type UniqueKeyTypes = "users" | "uniqueId";
21
-
22
- @Injectable({})
23
- export class ApUniqueIdGenerator implements OnModuleInit {
24
- private model: SoftDeleteModel<UniqueId>;
25
-
26
- constructor(@Inject(CONNECTION_NAME) private readonly connName: string, private readonly moduleRef: ModuleRef) {}
27
- // constructor(
28
- // @InjectModel(UniqueId.name)
29
- // private model: SoftDeleteModel<UniqueIdDocument>
30
- // ) {}
31
- onModuleInit() {
32
- this.ensureModelInitialized();
33
- }
34
-
35
- private ensureModelInitialized(): void {
36
- if (!this.model) {
37
- // Lazy initialization as fallback
38
- this.model = this.connName
39
- ? this.moduleRef.get<SoftDeleteModel<UniqueId>>(getModelToken(UniqueId.name, this.connName), {
40
- strict: false
41
- })
42
- : this.moduleRef.get<SoftDeleteModel<UniqueId>>(getModelToken(UniqueId.name), {
43
- strict: false
44
- });
45
-
46
- if (!this.model) {
47
- throw new Error(
48
- `UniqueId model is not initialized. Please ensure MongooseModule.forFeature includes UniqueId schema with connection name: ${
49
- this.connName || "default"
50
- }`
51
- );
52
- }
53
- }
54
- }
55
-
56
- public async getNextUniqueId(key: string = "uniqueId"): Promise<number> {
57
- this.ensureModelInitialized();
58
-
59
- const result = await this.model.findOneAndUpdate(
60
- { key },
61
- { $inc: { sequence_value: 1 } },
62
- { returnDocument: "after", upsert: true }
63
- );
64
-
65
- if (!result) {
66
- throw new Error("Failed to generate unique ID");
67
- }
68
-
69
- return result.sequence_value;
70
- }
71
-
72
- public getObjectId(): string {
73
- return new Types.ObjectId().toString();
74
- }
75
-
76
- public async seed(): Promise<void> {
77
- this.ensureModelInitialized();
78
-
79
- const keys = [{ key: "uniqueId", sequence_value: 1001 }];
80
-
81
- for await (const key of keys) {
82
- const exist = await this.model.findOne({ key: key.key });
83
-
84
- if (exist) {
85
- continue;
86
- }
87
- await this.model.create(key);
88
- }
89
- }
90
- }
@@ -1,99 +0,0 @@
1
- import moment from "moment";
2
- import { ObjectId } from "mongodb";
3
- import * as mongoose from "mongoose";
4
- import { Connection, Schema } from "mongoose";
5
-
6
- const mapToObjectIds = <T>(query: Partial<T>): T => {
7
- try {
8
- const mapVal = (val: any): any => {
9
- if (Array.isArray(val)) {
10
- return val.map(mapVal); // Recursively map each array element
11
- } else if (val && typeof val === "object" && !ObjectId.isValid(val)) {
12
- return mapToObjectIds(val); // Recursively process nested objects
13
- } else if (
14
- val &&
15
- ObjectId.isValid(val?.toString()) &&
16
- new ObjectId(val?.toString())?.toString() === val
17
- ) {
18
- return new ObjectId(val?.toString()); // Convert valid ObjectId strings
19
- }
20
- return val; // Return as-is if no conversion needed
21
- };
22
-
23
- const mappedQuery: any = { ...query };
24
- Object.keys(mappedQuery).forEach((key) => {
25
- mappedQuery[key] = mapVal(mappedQuery[key]); // Apply transformation
26
- });
27
-
28
- return mappedQuery;
29
- } catch (error) {
30
- console.error("mapToObjectIds Error:", error);
31
- // return query; // Return original query in case of error
32
- }
33
- };
34
-
35
- export const DbUtils = {
36
- mapToObjectIds,
37
- getOrCreateDiscriminatorModel(
38
- connection: Connection = mongoose.connection,
39
- baseModelName: string,
40
- baseSchema: Schema,
41
- discriminatorName: string,
42
- discriminatorSchema: Schema
43
- ) {
44
- const getBaseModel = (conn: Connection | typeof mongoose) =>
45
- conn.models[baseModelName] || conn.model(baseModelName, baseSchema);
46
-
47
- const BaseModel = connection
48
- ? getBaseModel(connection)
49
- : getBaseModel(mongoose);
50
-
51
- if (
52
- !BaseModel.discriminators ||
53
- !BaseModel.discriminators[discriminatorName]
54
- ) {
55
- return BaseModel.discriminator(discriminatorName, discriminatorSchema);
56
- }
57
-
58
- return connection
59
- ? connection.models[discriminatorName] ||
60
- connection.model(discriminatorName)
61
- : mongoose.models[discriminatorName] || mongoose.model(discriminatorName);
62
- },
63
- };
64
-
65
- export const SchemeUtil = {
66
- toObjectId: (value: string) => {
67
- try {
68
- if (Array.isArray(value)) {
69
- return value.map((v) =>
70
- mongoose.Types.ObjectId.isValid(v)
71
- ? new mongoose.Types.ObjectId(v)
72
- : v
73
- );
74
- } else if (mongoose.Types.ObjectId.isValid(value)) {
75
- return new mongoose.Types.ObjectId(value);
76
- } else if (typeof value === "string") {
77
- return new mongoose.Types.ObjectId(value);
78
- }
79
- } catch (error) {
80
- return value;
81
- }
82
- },
83
- toCurrentDate: (value: number | string) => {
84
- if (!value) {
85
- return moment().valueOf();
86
- }
87
-
88
- if (typeof value === "number" && !Number.isNaN(value)) {
89
- return value;
90
- }
91
-
92
- const momentDate = moment(value);
93
- if (momentDate.isValid()) {
94
- return momentDate.valueOf();
95
- }
96
-
97
- return moment().valueOf();
98
- },
99
- };
@@ -1,8 +0,0 @@
1
- export * from './database.scheme';
2
- export * from './database.repository';
3
- export * from './database.transaction';
4
- export * from './database.module';
5
- export * from './database.uniqueId';
6
- export * from './database.service';
7
- export * from './database.utils';
8
- export * from './database.sync';
package/libs/src/index.ts DELETED
@@ -1,5 +0,0 @@
1
- export * from "./backup";
2
- export * from "./database";
3
- export * from "./service";
4
- export * from "./base";
5
- export * from "./redis";
package/libs/src/main.ts DELETED
@@ -1,52 +0,0 @@
1
- import { NestFactory } from "@nestjs/core";
2
- import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
3
- import { ZyncNestDataModule } from "./app.module";
4
-
5
- async function bootstrap() {
6
- const app = await NestFactory.create(ZyncNestDataModule);
7
-
8
- // Enable CORS
9
- app.enableCors({
10
- origin: true,
11
- credentials: true,
12
- });
13
-
14
- // Swagger configuration
15
- const config = new DocumentBuilder()
16
- .setTitle("Zync Nest Data Module API")
17
- .setDescription("API documentation for Zync Nest Data Module")
18
- .setVersion("1.0.23")
19
- .addTag("Data Module", "Data Module endpoints for Zync Nest Data Module")
20
- .build();
21
-
22
- const document = SwaggerModule.createDocument(app, config);
23
- SwaggerModule.setup("api", app, document, {
24
- customSiteTitle: "Zync Nest Data Module API",
25
- customfavIcon: "https://nestjs.com/img/logo-small.svg",
26
- customJs: [
27
- "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui-bundle.js",
28
- "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui-standalone-preset.js",
29
- ],
30
- customCssUrl: [
31
- "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui.min.css",
32
- ],
33
- });
34
-
35
- const port = process.env.app_port || 3000;
36
- await app.listen(port);
37
-
38
- console.log(
39
- `🚀 Zync Nest Data Module server is running on: http://localhost:${port}`
40
- );
41
- console.log(
42
- `📚 Swagger documentation available at: http://localhost:${port}/api`
43
- );
44
- console.log(
45
- `🔍 Health check available at: http://localhost:${port}/test/health`
46
- );
47
- }
48
-
49
- bootstrap().catch((error) => {
50
- console.error("Failed to start the application:", error);
51
- process.exit(1);
52
- });
@@ -1,2 +0,0 @@
1
- export * from "./redis.service";
2
- export * from "./redis.module";
@@ -1,34 +0,0 @@
1
- export interface IRedisSearchParams {
2
- query?: string;
3
- minScore?: number;
4
- maxScore?: number;
5
- keyPrefix?: string;
6
- sortBy: {
7
- field: string;
8
- order?: "asc" | "desc";
9
- };
10
- }
11
-
12
- export interface IRedisPageParams extends IRedisSearchParams {
13
- page: number; // 1-based page
14
- pageSize: number;
15
- }
16
-
17
- export interface IRedisSearchResult<T> {
18
- data: T[];
19
- totalRecords: number;
20
- page?: number;
21
- totalPages?: number;
22
- }
23
-
24
- export interface IRedisZSetItem {
25
- key: string;
26
- score: number;
27
- }
28
-
29
- export interface IRedisSchemaField {
30
- name: string;
31
- type: "TEXT" | "NUMERIC" | "TAG"; // supported Redisearch types
32
- sortable?: boolean; // if field can be used in SORTBY
33
- noIndex?: boolean; // optional, skip indexing
34
- }
@@ -1,30 +0,0 @@
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 { }
@@ -1,137 +0,0 @@
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 +0,0 @@
1
- export * from "./service";