Infer object with Pothos without to call implement - node.js

I have a z object created like this:
import z from 'zod';
import { ObjectId } from 'mongodb';
interface IAppMenuItem {
folder: string;
unit: string;
items: IAppMenuItem[];
}
const zAppMenuItem: z.ZodType<IAppMenuItem> = z.lazy(() =>
z.object({
folder: z.string().trim().min(1).max(20),
unit: z.string().trim().min(1).max(20),
items: z.array(zAppMenuItem)
})
);
export const zApp = z.object({
orgId: z.instanceof(ObjectId),
name: z.string().trim().min(1).max(50),
caption: z.string().trim().min(1).max(50),
menu: z.array(zAppMenuItem).optional(),
});
....
import { z } from 'zod';
import { zApp } from '../validators';
import { ChangeLog } from './ChangeLog';
export type App = z.infer<typeof zApp> & { changeLog: ChangeLog };
then I have a builder file
const builder = new SchemaBuilder<{
Objects: {
AppObject: WithId<App>;
};
Scalars: {
Id: { Input: Id; Output: Id };
Date: { Input: Date; Output: Date };
DateTime: { Input: Date; Output: Date };
};
Context: Context;
}>({});
export const AppObject = builder.objectRef<WithId<App>>('App');
export const ChangeLogObject = builder.objectRef<ChangeLog>('ChangeLog');
ChangeLogObject.implement({
fields: t => ({
createdAt: t.expose('createdAt', { type: 'DateTime', nullable: true }),
createdById: t.expose('createdById', { type: 'Id', nullable: true }),
createdByName: t.expose('createdByName', { type: 'String', nullable: true }),
updatedAt: t.expose('updatedAt', { type: 'DateTime', nullable: true }),
updatedById: t.expose('updatedById', { type: 'Id', nullable: true }),
updatedByName: t.expose('updatedByName', { type: 'String', nullable: true })
})
});
AppObject.implement({
fields: t => ({
_id: t.expose('_id', { type: 'Id' }),
orgId: t.expose('orgId', { type: 'Id' }),
name: t.expose('name', { type: 'String' }),
caption: t.expose('caption', { type: 'String' }),
// menu should be implemented here...
changeLog: t.expose('changeLog', { type: ChangeLogObject })
})
});
export { builder };
Because the zApp object will have even more nested objects like menu and units, it's not practical to implement for each the corresponding model under pothos.
Is there any way to infer the App type, so that Pothos will understand the model?

Related

How to update a sub document in two levels in MongoDB (mongoose)

Purpose: Update a comment
"mongoose": "^6.7.0",
I've searched a few places for different ways to solve this problem, but to no avail.
My schema: (GalleryModule)
Here is the mongoose model creation
{
user: {
type: {
_id: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
},
required: true,
},
list: {
type: Array<{
_id: {
type: String;
required: true;
};
name: {
type: String;
required: true;
};
references: {
type: Array<{
type: {
type: string;
required: true;
};
body: {
type: string;
required: true;
};
}>;
};
comments: {
type: Array<{
_id: {
type: string;
required: true;
};
body: {
type: string;
required: true;
};
createdAt: {
type: Number;
required: true;
};
updatedAt: {
type: Number;
required: true;
};
}>;
};
createdAt: {
type: Number;
required: true;
};
updatedAt: {
type: Number;
required: true;
};
}>,
},
}
`The execution:
I look for a user with the ID, then I update some data
I only update the data that came in the body of the request
const User = await GetOneId(UserModule, req.body.UserId);
if (!User.body) {
return res.status(404).json({
message: "Usuário não existe no banco de dados",
});
}
var body = {};
if (req.body?.body) {
body["list.$[item].comments.$[score].body"] = req.body.body;
}
body["list.$[item].comments.$[score].user.name"] = User.body.name;
body["list.$[item].comments.$[score].user.image"] = User.body.image_small;
const response = await UpdateSubDoc<GalleryResponse>(
GalleryModule,
{
"list.$[item].comments.$[score].updatedAt": Date.now(),
},
[
{ "item._id": req.params.itemId },
{ "score._id": req.params.commentId },
],
{ _id: req.params.galleryId }
);
return res.status(response.status).json(response.body);
function: (UpdateSubDc)
Here is a reusable function in several pieces of code to update sub documents
export const UpdateSubDoc = async <S, TSchema = any, T = any>(
Schema: Model<S>,
Body: AnyKeys<TSchema> & AnyObject,
Filter: { [key: string]: any }[],
Id?: FilterQuery<T>
) => {
const response = await Schema.updateMany(
Id || {},
{ $set: Body },
{ arrayFilters: Filter }
);
return {
status: 200,
body: response,
};
};
Error:
Error: Could not find path "list.0.comments.0._id" in schema

Expression produces a union type that is too complex to represent.ts(2590) in nodejs project

I am new to nodejs and I cannot solve following problem: Error message : Expression produces a union type that is too complex to represent.ts(2590).I write the project in vs code in ubuntu but so far started giving such error. In project and VS code using the same ts version.
Error source code:
export const markAsNotified = async (instance, courier, order, searchDistance) => {
await NotifiedCourierModel.create({
order_number: order.number,
courier_id: courier.courier_id,
courier_token: courier.push_token,
distance: searchDistance,
sent_at: new Date(),
});
};
NotitfiedCourierModel:
import { getModelForClass, modelOptions, prop, index } from '#typegoose/typegoose';
#modelOptions({
schemaOptions: {
collection: 'notified_couriers',
}
})
#index({ sent_at: 1 }, { expireAfterSeconds: 30 * 60 }) // expire in 30 minutes
export class NotifiedCourier {
#prop({ required: true })
order_number!: number;
#prop({ required: true })
courier_id!: string;
#prop({ required: true })
courier_token!: string;
#prop({ required: true })
sent_at!: Date;
#prop({ required: true })
distance!: number;
public static async findByCourier(courierId: string, orderNumber: number, currentDistance: number) {
return NotifiedCourierModel.findOne({
courier_id: courierId,
order_number: orderNumber,
distance: { $lte: currentDistance }
}).exec();
}
public static async findNotAssignedCouriers(assignedCourierId: string, orderNumber: number) {
return NotifiedCourierModel.find({
courier_id: { $ne: assignedCourierId },
order_number: orderNumber
}).exec();
}
}
export const NotifiedCourierModel = getModelForClass(NotifiedCourier);

NestJS TypeORM ManytoMany how to save to a parameter in a related table?

I currently have a nestjs service /api/permission
To create a new permission I send the following parameters for REQUEST:
{"Id":"","EsName":"rxe2x","EnName":"rxi2x","Name":"rxclv2x","Type":"64","Role":"7,8,9"}
And RESPONSE is
{"status":201,"message":"Permission has been saved successfully.","permission":{"Id":"200","EsName":"rxe2x","EnName":"rxi2x","Name":"rxclv2x","Type":"64","Role":"7,8,9"}}
I want the Role parameter to also be saved, in the PermissionRole table, each role with an entry like this:
RoleId
PermissionId
7
200
8
200
9
200
on my permission.service.ts
async createPermission(permission: CreatePermissionDto) {
const exist = await this.permissionRepository.findOne({
where: { Name: permission.Name },
});
if (exist)
throw new ConflictException(
'The permission already exists.',
HttpStatus.CONFLICT.toString(),
);
const newPermission = await this.permissionRepository.save(permission);
return Object.assign(
{},
{
status: HttpStatus.CREATED,
message: 'Permission has been saved successfully.',
permission: newPermission,
},
);
}
summary of my Permission.entity.ts
import { Role } from './Role.entity';
#Entity('Permission', { schema: 'dbo' })
export class Permission extends BaseEntity {
#PrimaryGeneratedColumn({
type: 'int',
name: 'Id',
})
Id: number;
#Column('varchar', {
nullable: false,
name: 'Name',
})
Name: string;
#Column('int', {
nullable: false,
name: 'Type',
})
Type: number;
#Column('varchar', {
nullable: false,
name: 'EnName',
})
EnName: string;
#Column('varchar', {
nullable: false,
name: 'EsName',
})
EsName: string;
#ManyToMany(
() => Role,
(Role: Role) => Role.permissions,
)
roles: Role[];
}
summary of my Role.entity.ts
import { Permission } from './Permission.entity';
import { User } from './User.entity';
#Entity('Role', { schema: 'dbo' })
export class Role extends BaseEntity {
#PrimaryGeneratedColumn({
type: 'int',
name: 'Id',
})
Id: number;
#Column('varchar', {
nullable: false,
length: 50,
name: 'Name',
})
Name: string;
#Column('varchar', {
nullable: true,
length: 100,
name: 'AccessLevel',
})
AccessLevel: string;
#Column('bigint', {
nullable: true,
name: 'VALAccount',
})
VALAccount: string;
#Column('bit', {
name: 'CanModified',
default: '1',
})
CanModified: string;
#ManyToMany(
() => Permission,
(Permission: Permission) => Permission.roles,
{
nullable: false,
eager: true,
},
)
#JoinTable({
name: 'PermissionRole',
})
permissions: Permission[];
#ManyToMany(
() => User,
(User: User) => User.roles,
)
users: User[];
#ManyToMany(
() => User,
(User: User) => User.rolesCanAssign,
)
usersCanAssign: User[];
}
You have to define many to many like this in Permission.entity.ts
#ManyToMany(() => Role , (role) => role.id)
#JoinTable({
name: 'Permission_Role',
joinColumn: {
name: 'permissionId',
referencedColumnName: 'id'
},
inverseJoinColumn: {
name: 'roleId',
referencedColumnName: 'id'
}
})
roles: Role[];
And in permission.service.ts
async createPermission(permission: CreatePermissionDto) {
const exist = await this.permissionRepository.findOne({
where: { Name: permission.Name },
});
if (exist)
throw new ConflictException(
'The permission already exists.',
HttpStatus.CONFLICT.toString(),
);
const newPermissionDao = this.permissionRepository.create(permission);
newPermissionDao.roles = permission.roles.map((role) => {roleId: role, permissionId: newPermissionDao.id} );
const newPermission = await this.permissionRepository.save(newPermissionDao);
return Object.assign(
{},
{
status: HttpStatus.CREATED,
message: 'Permission has been saved successfully.',
permission: newPermission,
},
);
}
Basically you need to create an array of object for many to many relation like below:
permission.roles = [{
roleId: 1,
permissionId: 1
},
{
roleId: 2,
permissionId: 1
}];

Property 'save' does not exist on type 'Ipub[]' | mongoose - typescript

i'm trying to update a schema in my backend app (with node/express/typescript), but when i do .save() it breaks because the type is not like type it's type[]
And in my app is happening the following error
Property 'save' does not exist on type 'Ipub[]'
This is the schema
import { Schema, model } from "mongoose";
import { Ipub } from "../helpers/PublicationInterfaces";
const publication = new Schema<Ipub>({
body: { type: String },
photo: { type: String },
creator: {
name: { required: true, type: String },
perfil: { type: String },
identifier: { required: true, type: String }
},
likes: [
{
identifier: { type: String }
}
],
comments: [
{
body: { type: String },
name: { type: String },
perfil: { type: String },
identifier: { type: String },
createdAt: { type: Date, default: new Date() },
likesComments: [
{
identifier: { type: String }
}
]
}
],
createdAt: { required: true, type: Date, default: new Date() }
});
export default model("Publications", publication);
This is schema's interface
import { Document } from "mongoose";
// Publication's representation
export interface Ipub extends Document {
body: string;
photo: string;
creator: {
name: string;
perfil?: string;
identifier: string;
};
likes?: [
{
identifier: string;
}
];
comments?: [
{
body: string;
name: string;
perfil: string;
identifier: string;
createdAt: Date;
likesComments: [
{
identifier: string;
}
];
}
];
createdAt: Date;
}
And this is where the code breaks, look the line of code where i put await updateSub.save()
// Look for user's publications
const usersPub: Ipub[] = await Publication.find();
const updatePub = usersPub.filter(
(p: Ipub) => p.creator.identifier === specificUser.id
);
// update photo
try {
if (banner !== "") {
specificUser.banner = banner;
} else if (perfil !== "") {
specificUser.perfil = perfil;
updatePub.map((pub: Ipub) => (pub.creator.perfil = perfil));
await updatePub.save();
}
await specificUser.save();
return res.json(specificUser);
} catch (err) {
console.log(err);
return res.status(500).json({ Error: "The API Failed" });
}
It's really weird, it looks like it's because of the Ipub[] type definition, what can i do about it !
Thanks for your help !

TypeScript : MongoDB set method doesn't exist

I am working on an application in TypeScript and this is the first time I have gotten this error.
I am unable to use set method on an instance of a model.
Here is the model:
import mongoose from 'mongoose';
import { OrderStatus } from '#karantickets/common';
import { updateIfCurrentPlugin } from 'mongoose-update-if-current';
interface OrderAttrs {
id: string;
version: number;
userId: string;
price: number;
status: OrderStatus;
};
interface OrderDoc extends mongoose.Document {
version: number;
userId: string;
price: number;
status: OrderStatus;
};
interface OrderModel extends mongoose.Model<OrderDoc> {
build(attrs: OrderAttrs): OrderDoc;
};
const orderSchema = new mongoose.Schema({
userId: { type: String, required: true },
price: { type: Number, required: true },
status: { type: String, required: true }
}, {
toJSON: {
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
}
}
});
orderSchema.set('versionKey', 'version');
orderSchema.plugin(updateIfCurrentPlugin);
orderSchema.statics.build = (attrs: OrderAttrs) => {
return new Order({
_id: attrs.id,
version: attrs.version,
userId: attrs.userId,
price: attrs.price,
status: attrs.status
});
};
const Order = mongoose.model<OrderDoc, OrderModel>('Order', orderSchema);
export { Order };
And here is where I am using the <object.set()> method:
export class OrderCancelledListener extends Listener<OrderCancelledEvent> {
queueGroupName = queueGroupName;
subject: Subjects.OrderCancelled = Subjects.OrderCancelled;
async onMessage(data: OrderCancelledEvent['data'], msg: Message) {
const order = Order.findOne({
_id: data.id,
version: data.version - 1
});
if (!order) throw new Error('Order not found');
order.set({ // < -------------------------------- ERROR !!
status: OrderStatus.Cancelled
});
msg.ack();
}
}
Error: Property 'set' does not exist on type 'DocumentQuery<OrderDoc | null, OrderDoc, {}>'
Thanks in advance!

Resources