Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MorphMany #111

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8bec10a
Init MorphMany
ryandialpad Nov 23, 2021
2f75dcd
Adding MorphMany tests, removing TODOs from tested MorphMany methods.
ryandialpad Nov 24, 2021
1bba446
Removing TODO from tested method in MorphMany
ryandialpad Nov 24, 2021
e774cbe
Fixing a typo
ryandialpad Nov 25, 2021
03160be
Moving fill state into before all block
ryandialpad Nov 25, 2021
d6dd6c6
Correcting a typo
ryandialpad Nov 25, 2021
41aa1a8
Touching up some test descriptions
ryandialpad Nov 25, 2021
cafc529
Addressing PR comments
ryandialpad Nov 29, 2021
98d366f
Merge branch 'master' into morph-many
ryandialpad Dec 3, 2021
7d7c50d
Refactoring MorphMany match method to use query instead of results
ryandialpad Dec 3, 2021
6eb7366
Init MorphMany
ryandialpad Nov 23, 2021
f3b449d
Adding MorphMany tests, removing TODOs from tested MorphMany methods.
ryandialpad Nov 24, 2021
f13c298
Removing TODO from tested method in MorphMany
ryandialpad Nov 24, 2021
3defb88
Fixing a typo
ryandialpad Nov 25, 2021
b83e961
Moving fill state into before all block
ryandialpad Nov 25, 2021
de213c4
Correcting a typo
ryandialpad Nov 25, 2021
ae8453e
Touching up some test descriptions
ryandialpad Nov 25, 2021
ea25ea6
Addressing PR comments
ryandialpad Nov 29, 2021
8afbfd8
Refactoring MorphMany match method to use query instead of results
ryandialpad Dec 3, 2021
739dd38
Merge branch 'morph-many' of github.com:vuex-orm/vuex-orm-next into m…
ryandialpad Dec 3, 2021
ad65710
Resolving some duplicate code after resolving conflicts
ryandialpad Dec 3, 2021
7e5f0fe
Removing another duplicated import
ryandialpad Dec 3, 2021
f16c621
Fixing up some comment headers
ryandialpad Dec 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/index.cjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { BelongsTo } from './model/decorators/attributes/relations/BelongsTo'
import { HasMany } from './model/decorators/attributes/relations/HasMany'
import { HasManyBy } from './model/decorators/attributes/relations/HasManyBy'
import { MorphOne } from './model/decorators/attributes/relations/MorphOne'
import { MorphMany } from './model/decorators/attributes/relations/MorphMany'
import { Attribute } from './model/attributes/Attribute'
import { Type } from './model/attributes/types/Type'
import { Attr as AttrAttr } from './model/attributes/types/Attr'
Expand All @@ -29,6 +30,7 @@ import { BelongsTo as BelongsToAttr } from './model/attributes/relations/Belongs
import { HasMany as HasManyAttr } from './model/attributes/relations/HasMany'
import { HasManyBy as HasManyByAttr } from './model/attributes/relations/HasManyBy'
import { MorphOne as MorphOneAttr } from './model/attributes/relations/MorphOne'
import { MorphMany as MorphManyAttr } from './model/attributes/relations/MorphMany'
import { Repository } from './repository/Repository'
import { Interpreter } from './interpreter/Interpreter'
import { Query } from './query/Query'
Expand All @@ -51,6 +53,7 @@ export default {
HasMany,
HasManyBy,
MorphOne,
MorphMany,
Attribute,
Type,
AttrAttr,
Expand All @@ -64,6 +67,7 @@ export default {
HasManyAttr,
HasManyByAttr,
MorphOneAttr,
MorphManyAttr,
Repository,
Interpreter,
Query,
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export * from './model/decorators/attributes/relations/HasMany'
export * from './model/decorators/attributes/relations/HasManyBy'
export * from './model/decorators/attributes/relations/MorphOne'
export * from './model/decorators/attributes/relations/MorphTo'
export * from './model/decorators/attributes/relations/MorphMany'
export * from './model/decorators/Contracts'
export * from './model/decorators/NonEnumerable'
export * from './model/attributes/Attribute'
Expand All @@ -33,6 +34,7 @@ export { HasMany as HasManyAttr } from './model/attributes/relations/HasMany'
export { HasManyBy as HasManyByAttr } from './model/attributes/relations/HasManyBy'
export { MorphOne as MorphOneAttr } from './model/attributes/relations/MorphOne'
export { MorphTo as MorphToAttr } from './model/attributes/relations/MorphTo'
export { MorphMany as MorphManyAttr } from './model/attributes/relations/MorphMany'
export * from './modules/RootModule'
export * from './modules/RootState'
export * from './modules/Module'
Expand Down Expand Up @@ -66,6 +68,7 @@ import { HasMany as HasManyAttr } from './model/attributes/relations/HasMany'
import { HasManyBy as HasManyByAttr } from './model/attributes/relations/HasManyBy'
import { MorphOne as MorphOneAttr } from './model/attributes/relations/MorphOne'
import { MorphTo as MorphToAttr } from './model/attributes/relations/MorphTo'
import { MorphMany as MorphManyAttr } from './model/attributes/relations/MorphMany'
import { Repository } from './repository/Repository'
import { Interpreter } from './interpreter/Interpreter'
import { Query } from './query/Query'
Expand All @@ -92,6 +95,7 @@ export default {
HasManyByAttr,
MorphOneAttr,
MorphToAttr,
MorphManyAttr,
Repository,
Interpreter,
Query,
Expand Down
17 changes: 17 additions & 0 deletions src/model/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { HasMany } from './attributes/relations/HasMany'
import { HasManyBy } from './attributes/relations/HasManyBy'
import { MorphOne } from './attributes/relations/MorphOne'
import { MorphTo } from './attributes/relations/MorphTo'
import { MorphMany } from './attributes/relations/MorphMany'

export type ModelFields = Record<string, Attribute>
export type ModelSchemas = Record<string, ModelFields>
Expand Down Expand Up @@ -263,6 +264,22 @@ export class Model {
return new MorphTo(instance, relatedModels, id, type, ownerKey)
}

/**
* Create a new MorphMany relation instance.
*/
static morphMany(
related: typeof Model,
id: string,
type: string,
localKey?: string
): MorphMany {
const model = this.newRawInstance()

localKey = localKey ?? model.$getLocalKey()

return new MorphMany(model, related.newRawInstance(), id, type, localKey)
}

/**
* Get the constructor for this model.
*/
Expand Down
102 changes: 102 additions & 0 deletions src/model/attributes/relations/MorphMany.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Schema as NormalizrSchema } from 'normalizr'
import { Schema } from '../../../schema/Schema'
import { Element, Collection } from '../../../data/Data'
import { Query } from '../../../query/Query'
import { Model } from '../../Model'
import { Relation, Dictionary } from './Relation'

export class MorphMany extends Relation {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am noticing a fair amount of code duplication, at some point we might want to DRY these up once the library is feature complete (1.x).

/**
* The field name that contains id of the parent model.
*/
protected morphId: string

/**
* The field name that contains type of the parent model.
*/
protected morphType: string

/**
* The local key of the model.
*/
protected localKey: string

/**
* Create a new morph-many relation instance.
*/
constructor(
parent: Model,
related: Model,
morphId: string,
morphType: string,
localKey: string
) {
super(parent, related)
this.morphId = morphId
this.morphType = morphType
this.localKey = localKey
}

/**
* Get all related models for the relationship.
*/
getRelateds(): Model[] {
return [this.related]
}

/**
* Define the normalizr schema for the relation.
*/
define(schema: Schema): NormalizrSchema {
return schema.many(this.related, this.parent)
}

/**
* Attach the parent type and id to the given relation.
*/
attach(record: Element, child: Element): void {
child[this.morphId] = record[this.localKey]
child[this.morphType] = this.parent.$entity()
}

/**
* Set the constraints for an eager load of the relation.
*/
addEagerConstraints(query: Query, models: Collection): void {
query.where(this.morphType, this.parent.$entity())
query.whereIn(this.morphId, this.getKeys(models, this.localKey))
}

/**
* Match the eagerly loaded results to their parents.
*/
match(relation: string, models: Collection, query: Query): void {
const dictionary = this.buildDictionary(query.get())

models.forEach((model) => {
const key = model[this.localKey]

dictionary[key]
? model.$setRelation(relation, dictionary[key])
: model.$setRelation(relation, [])
})
}

/**
* Build model dictionary keyed by the relation's foreign key.
*/
protected buildDictionary(results: Collection): Dictionary {
return this.mapToDictionary(results, (result) => {
return [result[this.morphId], result]
})
}

/**
* Make related models.
*/
make(elements?: Element[]): Model[] {
return elements
? elements.map((element) => this.related.$newInstance(element))
: []
}
}
20 changes: 20 additions & 0 deletions src/model/decorators/attributes/relations/MorphMany.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Model } from '../../../Model'
import { PropertyDecorator } from '../../Contracts'

/**
* Create a morph-many attribute property decorator.
*/
export function MorphMany(
related: () => typeof Model,
id: string,
type: string,
localKey?: string
): PropertyDecorator {
return (target, propertyKey) => {
const self = target.$self()

self.setRegistry(propertyKey, () =>
self.morphMany(related(), id, type, localKey)
)
}
}
Loading