Skip to content

Commit

Permalink
Finishes OneToMany Decorator for Moongose (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
gastonmorixe authored Apr 1, 2021
1 parent 8b36f11 commit 2a1e94d
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 67 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@
"mongoose": "^5.11.19",
"passport": "^0.4.1",
"passport-jwt": "^4.0.0",
"pluralize": "^8.0.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rrule": "^2.6.8",
"rxjs": "^6.6.6",
"titleize": "^2.1.0",
"type-fest": "^0.21.3"
},
"devDependencies": {
Expand Down
1 change: 0 additions & 1 deletion src/entities/calendar/calendar.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { CalendarEvent } from '../calendarEvent/calendarEvent.model'
timestamps: true,
// autoIndex: true
})
@Utils.ValidateSchema()
export class Calendar extends Utils.Model {
@GQL.Field(() => GQL.ID)
_id: mongoose.Types.ObjectId
Expand Down
1 change: 0 additions & 1 deletion src/entities/calendarEvent/calendarEvent.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { Calendar } from '../calendar/calendar.model'
timestamps: true,
// autoIndex: true
})
@Utils.ValidateSchema()
export class CalendarEvent extends Utils.Model {
@GQL.Field(() => GQL.ID)
_id: mongoose.Types.ObjectId
Expand Down
1 change: 0 additions & 1 deletion src/entities/event/event.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { CalendarEvent } from '../calendarEvent/calendarEvent.model'
@DB.Schema({
autoIndex: true,
})
@Utils.ValidateSchema()
export class Event extends Utils.Model {
@GQL.Field(() => GQL.ID)
_id: mongoose.Types.ObjectId
Expand Down
13 changes: 1 addition & 12 deletions src/entities/school/school.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { Subject } from '../subject/subject.model'
timestamps: true,
// autoIndex: true
})
@Utils.ValidateSchema()
export class School extends Utils.Model {
@GQL.Field(() => GQL.ID)
_id: mongoose.Types.ObjectId
Expand All @@ -21,20 +20,10 @@ export class School extends Utils.Model {
@DB.Prop()
name: string

//@DB.Prop({ type: [mongoose.Schema.Types.ObjectId], ref: 'Subject' })
@GQL.Field(() => [Subject])
@GQL.Field(() => [Subject], { nullable: true })
@Utils.OneToMany()
subjects: mongoose.Types.ObjectId[] | Subject[]
}

export type SchoolDocument = School & mongoose.Document
export const SchoolSchema = School.schema
// SchoolSchema.virtual('subjects', {
// ref: 'Subject',
// localField: '_id',
// foreignField: 'school'
// })

// SchoolSchema.set('toObject', { virtuals: true })
// SchoolSchema.set('toJSON', { virtuals: true })

2 changes: 1 addition & 1 deletion src/entities/school/school.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { Subject } from '../subject/subject.model'

@Resolver(() => School)
export class SchoolResolver {
constructor(private service: SchoolService) { }
constructor(private service: SchoolService) {}

@Query(() => School)
async school(@Args('_id', { type: () => ID }) _id: Types.ObjectId) {
Expand Down
1 change: 0 additions & 1 deletion src/entities/subject/subject.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { School } from '../school/school.model'
timestamps: true,
// autoIndex: true
})
@Utils.ValidateSchema()
export class Subject extends Utils.Model {
@GQL.Field(() => GQL.ID)
_id: mongoose.Types.ObjectId
Expand Down
2 changes: 0 additions & 2 deletions src/entities/user/user.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ import * as Utils from '../../utils/Model'
timestamps: true,
// autoIndex: true
})
@Utils.ValidateSchema()
export class User extends Utils.Model {
@GQL.Field(() => GQL.ID)
_id: mongoose.Types.ObjectId

@GQL.Field(() => String, { nullable: true })
@DB.Prop({ required: false, min: 3, max: 100 })
fullName: string
// @V.Contains('franco')

@GQL.Field(() => String, { nullable: false })
@DB.Prop({
Expand Down
2 changes: 1 addition & 1 deletion src/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ type Query {
type School {
_id: ID!
name: String!
subjects(populate: Boolean!): [Subject!]!
subjects(populate: Boolean!): [Subject!]
}

type Subject {
Expand Down
89 changes: 43 additions & 46 deletions src/utils/Model.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as DB from '@nestjs/mongoose' // { Prop, Schema, SchemaFactory }
import * as V from 'class-validator'
import * as Reflect from 'reflect-metadata'
import { ApolloError } from 'apollo-server-errors'
import { plainToClass } from 'class-transformer'
import pluralize from 'pluralize'
import titleize from 'titleize'

export class ModelValidationError extends ApolloError {
public path: any[]
Expand All @@ -17,8 +18,6 @@ export class ModelValidationError extends ApolloError {
) {
super(message, 'MODEL_VALIDATION_FAILED', extensions)
this.path = path
// this.name = 'ModelValidationError'
// Object.defineProperty(this, 'name', { value: 'ValidationError' })
}
}

Expand All @@ -32,55 +31,35 @@ export function ValidateSchema() {
}
}

function WithRelations() {
return function <T extends typeof Model>(target: T) {
target.__withRelations__ = true
return target
}
interface IOneToManyOptions {
ref?: string
foreignField?: string
localField?: string
}


/*export function HasMany(options: {
field: string,
ref: string,
//foreignField: string
}) {
const { field, ref } = options
return function <T extends typeof Model>(target: T) {
target.schema.virtual(field, {
export function OneToMany(options: IOneToManyOptions = {}) {
const { ref } = options
return (target: any, propertyKey: string) => {
const model = target.constructor as typeof Model
model.__assoc__ = model.__assoc__ || {}
model.__assoc__['OneToMany'] = model.__assoc__['OneToMany'] || []
model.__assoc__['OneToMany'].push({
target,
propertyKey,
ref,
localField: '_id',
foreignField: target.name.toLowerCase()
foreignField,
localField,
})
//console.log(target.name.toLowerCase())
target.schema.set('toObject', { virtuals: true })
target.schema.set('toJSON', { virtuals: true })
return target
}
}*/

type ObjectType<T> = { new(): T } | Function;
// string | ((type?: any) => ObjectType<T>)
export function OneToMany<T>(typeFunctionOrTarget?: string | ((type?: any) => ObjectType<T>)): PropertyDecorator {
return function (object: Object, propertyName: string) {
console.log(arguments)
console.log(object)
}
}

// function format(formatString: string) {
// return Reflect.metadata(formatMetadataKey, formatString);
// }


/**
* Base Model
*/
@WithRelations()
@ValidateSchema()
export class Model {
static __validate__: boolean | undefined
static __withRelations__: boolean | undefined
static __assoc__: Record<string, any> | undefined
static schema?: ReturnType<typeof DB.SchemaFactory.createForClass>
}

Expand All @@ -96,18 +75,36 @@ Object.defineProperty(Model, 'schema', {
// eslint-disable-next-line
const klass = this

if (this['__withRelations__']) {
schema.pre('findOneAndDelete', async function (next) {
console.log('findOneAndDelete:', this)
next(undefined)
})
const assocs = this?.__assoc__?.['OneToMany']
if (assocs) {
for (const assoc of assocs) {
// TODO Cleanup to a function
const {
target,
propertyKey,
foreignField: _foreignField,
ref: _ref,
localField: _localField,
} = assoc
const model = target.constructor as typeof Model
const foreignField = _foreignField ?? model.name.toLowerCase()
const localField = _localField ?? '_id'
const ref = _ref ?? titleize(pluralize.singular(`${propertyKey}`))
model?.schema.virtual(propertyKey, {
ref,
localField,
foreignField,
})
model?.schema.set('toObject', { virtuals: true })
model?.schema.set('toJSON', { virtuals: true })
}
}

if (this['__validate__']) {
// TODO Cleanup to a function
schema.pre('validate', async function (next) {
const modelData = this.toObject()
const model = plainToClass(klass, modelData)

try {
console.log('model', model)
await V.validateOrReject(model)
Expand Down
7 changes: 6 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7167,7 +7167,7 @@ pkg-dir@^5.0.0:
dependencies:
find-up "^5.0.0"

[email protected]:
[email protected], pluralize@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
Expand Down Expand Up @@ -8410,6 +8410,11 @@ through@^2.3.6:
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=

titleize@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/titleize/-/titleize-2.1.0.tgz#5530de07c22147a0488887172b5bd94f5b30a48f"
integrity sha512-m+apkYlfiQTKLW+sI4vqUkwMEzfgEUEYSqljx1voUE3Wz/z1ZsxyzSxvH2X8uKVrOp7QkByWt0rA6+gvhCKy6g==

tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
Expand Down

0 comments on commit 2a1e94d

Please sign in to comment.