Skip to content

Persistence

jacwright edited this page Oct 14, 2014 · 1 revision

TeamSnap.js provides a specialized feature called Persistence for working with single users such as in a browser-based application. When Persistence is enabled, it alters TeamSnap.js to automatically do a little more behind-the-scenes. Persistence keeps all loaded items in memory, links them together automatically by their links, ensures when items are loaded they update their existing versions rather than create duplicates, and provides a rollback/undo mechanism to revert to the last saved state.

The methods associated with Persistence are:

  • enablePersistence() Enables persistence starting now, items previously loaded will not be persisted
  • enablePersistence(cachedItems) Starts persistence with objects loaded from cache (e.g. JSON.parse(JSON.stringify(teamsnap.getAllItems())))
  • disablePersistence() Disables, unlinks, and otherwise lets go of persisted items
  • findItem(href) Finds a loaded item by href when persistence is enabled
  • getAllItems() Returns all persisted items
  • linkItems(items) Adds provided items to Persistence and links them with existing and each other
  • unlinkItems(items) Removes provided items from Persistence and unlinks them
  • unlinkTeam(team) Removes a team and all of its data from Persistence

When enabling Persistence, items are given additional methods to help with this:

  • link(rel, relatedItem) Sets the link (and foreignKeyId) of an item to another, and links them
  • saveState() Saves the state as it currently is, automatically called when loaded and after save
  • rollback() Rolls an item back to its last saved state

Linking

Persistence Linking will connect related items together. If you load a team, all its members, all its events, and all its availabilities, the items will all be linked together. You will be able to have arrays such as team.members, member.availabilities, event.availabilities, and team.events. You will be able to easily access related data such as member.team.name and availability.member.firstName + ' - ' + availability.event.startDate.

Note: it is easy for a member to link into its team and add itself to the team's members array, but it is harder for the team to find all members that belong to it. Therefore, Linking works best when you load all the data at once or load the arrays of items after the single item (such as loading team before members, or events before availabilities). Persistence is really meant to work with a whole team's data (or more than one team) at a time.

Single instance enforced

A common problem that must be dealt with when keeping persistent data in-memory is when updating your data you can end up with duplicates. Persistence prevents this by ensuring only one item per href is kept in memory. If you were to use teamsnap.createEvent({ href: 'http...12345' }) when an item by that href already existed, the existing item would be returned from the createEvent method instead of a brand new one. If you call loadMembers(teamId) once and get back 20 members, then call loadMembers(teamId) again, you will get back those same 20 members, such that membersFirst[0] === membersSecond[0] would be true. While Persistence ensures the items are not duplicated, items that are loaded later will update the data on existing items allowing a reload to refresh the data.

Rollback

Another common problem with persistent data, especially in user-facing applications, is when a user changes the data of an item but then decides to cancel the operation, we need an easy way to revert to the original saved state. item.rollback() does this automatically for us, including undoing any links we've created using item.link(rel, relatedItem) since the last time the item was loaded or saved.

When using create*() and item will be returned that hasn't been loaded or saved. In this case, you can use item.link(rel, relatedItem) to temporarily link this un-saved item, but if the action is canceled and you call item.rollback(), the item will be unlinked and removed.

Example:

var newMember = teamsnap.createMember();
newMember.link('team', team);
team.members.indexOf(newMember); // does not equal -1, the member exists in the array
newMember.rollback();
team.members.indexOf(newMember); // equals -1, the member is removed

Domain smart

In addition to the generic additions Persistence adds to TeamSnap.js when enabled, it also is smart about the needs of specific methods in TeamSnap.js. For example, when deleting a repeating event with include = 'future', Persistence will remove all the events deleted from memory, not just the one passed. When a member is created, Persistence loads all the availabilities, customData, and trackedItemStatuses for that member automatically, and will remove all these objects when that member is deleted. Once you load a team, you can be assured that all the data for that team will be in-memory.

Memory concerns

Because items are persistent in-memory, it is important that you remove items no longer needed. Persistence will automatically remove items that you delete, but it will not automatically remove items you are no longer using.

For example, if you have hundreds of teams, say you are a league commissioner, you may load a team into memory using bulkLoad(teamId) so that you can access its data and do anything you need, however you should call teamsnap.unlinkTeam(team) when done, otherwise you may end up with millions of items in-memory and crash your browser after loading many teams.

Clone this wiki locally