Skip to content

Instantly share code, notes, and snippets.

@wycats
Created January 14, 2014 03:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wycats/8412578 to your computer and use it in GitHub Desktop.
Save wycats/8412578 to your computer and use it in GitHub Desktop.

There are several types of relationships.

  • OneToMany
  • OneToOne
  • OneToNone
  • ManyToNone

A OneToMany relationship has a Set of members and a link to the belongsTo. Each member and the belongsTo has a link back to the relationship. The member links can change.

A ManyToNone relationship has a Set of members and a link to the belongsTo. The belongsTo has a link back to the relationship. The link doesn't change.

A OneToOne relationship has a Set of members. Each member has a link back to the relationships. Either of the links may change.

A OneToNone relationship has a member and a belongsTo. The member has a link back to the relationship.

When a record is created for the first time, the kind of each relationship is determined. This determination is based on the kind of the relationship and the kind of its inverse.

These relationships are represented on one or more records by ManyArrays and belongsTo computed property caches.

Setting a Belongs-To Value (store.updateBelongsTo)

Parameters: name, newRecord

  1. let rel be record.relationshipFor(name)
  2. rel.removeMember(record)
  3. If newValue exists:
    1. let newRel be record.relationshipFor(name, newRecord)
    2. Call newRel.addMember(record) on the relationship

The abstraction is that a belongs-to relationship represents membership in a has-many set. In some cases (OneToNone), there is no actual has-many set, but the relationship implements the same hooks.

In some cases, the relationship may become unlinked when removeMember is called and linked to a new relationship when relationshipFor is called.

Adding to a ManyArray (store.addToRelationship)

Parameters: name, position, member

  1. let rel be record.relationshipFor(name)
  2. rel.addMember(member, position)

The relationships that represent a ManyArray are never unlinked from the primary record during these steps.

Removing from a ManyArray (store.removeFromRelationship)

Parameters: name, position

  1. let rel be record.relationshipFor(name)
  2. rel.removeMember(member, position)

Loading Data for the first time (setupRelationships)

Parameters: record, data Optional Parameter: inverse

inverse is passed along if the record was looked up through a relationship (for example record.fetch(name)) because the relationship value is often not provided in payloads.

  1. For each relName in record's relationships:
    1. let rel be record.relationshipFor(relName, inverse)

Updating Data

Request-Provided Inverses

Relationships

record.relationshipFor(name, value)

  1. let myKind be the kind of the name relationship on record
  2. let inverseKind, inverseName be the kind and name of the inverse of the name relationship
  3. Let RelationshipType be the result of getting from the registered map of relationship types with myKind and inverseKind as keys.
  4. Return RelationshipType.create(name, record, value)
Key A Key B Result
hasMany belongsTo ManyToOne
belongsTo hasMany OneToMany
hasMany null ManyToNone
belongsTo null OneToNone
belongsTo belongsTo OneToOne

Note: ManyToOne is just a wrapper that takes the arguments in reverse position and returns a OneToMany.

Abstract

rel.removeMember(member, [position])

rel.addMember(member, [position])

OneToMany

class ManyToNone {
  primary: Model,
  hasManySet: Set<Model>,
  hasManyName: string,
  belongsToName: string
}

OneToMany.create(name, value, record)

  • If the relationship already exists

removeMember(rec, position)

  • Remove rec from hasManySet
  • Unlink rec
  • Notify primary[hasManyName]
  • Notify rec[belongsToName]

addMember(rec)

  • Add rec to hasManySet
  • Link rec
  • Notify primary[hasManyName]
  • Notify rec[belongsToName]

ManyToNone

class ManyToNone {
  primary: Model,
  hasManySet: Set<Model>,
  hasManyName: string
}

removeMember(rec)

  • Remove rec from hasManySet
  • Notify primary[hasManyName]

OneToNone

struct OneToNone {
  primary: Model,
  belongsTo: Model,
  belongsToName: string
}

A OneToNone relationship is like a OneToMany relationship without a hasMany inverse.

belongsTo.relationshipFor(name, value)

  • If the relationship already exists:
    • Update the relationship's belongsTo with the new value
  • Otherwise:
    • Create a new OneToNone with primary: rec, belongsTo: value, and belongsToName: name

removeMember(rec)

  • Null out belongsTo
  • Notify primary[belongsToName] of the change

addMember(rec)

  • Notify primary[belongsToName] of the change

OneToOne

class OneToOne {
  a: Model,
  b: Model,
  aName: string,
  bName: string
}

OneToOne records aren't pinned on either side.

belongsTo.relationshipFor(name, value)

  • Assert that the relationship doesn't exist
  • Create a new OneToOne with a: rec, b: value, aName: name, bName: <inverseName>

removeMember(rec)

  • Unlink both records
  • Notify a[aName] and b[bName]
  • (the relationship should be GCed after this)

addMember(rec)

  • Notify a and b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment