-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(repository): add keyFrom to resolved relation metadata
- Loading branch information
1 parent
7752b08
commit 62f803e
Showing
4 changed files
with
352 additions
and
4 deletions.
There are no files selected for viewing
164 changes: 164 additions & 0 deletions
164
...epository/src/__tests__/integration/repositories/resolve-has-many-metadata.integration.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
// 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 { | ||
Entity, | ||
HasManyDefinition, | ||
ModelDefinition, | ||
RelationType, | ||
} 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', | ||
targetsMany: true, | ||
source: Category, | ||
keyFrom: 'id', | ||
target: () => Product, | ||
keyTo: 'categoryId', | ||
}); | ||
}); | ||
|
||
it('resolves metadata using keyTo, but not keyFrom', () => { | ||
const meta = resolveHasManyMetadata(Category.definition.relations[ | ||
'items' | ||
] as HasManyDefinition); | ||
|
||
expect(meta).to.not.have.property('keyFrom'); | ||
|
||
expect(meta).to.eql({ | ||
name: 'items', | ||
type: 'hasMany', | ||
targetsMany: true, | ||
source: Category, | ||
target: () => Item, | ||
keyTo: 'categoryId', | ||
}); | ||
}); | ||
|
||
it('infers keyTo if is it not provided', () => { | ||
const meta = resolveHasManyMetadata(Category.definition.relations[ | ||
'things' | ||
] as HasManyDefinition); | ||
|
||
expect(meta).to.eql({ | ||
name: 'things', | ||
type: 'hasMany', | ||
targetsMany: true, | ||
source: Category, | ||
keyFrom: 'id', | ||
target: () => Thing, | ||
keyTo: 'categoryId', | ||
}); | ||
}); | ||
|
||
it('throws if both keyFrom and keyTo 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', | ||
); | ||
|
||
expect(error.code).to.eql('INVALID_RELATION_DEFINITION'); | ||
}); | ||
|
||
/****** HELPERS *******/ | ||
|
||
class Category extends Entity {} | ||
|
||
Category.definition = new ModelDefinition('Category') | ||
.addProperty('id', {type: 'number', id: true, required: true}) | ||
.addRelation(<HasManyDefinition>{ | ||
name: 'products', | ||
type: RelationType.hasMany, | ||
targetsMany: true, | ||
|
||
source: Category, | ||
keyFrom: 'id', | ||
|
||
target: () => Product, | ||
keyTo: 'categoryId', | ||
}) | ||
.addRelation(<HasManyDefinition>{ | ||
name: 'items', | ||
type: RelationType.hasMany, | ||
targetsMany: true, | ||
|
||
source: Category, | ||
// no keyFrom | ||
|
||
target: () => Item, | ||
keyTo: 'categoryId', | ||
}) | ||
.addRelation(<HasManyDefinition>{ | ||
name: 'things', | ||
type: RelationType.hasMany, | ||
targetsMany: true, | ||
|
||
source: Category, | ||
keyFrom: 'id', | ||
|
||
target: () => Thing, | ||
// no keyTo | ||
}) | ||
.addRelation(<HasManyDefinition>{ | ||
name: 'categories', | ||
type: RelationType.hasMany, | ||
targetsMany: true, | ||
|
||
source: Category, | ||
// no keyFrom | ||
|
||
target: () => Category, | ||
// no keyTo | ||
}); | ||
|
||
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'}); | ||
}); |
164 changes: 164 additions & 0 deletions
164
...repository/src/__tests__/integration/repositories/resolve-has-one-metadata.integration.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
// 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 { | ||
Entity, | ||
HasOneDefinition, | ||
ModelDefinition, | ||
RelationType, | ||
} 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({ | ||
name: 'product', | ||
type: 'hasOne', | ||
targetsMany: false, | ||
source: Category, | ||
keyFrom: 'id', | ||
target: () => Product, | ||
keyTo: 'categoryId', | ||
}); | ||
}); | ||
|
||
it('resolves metadata using keyTo, but not keyFrom', () => { | ||
const meta = resolveHasOneMetadata(Category.definition.relations[ | ||
'item' | ||
] as HasOneDefinition); | ||
|
||
expect(meta).to.not.have.property('keyFrom'); | ||
|
||
expect(meta).to.eql({ | ||
name: 'item', | ||
type: 'hasOne', | ||
targetsMany: false, | ||
source: Category, | ||
target: () => Item, | ||
keyTo: 'categoryId', | ||
}); | ||
}); | ||
|
||
it('infers keyTo if is it not provided', () => { | ||
const meta = resolveHasOneMetadata(Category.definition.relations[ | ||
'thing' | ||
] as HasOneDefinition); | ||
|
||
expect(meta).to.eql({ | ||
name: 'thing', | ||
type: 'hasOne', | ||
targetsMany: false, | ||
source: Category, | ||
keyFrom: 'id', | ||
target: () => Thing, | ||
keyTo: 'categoryId', | ||
}); | ||
}); | ||
|
||
it('throws if both keyFrom and keyTo 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', | ||
); | ||
|
||
expect(error.code).to.eql('INVALID_RELATION_DEFINITION'); | ||
}); | ||
|
||
/****** HELPERS *******/ | ||
|
||
class Category extends Entity {} | ||
|
||
Category.definition = new ModelDefinition('Category') | ||
.addProperty('id', {type: 'number', id: true, required: true}) | ||
.addRelation(<HasOneDefinition>{ | ||
name: 'product', | ||
type: RelationType.hasOne, | ||
targetsMany: false, | ||
|
||
source: Category, | ||
keyFrom: 'id', | ||
|
||
target: () => Product, | ||
keyTo: 'categoryId', | ||
}) | ||
.addRelation(<HasOneDefinition>{ | ||
name: 'item', | ||
type: RelationType.hasOne, | ||
targetsMany: false, | ||
|
||
source: Category, | ||
// no keyFrom | ||
|
||
target: () => Item, | ||
keyTo: 'categoryId', | ||
}) | ||
.addRelation(<HasOneDefinition>{ | ||
name: 'thing', | ||
type: RelationType.hasOne, | ||
targetsMany: false, | ||
|
||
source: Category, | ||
keyFrom: 'id', | ||
|
||
target: () => Thing, | ||
// no keyTo | ||
}) | ||
.addRelation(<HasOneDefinition>{ | ||
name: 'category', | ||
type: RelationType.hasOne, | ||
targetsMany: false, | ||
|
||
source: Category, | ||
// no keyFrom | ||
|
||
target: () => Category, | ||
// no keyTo | ||
}); | ||
|
||
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'}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters