typegoose / typegoose Goto Github PK
View Code? Open in Web Editor NEWTypegoose - Define Mongoose models using TypeScript classes.
Home Page: https://typegoose.github.io/typegoose/
License: MIT License
Typegoose - Define Mongoose models using TypeScript classes.
Home Page: https://typegoose.github.io/typegoose/
License: MIT License
Following the docs: https://hasezoey.github.io/typegoose/docs/functions/addModelToTypegoose/
I am trying to use the build schema to then inject the methods and statics.
"dependencies": {
"@hasezoey/typegoose": "^6.0.0-28",
Continuation of szokodiakos/typegoose#19
class SelfContaining {
@prop()
public nest?: SelfContaining;
}
getModelForClass(SelfContaining);
Typegoose tries to build the schemas that are a prop
PS: i have absolutely no clue on how to fix this
Edit 1: addition, i didnt just meant like the code example, it was just very basic, here an proper example:
class SelfContaining {
@prop()
public nest?: SelfContaining;
}
const selfContainedModel = getModelForClass(SelfContaining);
const doc = new selfContainedModel({ nest: new selfContainedModel({ nest: new selfContainedModel({}) }) });
@Pre<User>('save', function(next) {
if (this.isModified('password')) {
const salt = bcrypt.genSaltSync();
this.password = bcrypt.hashSync(this.password, salt);
}
next();
})
declare type PreFnWithDT<T> = (this: DocumentType<T>, next?: EmptyVoidFn) => void;
// hooks.d.ts
type next
as optional
Custom Schema Types
parity
szokodiakos/typegoose#27
szokodiakos/typegoose#381
szokodiakos/typegoose#238
Pre 6.0 we were using our model schema along with the library class-transformer in order to hide/expose certain properties when they were serialized for use in a response.
We were able to annotate our schema like so:
import { Expose, Exclude } from 'class-transformer'
@Exclude()
@index('parent', { sparse: true })
export class Organization extends Typegoose {
@Expose()
public readonly _id: Types.ObjectId
@Expose()
@prop({ required: true })
public name: string
@Expose()
@prop({ default: null })
public parent: Ref<Organization> | null
}
My hope with 6.0 was to get rid of having to use things like DeepPartial
in order to use the class model definition type as an argument type to enforce the right data to functions that acted on the model.
My main issue is with the @Expose
on the _id
field. Since that field is present when dealing with a document, but not at object creation time. Now when trying to pass in a plain object with properties that match all the other class properties to an argument that is typed to Organization
TS complains that my object does not have an _id.
Imagine a function like this:
class SomeService {
public createNewOrganization(data: Organization) {
//
}
}
And then trying to call it:
const data = {
name: 'TheOrg',
parent: null
}
someService.createNewOrganization(data)
Any idea on how to get around this? I know this may not be specifically a typegoose issue, but since this was a heavy use case in our past usage of Typegoose, I figured I would pose the question here.
Currently, the class name is used as the model name in mongoose. In plain mongoose, there is the option to set a different model name.
This probably doesn't matter for most users, but I'm currently writing migrations for MongoDB where I have a few similar, but different versions of the same model. When using the same name for all of them, a lot of weird errors came up and it took me quite some time to figure out what the problem was.
Add an additional parameter to the modelOptions
decorator, e.g. modelName
and use it if it's present instead of the class name in getModelForClass
.
We have a code path that adds "Mixed" fields. These can be a bit dangerous IMO because you might think you have a field that's guaranteed to be of a certain type, but literally anything can be jammed into it.
I can see how some applications might be okay with Mixed, but I think it should always be explicit (there was an issue on mongoose's issue queue where vkarpov was discussing this too).
Mongoose itself was talking about deprecating implicit mixed too. I think typegoose should step with the best foot forward on r6 and throw in the "Mixed" branch by default (unless some "implicitMixedOkay" option is set). Or just disallow implicit mixed altogether.
Yes - mentioned above.
Hello,
Model names are being suffixed with the collection name when schemaOptions.collection
is passed as model options.
We dynamically use these model names and therefore prefer to have control over them. If I name my model X, then it should be named X, nonetheless of whether I specify a collection name. I think it is better to not make any decisions for the user of how models should be named, but instead use the class name as model name while providing an option to override it.
function getName(cl) {
const options = Reflect.getMetadata(constants_1.DecoratorKeys.ModelOptions, cl) || {};
const baseName = cl.name;
const suffix = (options.options ? options.options.customName : undefined) ||
(options.schemaOptions ? options.schemaOptions.collection : undefined);
return suffix ? `${baseName}_${suffix}` : baseName;
}
Maybe use customName
as name instead of suffix.
I humbly request you to reconsider,
Chris
Extending on szokodiakos/typegoose#260
What this Fork currently has, and the original not:
Hi @hasezoey , thanks for maintaining this project
I just refactored a project to use Typegoose instead of just Mongoose. I'm using the 6.0 "next" version on NPM. But when I start my server, I get this error:
Error: "undefined.users"'s Type is invalid! Type is: "undefined"
The error is quite vague, and it's hard to know where it comes from, especially since I just made a lot of changes. All I know is that users
is one of my collections.
Is it introspecting my database to see if it matches the generated schema ? Did I mess up a prop()
?
Thanks
It's quite difficult to remember your npm package name, since typegoose
is not active, so why not use another package name?
Hi. I read through the code a bit, and correct me if I'm wrong, but it seems typegoose maintains a registry that maintains mongoosey information, and that registry is keyed by the name of the class as it's defined.
I think this creates a gotcha that most users won't realize that if they use the same class name in different files, things will very likely break.
So:
Yes - Assuming it's option one, I think I could submit a PR to README that explains this pretty fast.
And if it's option 2, I wouldn't mind taking a whack at it either ;).
thanks to the pr on typescript, typescript 3.7.0 will include optional chaining, which would make the if's and some checks more easy
-> this issue is opened as a reminder
Hi, thanks for maintaining this amazing project.
We ran into a problem during porting our Mongoose schemas to Typegoose definitions. We use multidimensional arrays in our schemas, but I haven't found any information about this use-case in the documentation. Is it supported by the lib?
E.g. I have a class definition like this:
class Foo {
@arrayProp({
items: [Number]
})
public bar: number[][];
}
const FooModel = getModelForClass(Foo);
When I run the code it gives me an error:
Error: "Foo.bar"'s Type is invalid! Type is: "function Number() { [native code] }"
As far as I know this is a valid Mongoose schema:
new mongoose.Schema({
bar: [[Number]]
})
Could you provide some information about this problem?
Thanks
(just for completion)
szokodiakos/typegoose#366
Continuation of hasezoey#22
Make Better Documentation of the difference between ModelType
and ReturnModelType
Current situation: sometimes ReturnModelType
cannot be used (needs repo script, because i cant find a case where it happens) and ModelType
seems to solve it, but has actually not a good documentation on what it does
Help is appreciated, because i dont really understand what ModelType
and ReturnModelType
do differently (i know i made ReturnModelType
, but only because i dont really understand ModelType
) ... they seem to do the same thing, but actually dont
Model configuration classes (a term i just made up) are easy to be used accidentally instead of the model itself.
I know r6 seemed to make efforts to avoid decorators on the classes themselves, but I think it would be useful to have them.
I know it's not a HUGE deal, but it's pretty easy to implement.
yes... for example:
@typegoosemodelconfig()
class CarConfig {
@prop()
passengers: number;
@prop()
name: string;
}
typegoosemodelconfig can decorate the constructor so it throws (the behavior can be disabled w/ options). Also, the prop processors can throw if some metadata that typegoosemodelconfig sets isn't set.
Actually... technically, prop's decorator can do it too and avoid the decorator, since you have access to target - but I'm not sure I'd prefer that approach.
I am attempting to migrate to 6.0. We are using NestJS as our framework, and more specifically, kpfromer/nestjs-typegoose for integrating Typegoose with NestJS.
In an effort to migrate nestjs-typegoose to 6.0, the first hangup I am running into is the removal of options
from getModelForClass
. Since the mongoose connection is setup ahead of time, and does not use the default connection, passing this connection into each model is challenging.
Giving this some additional thought, since the connection is added as part of a decorator, I'm having a hard time seeing how this could be done for even non-NestJS apps. Usually, an additional connection needs to be setup async ahead of time, which makes it hard to pass a connection to an imported file at module load time, without forcing the creation of a wrapper for each model that allows passing in a connection post module load time.
Any thoughts on how to get the existingConnection back into the model load time in a way more similar to how it was passed in via getModelForClass?
Hi everyone
I looked in the issues here and tried to derive it myself from the documentation but wasn't able to fully cope the functionality.
I have a model with a ref myReference!: Ref<MyReference>
annotated as @prop({ required: true, ref: Customer})
. MyReference
is just a class with name
for testing purposes.
How, two problems I faced:
myReference
. It worked without, the required
did not pose an issueMyReference
_id into the model, it stored fine and I can see the $oid
saved in the model. If I retrieve the model I get the $oid
. How can I populate myReference
while loading? I tried the Virtual-Populate documentation but wasn't able to figure it out.If anybody can maybe point me in the right direction it would be awesome.
Thanks a lot in advance
class Post {
@prop() _id!: string;
@prop({ required: true, unique: true }) title!: string;
@prop() date?: Date;
@prop({ default: [] }) tag!: string[];
@prop({ required: true }) content!: string;
async findByQ(q: string, offset: number = 0, limit: number | null = 10, sort?: ISortOptions<Post>) {
...
return {count, data};
}
}
const PostModel = getModelForClass(Post);
// PostModel.findByQ = new Post().findByQ; // TypeScript will complain findByQ is not a function, without this line.
Adding decorator @staticMethod
doesn't help.
no
Hi!
Why prop decorator don't accept get and set option? Thanks
e.g:
class TestDoc{
@instanceMethod
getSomething(){
this.id; // property does not exist
this._id; // property does not exist
}
}
Anyone who wants to write guides can write one and Pull-Request it
Guidelines:
github-page/_guides
github-page/_guides/advanced
github-page/_docs
and the folder most appropriate for itjekyll got added in e37001a, help is here wanted too to make it better, its currently just bare-bones
PS: when someone wants to do an icon for typegoose, it would be appreciated :)
export class User{
@prop()
username:string
}
export const UserModel = getModelForClass(User)
const user = new UserModel({username: 'user1'})
console.log(user)
// there is no `username` property in `user`.
no
This is an "Issue" for what is included in version 6.0.0
Move collections to use Map<T, S>
These Changes can be found in branch r6/master
Extending on szokodiakos#313
I'm new to using your package and think it's fantastic and makes my life a lot easier so thank you firstly.
I am currently stuck on an issue I can't seem to work around, I put data into a database absolutely fine but when i try to retrieve it, even with it being small amounts it returns RangeError: Maximum call stack size exceeded
. I am trying to use the .find({})
function on my model and it weirdly returns to the variable locally as a correct object but when the function itself tries to return it, it splays out that message on four different models I have. These are triple nested objects, I have attached a few of these objects. If anyone can work it out, I would be grateful. I have uploaded my three DTO files that link to one another. If anyone would like anymore information, please ask. Thanks.
Archive.zip
Typegoose allows sharing of types between back-end and front-end. But it requires Mongose on client side for no reason.
So Mongoose is embedded inside the client bundle. Hence packages as Buffer. Furthermore with eg Angular 8 the need of some polyfills as:
// to avoid "ReferenceError: global is not defined" */
(window as any)['global'] = window;
// global.Buffer = global.Buffer || require('buffer').Buffer;
// @ts-ignore
window.Buffer = window.Buffer || require('buffer').Buffer;
(window as any).process = {
env: { DEBUG: undefined }
};
Is there any plan that previous works/discussion threads on the subject would be taken in account soon?
See:
existingMongoose
in buildSchema
#96import { prop, Typegoose } from 'typegoose';
export class Dummy extends Typegoose {
_id?: string; // surrogate key
@prop({ unique: true, required: true }) id?: string; // business key
@prop() title?: string;
@prop() description?: string;
@prop() nature?: string;
@prop() statut?: string;
}
currently in
https://github.com/hasezoey/typegoose/blob/b1f1f1c2d312824e1bbc98cd11fa3824e6786cf4/src/typegoose.ts#L152-L162
its has a as string
because @types/mongoose dosnt support RegExp without the Parallel option as described in DefinitelyTyped/DefinitelyTyped#37333
someprop
in the following example saves as an string, which shouldnt happen
function somefunc(arg: string) {
// unkown
return 'some string';
}
class something {
@prop({ ref: 'Business', default: () => somefunc('business') })
public someprop: Ref<Business>;
}
class Business {} // was not provided
no, it is really confusing because when chaning Ref<T>
to mongoose.Schema.Types.ObjectId
, it works again
public something: type
should have no effect in ref
refType
(to force the type) has absolutely no effectproposed things:
discovered by @RyannGalea on discord
@modelOptions({ schemaOptions: { timestamps: true } })
(6.0.0-14)(striked means canceled)
https://github.com/fabioformosa/typegoose-validation-error/tree/typegoosev6
Decorator Execution order
this conflicts because of:
name
of schema, which is applied in @modeloptions (class decorator)Hello,
References in array schemas translate to Mixed instead of ObjectID.
Consider the following code:
export class ChatChannelGroup {
@prop({ enum: ChatChannelGroupType, required: true })
public type!: ChatChannelGroupType;
@prop({ ref: TEvent, required: true })
public id!: Ref<TEvent>;
}
export class ChatChannel {
@arrayProp({ _id: false, items: ChatChannelGroup, required: true })
public access_groups!: ChatChannelGroup[];
}
When inspecting ChatChannel.schema.paths.access_groups.schema.paths.id
I get a type of instance Mixed:
"id": {
"path": "id",
"instance": "Mixed",
"validators": [
{
"message": "Path `{PATH}` is required.",
"type": "required"
}
],
"getters": [],
"setters": [],
"options": {
"required": true
},
"_index": null,
"isRequired": true,
"originalRequiredValue": true,
"$isUnderneathDocArray": true
}
},
When passing the class instead of the class name on line https://github.com/typegoose/typegoose/blob/master/src/prop.ts#L116 it correctly translates into ObjectID:
"_id": {
"path": "_id",
"instance": "ObjectID",
"validators": [],
"getters": [],
"setters": [
null
],
"options": {
"auto": true
},
"_index": null,
"$isUnderneathDocArray": true
}
Best regards
To support the discriminator feature altogether, we need to think about structures like this:
export class Building {
@prop({default: 100})
public width: number;
@prop({enum: BuildingTypes})
public type: BuildingTypes;
}
export class Garage extends Building {
@prop({default: 10})
public slotsForCars: number;
}
export class SummerHouse extends Building {
@prop({default: 100})
public distanceToLake: number;
}
export class Area {
@arrayProp({items: Building})
public buidlings: Building[];
}
const area = AreaModel.create({})
area.buildings.push({__t: "SummerHouse", distanceToLake: 100})
area.buildings.push({__t: "Garage", slotsForCars: 20})
area.save()
The current behaviour is that all properties that are not in the Building model will be deleted
enum BuildingTypes {
Garage = "Garage",
SummerHouse = "SummerHouse"
@modelOptions({
schemaOptions: {
discriminatorKey: 'type',
}
})
export class Building {
@prop({default: 100})
public width: number;
@prop({enum: BuildingTypes})
public type: BuildingTypes;
}
@modelOptions({
discriminatorId: BuildingTypes.Garage
})
export class Garage extends Building {
@prop({default: 10})
public slotsForCars: number;
}
@modelOptions({
discriminatorId: BuildingTypes.SummerHouse
})
export class SummerHouse extends Building {
@prop({default: 100})
public distanceToLake: number;
}
export class Area {
@arrayProp({items: Building, discriminatorClasses: [SummerHouse, Garage]})
public buidlings: Building[];
}
const area = AreaModel.create({})
area.buildings.push({__t: "SummerHouse", distanceToLake: 100})
area.buildings.push({__t: "Garage", slotsForCars: 20})
area.save()
Implemented this solution in B-Stefan#1
What do you think about this feature and the potential solution?
I would suggest using jest instead of mocha.
For several reasons:
What do you think about this suggestion?
Hi,
i've got this error (intermediate value).setModelForClass is not a function , i read the note section and i found this Typegoose cannot be used with classes of the same name, it will always return the first build class with that name, so i want to implement in my class User and extend it with Typegoose and BaseEntity using the function of TS applyMixins, this will broken my code ? because my class and the interface have the same name ? Anyways i just trying to use typegoose to avoid using schemas and trying to use Base Entity to use repository for DB stuff.
the following code snippet's error seems to be never fired, if someone can get it to fire, please provide an repro script, thanks
For everyone who has a clone / fork, please know that the master branch will get replaced by r6/master (will be merged, but please know, until the actual tag of the version, it might be not working commits)
and that the package will change again to @typegoose/typegoose
I had a class which looked like this:
interface Car {
model: string;
}
function insertCar(car: Car) {
// use mongodb js driver to insert
}
insertCar({model: "Tesla"});
Now when I convert that to Typegoose, I am unable to use Car
as the type of my function parameter:
class Car extends Typegoose {
@prop()
model!: string;
}
function insertCar(car: Car) {
// use typegoose to insert
}
insertCar({model: "Tesla"});
// Error: Type '{model: string}' is missing the
// following properties from type 'Car':
// getModelForClass, setModelForClass, buildSchema
How to fix this error?
Here's my model.
import {
Ref,
arrayProp,
getModelForClass,
modelOptions,
prop
} from '@hasezoey/typegoose'
import { User } from './user'
export class Person {
@prop({ default: new Date(), required: true })
joined!: Date
@prop({ required: true })
approved!: Date
@prop({ ref: User })
user!: Ref<User>
get isOwner() {
return false
// console.log('parent', this.parent)
// return this.parent().user._id.equals(this.user)
}
}
const PersonModel = getModelForClass(Person)
@modelOptions({
schemaOptions: {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
}
})
export class Plan {
@prop({ required: true })
description!: string
@prop({ required: true })
location!: number[]
@arrayProp({ items: Person })
people!: Person[]
@prop({ ref: User, required: true })
user!: Ref<User>
static async add(
description: string,
location: {
latitude: number
longitude: number
},
user: User
) {
const { latitude, longitude } = location
const owner = new PersonModel({
user,
approved: new Date()
})
const plan = await PlanModel.create({
description,
user,
location: [longitude, latitude],
people: [owner]
})
return plan
}
json() {
const { _id, created, description, location, people, updated } = this
const [longitude, latitude] = location
return {
created,
description,
updated,
id: _id.toString(),
location: {
latitude,
longitude
},
people: people.map(({ approved, joined, isOwner, user }) => ({
approved,
isOwner,
joined,
user: {
id: user._id.toString(),
name: user.name
}
}))
}
}
}
const PlanModel = getModelForClass(Plan)
export default PlanModel
Questions
this.parent()
inside a sub-document so I can populate the isOwner
field?isOwner
virtual field?toJSON
method from mongoose
so I don't have to create my custom json
method?_id
, created
, and updated
don't exist on type Plan
, even though _id
should exist and I've added created
and updated
timestamps through schemaOptions
. How can I resolve this? The response, as expected, works fine.await plan.populate('people.user').execPopulate()
before plan.json()
but json
doesn't know that the people.user
field has been populated. Is this a bug or am I doing this wrong? VS Code complains that Property 'name' does not exist on type 'Ref<User, ObjectId>'
even though according to the documentation, it's T
if populated, and ObjectID
if not._id.equals
, VS Code complains Property 'equals' does not exist on type 'Ref<User, ObjectId>'
. Is this a bug? You can't compare strings against ObjectIds without equals
.import { getModelForClass, prop } from "@hasezoey/typegoose";
import * as mongoose from "mongoose"; // [email protected]
class User {
@prop()
public username?: string;
@prop()
get name(){
return this.username
}
}
const UserModel = getModelForClass(User);
(async () => {
await mongoose.connect(`mongodb://localhost:27017/test`, { useNewUrlParser: true });
const user = new UserModel({ username: "user1" });
await user.save()
console.log(user);
})();
Output:
/Users/johnny/projects/test/typegoose-test/node_modules/mongoose/lib/schema.js:1712
throw new Error('Virtual path "' + name + '"' +
^
Error: Virtual path "name" conflicts with a real path in the schema
at Schema.virtual (/Users/johnny/projects/test/typegoose-test/node_modules/mongoose/lib/schema.js:1712:11)
at Schema.<anonymous> (/Users/johnny/projects/test/typegoose-test/node_modules/mongoose/lib/schema.js:1869:12)
at Array.forEach (<anonymous>)
at Schema.loadClass (/Users/johnny/projects/test/typegoose-test/node_modules/mongoose/lib/schema.js:1858:47)
at Object._buildSchema (/Users/johnny/projects/test/typegoose-test/node_modules/@hasezoey/typegoose/src/internal/schema.ts:49:7)
at buildSchema (/Users/johnny/projects/test/typegoose-test/node_modules/@hasezoey/typegoose/src/typegoose.ts:141:9)
at Object.getModelForClass (/Users/johnny/projects/test/typegoose-test/node_modules/@hasezoey/typegoose/src/typegoose.ts:96:42)
at Object.<anonymous> (/Users/johnny/projects/test/typegoose-test/src/main.ts:12:19)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Module.m._compile (/usr/local/lib/node_modules/ts-node/src/index.ts:473:23)
at Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Object.require.extensions.<computed> [as .ts] (/usr/local/lib/node_modules/ts-node/src/index.ts:476:12)
at Module.load (internal/modules/cjs/loader.js:643:32)
at Function.Module._load (internal/modules/cjs/loader.js:556:12)
at Function.Module.runMain (internal/modules/cjs/loader.js:839:10)
at Object.<anonymous> (/usr/local/lib/node_modules/ts-node/src/bin.ts:158:12)
no
Is there any way to keep the old codes, just add something like package alias to do this?
I tried to use "typegoose":"@hasezoey/typegoose@next"
in package.json
, but it does not work.
Extending on szokodiakos#186
@modelOptions()
(6.0.0-11)As typegoose
is in the middle of a repo migration. I would suggest opening official orgs
on GitHub and NPM to host the official versions of typegoose
. Fortunately, the typegoose
org names are available on npm
and GitHub
as the time of this issue creation.
This would allow users to install typegoose
via the npm
scope @typegoose
:
npm install @typegoose/typegoose
Thanks @hasezoey for taking over this project. Our team was planning to start adopting this project in the near future.
I'm adapting my Nest.js application to the latest typegoose . One issue I stumbled upon was that my static methods didn't transpile anymore.
I had to use "typeof" (like in the test classes of typegoose) to address TS2344 and an explicit return type to address TS2742.
I receive the following warning:
DeprecationWarning: This Package got moved, please use
@hasezoey/typegoose
| github:hasezoey/typegoose
I removed typegoose
and add it again but the warning is still there. What to do?
Title
its currently planned for version 6.1.0 to remove all the deprecated things (at least these that serve absolutely no purpose anymore (like instanceMethod
& staticMethod
), others might be in longer for backwards-compatibility
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.