added graphql entegration and tested tanstack query

This commit is contained in:
2025-11-15 16:37:51 +03:00
parent a67170daa8
commit cf4f632afe
526 changed files with 55717 additions and 154 deletions

View File

@@ -19,6 +19,7 @@
"@nestjs/platform-express": "^11.0.1",
"graphql": "^16.12.0",
"graphql-fields": "^2.0.3",
"graphql-type-json": "^0.3.2",
"mongoose": "^8.19.3",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1"
@@ -6769,6 +6770,15 @@
"graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
}
},
"node_modules/graphql-type-json": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.3.2.tgz",
"integrity": "sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==",
"license": "MIT",
"peerDependencies": {
"graphql": ">=0.8.0"
}
},
"node_modules/graphql-ws": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.6.tgz",

View File

@@ -30,6 +30,7 @@
"@nestjs/platform-express": "^11.0.1",
"graphql": "^16.12.0",
"graphql-fields": "^2.0.3",
"graphql-type-json": "^0.3.2",
"mongoose": "^8.19.3",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1"

View File

View File

@@ -0,0 +1,17 @@
import { GraphQLJSONObject } from 'graphql-type-json';
import { Field, Int, InputType } from '@nestjs/graphql';
@InputType()
export class ListArguments {
@Field(() => GraphQLJSONObject, { nullable: true })
filters?: any;
@Field(() => GraphQLJSONObject, { nullable: true })
sort?: any;
@Field(() => Int, { defaultValue: 0 })
skip: number;
@Field(() => Int, { defaultValue: 10 })
limit: number;
}

View File

@@ -0,0 +1,14 @@
import { Field, ObjectType } from "@nestjs/graphql";
import { User } from "@/models/user.model";
import { Int } from "@nestjs/graphql";
@ObjectType()
export class UsersListResponse {
@Field(() => [User])
data: User[];
@Field(() => Int)
totalCount: number;
}

View File

@@ -0,0 +1,73 @@
mutation CreatePerson {
createPerson(
input: {
firstName: "John",
surname: "Doe",
middleName: "Michael",
sexCode: "M",
personRef: "REF12345",
personTag: "TAG001",
fatherName: "Robert",
motherName: "Jane",
countryCode: "US",
nationalIdentityId: "12345678901",
birthPlace: "New York",
birthDate: "1990-01-01T00:00:00.000Z",
taxNo: "987654321",
birthname: "Johnathan"
}
) {
_id
firstName
surname
birthDate
}
}
query {
Persons {
firstName
surname
middleName
sexCode
personRef
personTag
fatherName
motherName
countryCode
nationalIdentityId
birthPlace
birthDate
taxNo
birthname
}
}
query GetPerson {
Person(id: "AnID") {
_id
uuid
expiryStarts
expiryEnds
isConfirmed
deleted
active
crypUuId
createdCredentialsToken
updatedCredentialsToken
confirmedCredentialsToken
isNotificationSend
isEmailSend
refInt
refId
replicationId
createdAt
updatedAt
firstName
surname
middleName
sexCode
birthDate
}
}

View File

@@ -1,53 +0,0 @@
mutation CreatePerson {
createPerson(input: {
firstName: "John",
surname: "Doe",
middleName: "Michael",
sexCode: "M",
personRef: "REF12345",
personTag: "TAG001",
fatherName: "Robert",
motherName: "Jane",
countryCode: "US",
nationalIdentityId: "12345678901",
birthPlace: "New York",
birthDate: "1990-01-01T00:00:00.000Z",
taxNo: "987654321",
birthname: "Johnathan"
}) {
_id
firstName
surname
birthDate
}
}
query GetPerson {
Person(id: "69175eec7baea04628ad126c") {
_id
firstName
surname
middleName
sexCode
birthDate
}
}
query {
Persons {
firstName
surname
middleName
sexCode
personRef
personTag
fatherName
motherName
countryCode
nationalIdentityId
birthPlace
birthDate
taxNo
birthname
}
}

View File

@@ -1,30 +0,0 @@
mutation {
createUser(input: {
password: "secret123",
history: ["login1"],
tag: "admin",
email: "test@example.com",
phone: "555123456",
collectionTokens: {
default: "default-token",
tokens: [{ prefix: "main", token: "abc123" }]
},
person: "64f8b2a4e1234567890abcdef"
}) {
_id
password
tag
email
phone
tag
collectionTokens {
default
tokens {
prefix
token
}
}
person
}
}

View File

@@ -0,0 +1,120 @@
mutation {
createUser(input: {
password: "secret123",
history: ["login1"],
tag: "admin",
email: "test@example.com",
phone: "555123456",
collectionTokens: {
default: "default-token",
tokens: [{ prefix: "main", token: "abc123" }]
},
person: "64f8b2a4e1234567890abcdef"
}) {
_id
password
tag
email
phone
tag
collectionTokens {
default
tokens {
prefix
token
}
}
person
}
}
query {
users(limit:1, skip: 0) {
_id
uuid
expiryStarts
expiryEnds
isConfirmed
deleted
active
crypUuId
createdCredentialsToken
updatedCredentialsToken
confirmedCredentialsToken
isNotificationSend
isEmailSend
refInt
refId
replicationId
expiresAt
resetToken
password
history
tag
email
phone
collectionTokens {
default
tokens {
prefix
token
}
}
createdAt
updatedAt
}
}
query TestUsers(
$skip: Int
$limit: Int
$sort: JSON
$filters: JSON
) {
users(skip: $skip, limit: $limit, sort: $sort, filters: $filters) {
_id
email
phone
tag
createdAt
person {
firstName
lastName
}
}
}
{
"skip": 0,
"limit": 5,
"sort": {
"createdAt": 1
},
"filters": {}
}
{
"skip": 0,
"limit": 20,
"sort": { "email": -1 },
"filters": {
"email": {
"$regex": "@gmail.com",
"$options": "i"
}
}
}
{
"skip": 0,
"limit": 50,
"sort": { "tag": 1 },
"filters": {
"$or": [
{ "email": { "$regex": "example", "$options": "i" }},
{ "phone": { "$regex": "555", "$options": "i" }}
]
}
}

View File

@@ -2,25 +2,21 @@ import { Resolver, Query, Args, ID, Info, Mutation, Int } from '@nestjs/graphql'
import { Types } from 'mongoose';
import { User } from '@/models/user.model';
import { UsersService } from '@/users/users.service';
import type { GraphQLResolveInfo } from 'graphql';
import graphqlFields from 'graphql-fields';
import { CreateUserInput } from './dto/create-user.input';
import { ListArguments } from '@/dto/list.input';
import { UsersListResponse } from '@/people/dto/list-result.response';
import graphqlFields from 'graphql-fields';
import type { GraphQLResolveInfo } from 'graphql';
@Resolver(() => User)
export class UsersResolver {
constructor(private readonly usersService: UsersService) { }
// Add pagination skip and limit arguments
@Query(() => [User], { name: 'users' })
async getUsers(
@Info() info: GraphQLResolveInfo,
@Args('skip', { type: () => Int, defaultValue: 0 }) skip: number,
@Args('limit', { type: () => Int, defaultValue: 10 }) limit: number,
): Promise<User[]> {
const fields = graphqlFields(info);
const projection = this.usersService.buildProjection(fields);
return this.usersService.findAll(projection, skip, limit);
@Query(() => UsersListResponse, { name: "users" })
async getUsers(@Info() info: GraphQLResolveInfo, @Args('input') input: ListArguments): Promise<UsersListResponse> {
const fields = graphqlFields(info); const projection = this.usersService.buildProjection(fields?.data); const { skip, limit, sort, filters } = input;
return await this.usersService.findAll(projection, skip, limit, sort, filters);
}
@Query(() => User, { name: 'user', nullable: true })
@@ -29,8 +25,6 @@ export class UsersResolver {
}
@Mutation(() => User, { name: 'createUser' })
async createUser(@Args('input') input: CreateUserInput): Promise<User> {
return this.usersService.create(input);
}
async createUser(@Args('input') input: CreateUserInput): Promise<User> { return this.usersService.create(input) }
}

View File

@@ -3,18 +3,26 @@ import { InjectModel } from '@nestjs/mongoose';
import { Types, Model } from 'mongoose';
import { User, UserDocument } from '@/models/user.model';
import { CreateUserInput } from './dto/create-user.input';
import { UsersListResponse } from '@/people/dto/list-result.response';
@Injectable()
export class UsersService {
constructor(@InjectModel(User.name) private readonly userModel: Model<UserDocument>) { }
async findAll(projection?: any, skip: number = 0, limit: number = 10): Promise<UserDocument[]> { return this.userModel.find({}, projection, { lean: false }).skip(skip).limit(limit).exec() }
async findAll(projection: any, skip: number, limit: number, sort?: Record<string, 1 | -1>, filters?: Record<string, any>): Promise<UsersListResponse> {
const query: any = {}; if (filters && Object.keys(filters).length > 0) { Object.assign(query, filters) };
const totalCount = await this.userModel.countDocuments(query).exec();
const data = await this.userModel.find(query, projection, { lean: true }).skip(skip).limit(limit).sort(sort).exec()
return { data, totalCount };
}
async findById(id: Types.ObjectId, projection?: any): Promise<UserDocument | null> { return this.userModel.findById(id, projection, { lean: false }).populate({ path: 'person', select: projection?.person }).exec() }
async create(input: CreateUserInput): Promise<UserDocument> { const user = new this.userModel(input); return user.save() }
buildProjection(fields: Record<string, any>): any { const projection: any = {}; for (const key in fields) { projection[key] = 1 }; return projection }
buildProjection(fields: Record<string, any>): Record<string, 1> {
const projection: Record<string, 1> = {}; for (const key in fields) { projection[key] = 1 }; console.dir({ fields, projection }, { depth: null }); return projection
}
}