Skip to content
This repository has been archived by the owner on Jun 29, 2021. It is now read-only.

Commit

Permalink
Nested documents
Browse files Browse the repository at this point in the history
  • Loading branch information
ukoester committed Dec 7, 2017
1 parent bc04521 commit f4bccc0
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .editorconfig
Expand Up @@ -3,4 +3,5 @@ root = true
[*.ts]
end_of_line = lf
insert_final_newline = true
indent_size = 2
indent_size = 2
indent_style = space
20 changes: 20 additions & 0 deletions .vscode/launch.json
@@ -0,0 +1,20 @@
{
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Run Tests",
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
"args": [
"--colors",
"${workspaceRoot}/lib/test/*.test.js"
],
"sourceMaps": true,
"preLaunchTask": "build"
}
]
}
13 changes: 13 additions & 0 deletions .vscode/tasks.json
@@ -0,0 +1,13 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build",
"label": "build",
"problemMatcher": []
}
]
}
17 changes: 14 additions & 3 deletions src/prop.ts
Expand Up @@ -2,7 +2,7 @@ import * as mongoose from 'mongoose';
import * as _ from 'lodash';

import { schema, virtuals } from './data';
import { isPrimitive, initAsObject, initAsArray, isString, isNumber } from './utils';
import { isPrimitive, initAsObject, initAsArray, isString, isNumber, isObject } from './utils';
import { InvalidPropError, NotNumberTypeError, NotStringTypeError, NoMetadataError } from './errors';

export type Func = (...args: any[]) => any;
Expand Down Expand Up @@ -118,8 +118,8 @@ const baseProp = (rawOptions, Type, target, key, isArray = false) => {

const instance = new Type();
const subSchema = schema[instance.constructor.name];
if (!subSchema && !isPrimitive(Type)) {
throw new InvalidPropError(Type.name, key);
if (!subSchema && !isPrimitive(Type) && !isObject(Type)) {
throw new InvalidPropError(Type.name, key);
}

const options = _.omit(rawOptions, ['ref', 'items']);
Expand All @@ -140,6 +140,17 @@ const baseProp = (rawOptions, Type, target, key, isArray = false) => {
return;
}

// If the 'Type' is not a 'Primitive Type' and no subschema was found treat the type as 'Object'
// so that mongoose can store it as nested document
if (isObject(Type) && !subSchema) {
schema[name][key] = {
...schema[name][key],
...options,
type: Object,
};
return;
}

if (isArray) {
schema[name][key][0] = {
...schema[name][key][0],
Expand Down
24 changes: 23 additions & 1 deletion src/test/index.test.ts
Expand Up @@ -4,7 +4,8 @@ import * as mongoose from 'mongoose';

import { model as User, User as UserType } from './models/user';
import { model as Car, Car as CarType } from './models/car';
import { model as Person } from './models/person';
import { model as Person, PersistentModel } from './models/person';
import { PersonNested, AddressNested, PersonNestedModel } from './models/nested-object';
import { Genders } from './enums/genders';
import { Role } from './enums/role';
import { initDatabase } from './utils/mongoConnect';
Expand Down Expand Up @@ -207,4 +208,25 @@ describe('getClassForDocument()', () => {
expect(user.getClassName()).to.equals('Person');
expect(Person.getStaticName()).to.equals('Person');
});

it('Should store nested address', async () => {
const personInput = new PersonNested();
personInput.name = 'Person, Some';
personInput.address = new AddressNested('A Street 1');
personInput.moreAddresses = [
new AddressNested('A Street 2'),
new AddressNested('A Street 3'),
];

const person = await PersonNestedModel.create(personInput);

expect(person).is.not.undefined;
expect(person.name).equals('Person, Some');
expect(person.address).is.not.undefined;
expect(person.address.street).equals('A Street 1');
expect(person.moreAddresses).is.not.undefined;
expect(person.moreAddresses.length).equals(2);
expect(person.moreAddresses[0].street).equals('A Street 2');
expect(person.moreAddresses[1].street).equals('A Street 3');
});
});
21 changes: 21 additions & 0 deletions src/test/models/nested-object.ts
@@ -0,0 +1,21 @@
import * as mongoose from 'mongoose';
import * as tg from '../../typegoose';

export class AddressNested {
street: string;

constructor(street: string) {
this.street = street;
}
}

export class PersonNested extends tg.Typegoose {
@tg.prop()
name: string;
@tg.prop()
address: AddressNested;
@tg.prop()
moreAddresses: AddressNested[] = [];
}

export const PersonNestedModel = new PersonNested().getModelForClass(PersonNested);
14 changes: 14 additions & 0 deletions src/utils.ts
Expand Up @@ -5,6 +5,20 @@ import { schema, constructors } from './data';

export const isPrimitive = (Type) => _.includes(['String', 'Number', 'Boolean', 'Date'], Type.name);

export const isObject = (Type) => {
let prototype = Type.prototype;
let name = Type.name;
while (name) {
if (name === 'Object') {
return true;
}
prototype = Object.getPrototypeOf(prototype);
name = prototype ? prototype.constructor.name : null;
}

return false;
};

export const isNumber = (Type) => Type.name === 'Number';

export const isString = (Type) => Type.name === 'String';
Expand Down

0 comments on commit f4bccc0

Please sign in to comment.