From 606d40b9ee0fb0f5f021490d9e361b5cec660b28 Mon Sep 17 00:00:00 2001 From: Nora Date: Tue, 5 Nov 2019 12:54:54 -0500 Subject: [PATCH 1/2] test(repository): verify relation type in `resolve{Relation}Metadata` --- ...resolve-belongs-to-metadata.integration.ts | 29 +++ .../resolve-has-many-metadata.integration.ts | 165 ++++++++++-------- .../resolve-has-one-metadata.integration.ts | 151 +++++++++------- 3 files changed, 209 insertions(+), 136 deletions(-) create mode 100644 packages/repository/src/__tests__/integration/repositories/resolve-belongs-to-metadata.integration.ts diff --git a/packages/repository/src/__tests__/integration/repositories/resolve-belongs-to-metadata.integration.ts b/packages/repository/src/__tests__/integration/repositories/resolve-belongs-to-metadata.integration.ts new file mode 100644 index 000000000000..8687c0dc6806 --- /dev/null +++ b/packages/repository/src/__tests__/integration/repositories/resolve-belongs-to-metadata.integration.ts @@ -0,0 +1,29 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/repository +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {expect} from '@loopback/testlab'; +import {BelongsToDefinition, Entity, RelationType} from '../../..'; +import {resolveBelongsToMetadata} from '../../../relations/belongs-to/belongs-to.helpers'; + +describe('resolveBelongsToMetadata', () => { + it('throws if the wrong metadata type is used', async () => { + const metadata: unknown = { + name: 'category', + type: RelationType.hasOne, + targetsMany: false, + source: Category, + target: () => Category, + }; + + expect(() => { + resolveBelongsToMetadata(metadata as BelongsToDefinition); + }).to.throw( + /Invalid hasOne definition for Category#category: relation type must be BelongsTo/, + ); + }); + + /****** HELPERS *******/ + class Category extends Entity {} +}); diff --git a/packages/repository/src/__tests__/integration/repositories/resolve-has-many-metadata.integration.ts b/packages/repository/src/__tests__/integration/repositories/resolve-has-many-metadata.integration.ts index bcf494ca11ac..595521e1386a 100644 --- a/packages/repository/src/__tests__/integration/repositories/resolve-has-many-metadata.integration.ts +++ b/packages/repository/src/__tests__/integration/repositories/resolve-has-many-metadata.integration.ts @@ -12,92 +12,109 @@ import { } from '../../..'; import {resolveHasManyMetadata} from '../../../relations/has-many/has-many.helpers'; -describe('keyTo and keyFrom with resolveHasManyMetadata', () => { - it('resolves metadata using keyTo and keyFrom', () => { - const meta = resolveHasManyMetadata(Category.definition.relations[ - 'products' - ] as HasManyDefinition); - - expect(meta).to.eql({ - name: 'products', - type: 'hasMany', +describe('resolveHasManyMetadata', () => { + it('throws if the wrong metadata type is used', async () => { + const metadata: unknown = { + name: 'category', + type: RelationType.hasOne, targetsMany: true, source: Category, - keyFrom: 'id', - target: () => Product, - keyTo: 'categoryId', - }); + target: () => Category, + }; + + expect(() => { + resolveHasManyMetadata(metadata as HasManyDefinition); + }).to.throw( + /Invalid hasOne definition for Category#category: relation type must be HasMany/, + ); }); - it('infers keyFrom if it is not provided', () => { - const meta = resolveHasManyMetadata(Category.definition.relations[ - 'items' - ] as HasManyDefinition); + describe('keyTo and keyFrom with resolveHasManyMetadata', () => { + it('resolves metadata using keyTo and keyFrom', () => { + const meta = resolveHasManyMetadata(Category.definition.relations[ + 'products' + ] as HasManyDefinition); - expect(meta).to.eql({ - name: 'items', - type: 'hasMany', - targetsMany: true, - source: Category, - keyFrom: 'id', - target: () => Item, - keyTo: 'categoryId', + expect(meta).to.eql({ + name: 'products', + type: 'hasMany', + targetsMany: true, + source: Category, + keyFrom: 'id', + target: () => Product, + keyTo: 'categoryId', + }); }); - }); - it('infers keyTo if it is not provided', () => { - const meta = resolveHasManyMetadata(Category.definition.relations[ - 'things' - ] as HasManyDefinition); + it('infers keyFrom if it is not provided', () => { + const meta = resolveHasManyMetadata(Category.definition.relations[ + 'items' + ] as HasManyDefinition); - expect(meta).to.eql({ - name: 'things', - type: 'hasMany', - targetsMany: true, - source: Category, - keyFrom: 'id', - target: () => Thing, - keyTo: 'categoryId', + expect(meta).to.eql({ + name: 'items', + type: 'hasMany', + targetsMany: true, + source: Category, + keyFrom: 'id', + target: () => Item, + keyTo: 'categoryId', + }); }); - }); - it('throws if keyFrom, keyTo, and default foreign key name are not provided', async () => { - let error; - - try { - resolveHasManyMetadata(Category.definition.relations[ - 'categories' + it('infers keyTo if it is not provided', () => { + const meta = resolveHasManyMetadata(Category.definition.relations[ + 'things' ] as HasManyDefinition); - } catch (err) { - error = err; - } - expect(error.message).to.eql( - 'Invalid hasMany definition for Category#categories: target model ' + - 'Category is missing definition of foreign key categoryId', - ); + expect(meta).to.eql({ + name: 'things', + type: 'hasMany', + targetsMany: true, + source: Category, + keyFrom: 'id', + target: () => Thing, + keyTo: 'categoryId', + }); + }); - expect(error.code).to.eql('INVALID_RELATION_DEFINITION'); - }); + it('throws if keyFrom, keyTo, and default foreign key name are not provided', async () => { + let error; - it('resolves metadata if keyTo and keyFrom are not provided, but default foreign key is', async () => { - Category.definition.addProperty('categoryId', {type: 'number'}); + try { + resolveHasManyMetadata(Category.definition.relations[ + 'categories' + ] as HasManyDefinition); + } catch (err) { + error = err; + } - const meta = resolveHasManyMetadata(Category.definition.relations[ - 'categories' - ] as HasManyDefinition); + expect(error.message).to.eql( + 'Invalid hasMany definition for Category#categories: target model ' + + 'Category is missing definition of foreign key categoryId', + ); - expect(meta).to.eql({ - name: 'categories', - type: 'hasMany', - targetsMany: true, - source: Category, - keyFrom: 'id', - target: () => Category, - keyTo: 'categoryId', + expect(error.code).to.eql('INVALID_RELATION_DEFINITION'); }); - }); + it('resolves metadata if keyTo and keyFrom are not provided, but default foreign key is', async () => { + Category.definition.addProperty('categoryId', {type: 'number'}); + + const meta = resolveHasManyMetadata(Category.definition.relations[ + 'categories' + ] as HasManyDefinition); + + expect(meta).to.eql({ + name: 'categories', + type: 'hasMany', + targetsMany: true, + source: Category, + keyFrom: 'id', + target: () => Category, + keyTo: 'categoryId', + }); + }); + }); /****** HELPERS *******/ class Category extends Entity {} @@ -147,7 +164,17 @@ describe('keyTo and keyFrom with resolveHasManyMetadata', () => { target: () => Category, // no keyTo - }); + }) + // need to avoid Type 'RelationType.hasOne' is not comparable + // to type 'RelationType.hasMany' + .addRelation(({ + name: 'category', + type: RelationType.hasOne, + targetsMany: true, + source: Category, + // no keyFrom + target: () => Category, + })); class Product extends Entity {} diff --git a/packages/repository/src/__tests__/integration/repositories/resolve-has-one-metadata.integration.ts b/packages/repository/src/__tests__/integration/repositories/resolve-has-one-metadata.integration.ts index 3db13b0d66b4..bfb776565845 100644 --- a/packages/repository/src/__tests__/integration/repositories/resolve-has-one-metadata.integration.ts +++ b/packages/repository/src/__tests__/integration/repositories/resolve-has-one-metadata.integration.ts @@ -12,92 +12,109 @@ import { } from '../../..'; import {resolveHasOneMetadata} from '../../../relations/has-one/has-one.helpers'; -describe('keyTo and keyFrom with resolveHasOneMetadata', () => { - it('resolves metadata using keyTo and keyFrom', () => { - const meta = resolveHasOneMetadata(Category.definition.relations[ - 'product' - ] as HasOneDefinition); - - expect(meta).to.eql({ +describe('resolveHasOneMetadata', () => { + it('throws if the wrong metadata type is used', async () => { + const metadata: unknown = { name: 'product', - type: 'hasOne', - targetsMany: false, + type: RelationType.hasMany, + targetsMany: true, source: Category, - keyFrom: 'id', target: () => Product, - keyTo: 'categoryId', - }); + }; + + expect(() => { + resolveHasOneMetadata(metadata as HasOneDefinition); + }).to.throw( + /Invalid hasMany definition for Category#product: relation type must be HasOne/, + ); }); - it('infers keyFrom if it is not provided', () => { - const meta = resolveHasOneMetadata(Category.definition.relations[ - 'item' - ] as HasOneDefinition); + describe('keyTo and keyFrom with resolveHasOneMetadata', () => { + it('resolves metadata using keyTo and keyFrom', () => { + const meta = resolveHasOneMetadata(Category.definition.relations[ + 'product' + ] as HasOneDefinition); - expect(meta).to.eql({ - name: 'item', - type: 'hasOne', - targetsMany: false, - source: Category, - keyFrom: 'id', - target: () => Item, - keyTo: 'categoryId', + expect(meta).to.eql({ + name: 'product', + type: 'hasOne', + targetsMany: false, + source: Category, + keyFrom: 'id', + target: () => Product, + keyTo: 'categoryId', + }); }); - }); - it('infers keyTo if it is not provided', () => { - const meta = resolveHasOneMetadata(Category.definition.relations[ - 'thing' - ] as HasOneDefinition); + it('infers keyFrom if it is not provided', () => { + const meta = resolveHasOneMetadata(Category.definition.relations[ + 'item' + ] as HasOneDefinition); - expect(meta).to.eql({ - name: 'thing', - type: 'hasOne', - targetsMany: false, - source: Category, - keyFrom: 'id', - target: () => Thing, - keyTo: 'categoryId', + expect(meta).to.eql({ + name: 'item', + type: 'hasOne', + targetsMany: false, + source: Category, + keyFrom: 'id', + target: () => Item, + keyTo: 'categoryId', + }); }); - }); - - it('throws if keyFrom, keyTo, and default foreign key name are not provided', async () => { - let error; - try { - resolveHasOneMetadata(Category.definition.relations[ - 'category' + it('infers keyTo if it is not provided', () => { + const meta = resolveHasOneMetadata(Category.definition.relations[ + 'thing' ] as HasOneDefinition); - } catch (err) { - error = err; - } - expect(error.message).to.eql( - 'Invalid hasOne definition for Category#category: target model Category' + - ' is missing definition of foreign key categoryId', - ); + expect(meta).to.eql({ + name: 'thing', + type: 'hasOne', + targetsMany: false, + source: Category, + keyFrom: 'id', + target: () => Thing, + keyTo: 'categoryId', + }); + }); - expect(error.code).to.eql('INVALID_RELATION_DEFINITION'); - }); + it('throws if keyFrom, keyTo, and default foreign key name are not provided', async () => { + let error; - it('resolves metadata if keyTo and keyFrom are not provided, but default foreign key is', async () => { - Category.definition.addProperty('categoryId', {type: 'number'}); + try { + resolveHasOneMetadata(Category.definition.relations[ + 'category' + ] as HasOneDefinition); + } catch (err) { + error = err; + } - const meta = resolveHasOneMetadata(Category.definition.relations[ - 'category' - ] as HasOneDefinition); + expect(error.message).to.eql( + 'Invalid hasOne definition for Category#category: target model Category' + + ' is missing definition of foreign key categoryId', + ); - expect(meta).to.eql({ - name: 'category', - type: 'hasOne', - targetsMany: false, - source: Category, - keyFrom: 'id', - target: () => Category, - keyTo: 'categoryId', + expect(error.code).to.eql('INVALID_RELATION_DEFINITION'); }); - }); + it('resolves metadata if keyTo and keyFrom are not provided, but default foreign key is', async () => { + Category.definition.addProperty('categoryId', {type: 'number'}); + + const meta = resolveHasOneMetadata(Category.definition.relations[ + 'category' + ] as HasOneDefinition); + + expect(meta).to.eql({ + name: 'category', + type: 'hasOne', + targetsMany: false, + source: Category, + keyFrom: 'id', + target: () => Category, + keyTo: 'categoryId', + }); + }); + }); /****** HELPERS *******/ class Category extends Entity {} From 9fc1981a4342f68b49ee72f4e1e847347623ffd3 Mon Sep 17 00:00:00 2001 From: Nora Date: Thu, 7 Nov 2019 11:30:35 -0500 Subject: [PATCH 2/2] refactor(repository): simplify `resolve{Relation}Metadata` test setup --- .../resolve-has-many-metadata.integration.ts | 186 +++++++--------- .../resolve-has-one-metadata.integration.ts | 203 ++++++++---------- 2 files changed, 166 insertions(+), 223 deletions(-) diff --git a/packages/repository/src/__tests__/integration/repositories/resolve-has-many-metadata.integration.ts b/packages/repository/src/__tests__/integration/repositories/resolve-has-many-metadata.integration.ts index 595521e1386a..12f04b76adb6 100644 --- a/packages/repository/src/__tests__/integration/repositories/resolve-has-many-metadata.integration.ts +++ b/packages/repository/src/__tests__/integration/repositories/resolve-has-many-metadata.integration.ts @@ -17,7 +17,7 @@ describe('resolveHasManyMetadata', () => { const metadata: unknown = { name: 'category', type: RelationType.hasOne, - targetsMany: true, + targetsMany: false, source: Category, target: () => Category, }; @@ -31,9 +31,18 @@ describe('resolveHasManyMetadata', () => { describe('keyTo and keyFrom with resolveHasManyMetadata', () => { it('resolves metadata using keyTo and keyFrom', () => { - const meta = resolveHasManyMetadata(Category.definition.relations[ - 'products' - ] as HasManyDefinition); + const metadata = { + name: 'products', + type: RelationType.hasMany, + targetsMany: true, + + source: Category, + keyFrom: 'id', + + target: () => Product, + keyTo: 'categoryId', + }; + const meta = resolveHasManyMetadata(metadata as HasManyDefinition); expect(meta).to.eql({ name: 'products', @@ -47,65 +56,95 @@ describe('resolveHasManyMetadata', () => { }); it('infers keyFrom if it is not provided', () => { - const meta = resolveHasManyMetadata(Category.definition.relations[ - 'items' - ] as HasManyDefinition); + const metadata = { + name: 'products', + type: RelationType.hasMany, + targetsMany: true, + + source: Category, + // no keyFrom + + target: () => Product, + keyTo: 'categoryId', + }; + const meta = resolveHasManyMetadata(metadata as HasManyDefinition); expect(meta).to.eql({ - name: 'items', + name: 'products', type: 'hasMany', targetsMany: true, source: Category, keyFrom: 'id', - target: () => Item, + target: () => Product, keyTo: 'categoryId', }); }); it('infers keyTo if it is not provided', () => { - const meta = resolveHasManyMetadata(Category.definition.relations[ - 'things' - ] as HasManyDefinition); + const metadata = { + name: 'products', + type: RelationType.hasMany, + targetsMany: true, + + source: Category, + keyFrom: 'id', + + target: () => Product, + // no keyTo + }; + + const meta = resolveHasManyMetadata(metadata as HasManyDefinition); expect(meta).to.eql({ - name: 'things', + name: 'products', type: 'hasMany', targetsMany: true, source: Category, keyFrom: 'id', - target: () => Thing, + target: () => Product, keyTo: 'categoryId', }); }); it('throws if keyFrom, keyTo, and default foreign key name are not provided', async () => { - let error; - - try { - resolveHasManyMetadata(Category.definition.relations[ - 'categories' - ] as HasManyDefinition); - } catch (err) { - error = err; - } - - expect(error.message).to.eql( - 'Invalid hasMany definition for Category#categories: target model ' + - 'Category is missing definition of foreign key categoryId', - ); + const metadata = { + name: 'categories', + type: RelationType.hasMany, + targetsMany: true, - expect(error.code).to.eql('INVALID_RELATION_DEFINITION'); + source: Category, + // no keyFrom + + target: () => Category, + // no keyTo + }; + + expect(() => { + resolveHasManyMetadata(metadata as HasManyDefinition); + }).to.throw( + /Invalid hasMany definition for Category#categories: target model Category is missing definition of foreign key categoryId/, + ); }); it('resolves metadata if keyTo and keyFrom are not provided, but default foreign key is', async () => { Category.definition.addProperty('categoryId', {type: 'number'}); - const meta = resolveHasManyMetadata(Category.definition.relations[ - 'categories' - ] as HasManyDefinition); + const metadata = { + name: 'category', + type: RelationType.hasMany, + targetsMany: true, + + source: Category, + // no keyFrom + + target: () => Category, + // no keyTo + }; + + const meta = resolveHasManyMetadata(metadata as HasManyDefinition); expect(meta).to.eql({ - name: 'categories', + name: 'category', type: 'hasMany', targetsMany: true, source: Category, @@ -119,62 +158,11 @@ describe('resolveHasManyMetadata', () => { class Category extends Entity {} - Category.definition = new ModelDefinition('Category') - .addProperty('id', {type: 'number', id: true, required: true}) - .addRelation({ - name: 'products', - type: RelationType.hasMany, - targetsMany: true, - - source: Category, - keyFrom: 'id', - - target: () => Product, - keyTo: 'categoryId', - }) - .addRelation({ - name: 'items', - type: RelationType.hasMany, - targetsMany: true, - - source: Category, - // no keyFrom - - target: () => Item, - keyTo: 'categoryId', - }) - .addRelation({ - name: 'things', - type: RelationType.hasMany, - targetsMany: true, - - source: Category, - keyFrom: 'id', - - target: () => Thing, - // no keyTo - }) - .addRelation({ - name: 'categories', - type: RelationType.hasMany, - targetsMany: true, - - source: Category, - // no keyFrom - - target: () => Category, - // no keyTo - }) - // need to avoid Type 'RelationType.hasOne' is not comparable - // to type 'RelationType.hasMany' - .addRelation(({ - name: 'category', - type: RelationType.hasOne, - targetsMany: true, - source: Category, - // no keyFrom - target: () => Category, - })); + Category.definition = new ModelDefinition('Category').addProperty('id', { + type: 'number', + id: true, + required: true, + }); class Product extends Entity {} @@ -185,24 +173,4 @@ describe('resolveHasManyMetadata', () => { required: true, }) .addProperty('categoryId', {type: 'number'}); - - class Item extends Entity {} - - Item.definition = new ModelDefinition('Item') - .addProperty('id', { - type: 'number', - id: true, - required: true, - }) - .addProperty('categoryId', {type: 'number'}); - - class Thing extends Entity {} - - Thing.definition = new ModelDefinition('Thing') - .addProperty('id', { - type: 'number', - id: true, - required: true, - }) - .addProperty('categoryId', {type: 'number'}); }); diff --git a/packages/repository/src/__tests__/integration/repositories/resolve-has-one-metadata.integration.ts b/packages/repository/src/__tests__/integration/repositories/resolve-has-one-metadata.integration.ts index bfb776565845..dd22965f1c79 100644 --- a/packages/repository/src/__tests__/integration/repositories/resolve-has-one-metadata.integration.ts +++ b/packages/repository/src/__tests__/integration/repositories/resolve-has-one-metadata.integration.ts @@ -15,94 +15,133 @@ import {resolveHasOneMetadata} from '../../../relations/has-one/has-one.helpers' describe('resolveHasOneMetadata', () => { it('throws if the wrong metadata type is used', async () => { const metadata: unknown = { - name: 'product', + name: 'category', type: RelationType.hasMany, targetsMany: true, - source: Category, - target: () => Product, + source: Product, + target: () => Category, }; expect(() => { resolveHasOneMetadata(metadata as HasOneDefinition); }).to.throw( - /Invalid hasMany definition for Category#product: relation type must be HasOne/, + /Invalid hasMany definition for Product#category: relation type must be HasOne/, ); }); describe('keyTo and keyFrom with resolveHasOneMetadata', () => { it('resolves metadata using keyTo and keyFrom', () => { - const meta = resolveHasOneMetadata(Category.definition.relations[ - 'product' - ] as HasOneDefinition); + const metadata = { + name: 'category', + type: RelationType.hasOne, + targetsMany: false, + + source: Product, + keyFrom: 'id', + + target: () => Category, + keyTo: 'productId', + }; + const meta = resolveHasOneMetadata(metadata as HasOneDefinition); expect(meta).to.eql({ - name: 'product', + name: 'category', type: 'hasOne', targetsMany: false, - source: Category, + source: Product, keyFrom: 'id', - target: () => Product, - keyTo: 'categoryId', + target: () => Category, + keyTo: 'productId', }); }); it('infers keyFrom if it is not provided', () => { - const meta = resolveHasOneMetadata(Category.definition.relations[ - 'item' - ] as HasOneDefinition); + const metadata = { + name: 'category', + type: 'hasOne', + targetsMany: false, + + source: Product, + // no keyFrom + + target: () => Category, + keyTo: 'productId', + }; + const meta = resolveHasOneMetadata(metadata as HasOneDefinition); expect(meta).to.eql({ - name: 'item', + name: 'category', type: 'hasOne', targetsMany: false, - source: Category, + source: Product, keyFrom: 'id', - target: () => Item, - keyTo: 'categoryId', + target: () => Category, + keyTo: 'productId', }); }); it('infers keyTo if it is not provided', () => { - const meta = resolveHasOneMetadata(Category.definition.relations[ - 'thing' - ] as HasOneDefinition); + const metadata = { + name: 'category', + type: RelationType.hasOne, + targetsMany: false, + + source: Product, + keyFrom: 'id', + + target: () => Category, + // no keyTo + }; + + const meta = resolveHasOneMetadata(metadata as HasOneDefinition); expect(meta).to.eql({ - name: 'thing', + name: 'category', type: 'hasOne', targetsMany: false, - source: Category, + source: Product, keyFrom: 'id', - target: () => Thing, - keyTo: 'categoryId', + target: () => Category, + keyTo: 'productId', }); }); it('throws if keyFrom, keyTo, and default foreign key name are not provided', async () => { - let error; - - try { - resolveHasOneMetadata(Category.definition.relations[ - 'category' - ] as HasOneDefinition); - } catch (err) { - error = err; - } - - expect(error.message).to.eql( - 'Invalid hasOne definition for Category#category: target model Category' + - ' is missing definition of foreign key categoryId', - ); + const metadata = { + name: 'category', + type: RelationType.hasOne, + targetsMany: false, + + source: Category, + // no keyFrom - expect(error.code).to.eql('INVALID_RELATION_DEFINITION'); + target: () => Category, + // no keyTo + }; + + expect(() => { + resolveHasOneMetadata(metadata as HasOneDefinition); + }).to.throw( + /Invalid hasOne definition for Category#category: target model Category is missing definition of foreign key categoryId/, + ); }); it('resolves metadata if keyTo and keyFrom are not provided, but default foreign key is', async () => { Category.definition.addProperty('categoryId', {type: 'number'}); - const meta = resolveHasOneMetadata(Category.definition.relations[ - 'category' - ] as HasOneDefinition); + const metadata = { + name: 'category', + type: RelationType.hasOne, + targetsMany: false, + + source: Category, + // no keyFrom + + target: () => Category, + // no keyTo + }; + + const meta = resolveHasOneMetadata(metadata as HasOneDefinition); expect(meta).to.eql({ name: 'category', @@ -115,84 +154,20 @@ describe('resolveHasOneMetadata', () => { }); }); }); + /****** HELPERS *******/ class Category extends Entity {} Category.definition = new ModelDefinition('Category') .addProperty('id', {type: 'number', id: true, required: true}) - .addRelation({ - name: 'product', - type: RelationType.hasOne, - targetsMany: false, - - source: Category, - keyFrom: 'id', - - target: () => Product, - keyTo: 'categoryId', - }) - .addRelation({ - name: 'item', - type: RelationType.hasOne, - targetsMany: false, - - source: Category, - // no keyFrom - - target: () => Item, - keyTo: 'categoryId', - }) - .addRelation({ - name: 'thing', - type: RelationType.hasOne, - targetsMany: false, - - source: Category, - keyFrom: 'id', - - target: () => Thing, - // no keyTo - }) - .addRelation({ - name: 'category', - type: RelationType.hasOne, - targetsMany: false, - - source: Category, - // no keyFrom - - target: () => Category, - // no keyTo - }); + .addProperty('productId', {type: 'number', required: true}); class Product extends Entity {} - Product.definition = new ModelDefinition('Product') - .addProperty('id', { - type: 'number', - id: true, - required: true, - }) - .addProperty('categoryId', {type: 'number'}); - - class Item extends Entity {} - - Item.definition = new ModelDefinition('Item') - .addProperty('id', { - type: 'number', - id: true, - required: true, - }) - .addProperty('categoryId', {type: 'number'}); - - class Thing extends Entity {} - - Thing.definition = new ModelDefinition('Thing') - .addProperty('id', { - type: 'number', - id: true, - required: true, - }) - .addProperty('categoryId', {type: 'number'}); + Product.definition = new ModelDefinition('Product').addProperty('id', { + type: 'number', + id: true, + required: true, + }); });