API Docs for: 0.1.0.ee3e9e64
Show:

File: addon/mixins/atomic-serializer.js

/**
  @module solr
*/

import Ember from 'ember';
import NotDirtyError from 'ember-solr/not-dirty-error';

const get = Ember.get;

/**
  Mixin that serializes uses [Atomic Updates](https://wiki.apache.org/solr/Atomic_Updates)
  to only update fields that have been modified.

  Atomic Updates can optionally include Optimistic Concurrency
  to ensure updates are not conflicting with other clients.
  See {{#crossLink "SolrAdapter/updateMode:property"}}SolrAdapter.updateMode{{/crossLink}}.

  This implementation treats arrays as ordered and non-distinct.
  A multiValued field will be updated if the order of items
  changes or if any items are added or removed. The entire
  array will be sent using a `set` operation to preserve order
  and allow for duplicate values.

  To treat multiValued fields as distinct sets, use
  {{#crossLink "AtomicMultiValuedSerializerMixin"}}{{/crossLink}}
  which will use `add` and `remove` operations.

  @class AtomicSerializerMixin
  @extends SolrSerializer
*/
export default Ember.Mixin.create({

  /**
    Serialize only modified attributes for a snapshot
    using atomic update operations.

    @method serialize
    @param {DS.Snapshot} snapshot
    @param {object} options
  */
  serialize: function(snapshot, options) {
    // don't pass options with includeId = true; handled later.
    var json = this._super(snapshot);

    if (Ember.isEmpty(Object.keys(json))) {
      throw new NotDirtyError(snapshot.type, snapshot.id);
    }

    var id = snapshot.id;
    if (id) {
      var primaryKey = get(this, 'primaryKey') || 'id';
      json[primaryKey] = id;
    }

    if (typeof this.setVersionConstraint === 'function') {
      this.setVersionConstraint(snapshot, options, json);
    }

    return json;
  },

  /**
    Determines if an attribute can be serialized and if the
    value is dirty.

    @method serializeAttribute
    @param {DS.Snapshot} snapshot
    @param {object} json
    @param {string} key
    @param {DS.Attribute} attribute
  */
  serializeAttribute: function(snapshot, json, key, attribute) {
    if (typeof this._canSerialize === 'function' && !this._canSerialize(key)) {
      return;
    }

    var value = snapshot.attr(key);
    var previousValue = get(snapshot.record, 'data')[key];

    var type = attribute.type;
    if (type) {
      var transform = this.transformFor(type);
      value = transform.serialize(value);
      previousValue = transform.serialize(previousValue);
    }

    if (!this.isAttributeModified(snapshot, key, attribute, value, previousValue)) {
      return;
    }

    var payloadKey = key;

    // this is bad and you should feel bad:
    if (typeof this._getMappedKey === 'function') {
      payloadKey = this._getMappedKey(key);
    }

    if (payloadKey === key && typeof this.keyForAttribute === 'function') {
      payloadKey = this.keyForAttribute(key);
    }

    if (Array.isArray(value) || Array.isArray(previousValue)) {
      var diff = this.serializeArrayAttribute(snapshot, key, attribute, value, previousValue);
      if (!Ember.isEmpty(Object.keys(diff))) {
        json[payloadKey] = diff;
      }
    } else {
      json[payloadKey] = {set: value};
    }
  },

  /**
    Determine if a value is modified from a previous value.

    @method isAttributeModified
    @param {DS.Snapshot} snapshot
    @param {string} key
    @param {DS.Attribute} attribtue
    @param {anything} value
    @param {anything} previousValue
    @return {boolean}
  */
  isAttributeModified: function(snapshot, key, attribute, value, previousValue) {
    if (!Array.isArray(value) && !Array.isArray(previousValue)) {
      return value !== previousValue;
    }

    value = value || [];
    previousValue = previousValue || [];

    if (value.length !== previousValue.length) {
      return true;
    }

    for (var i=0; i<value.length; i++) {
      if (value[i] !== previousValue[i]) {
        return true;
      }
    }

    return false;
  },

  /**
    Serialize an update to a multiValued field.

    @method serializeArrayAttribute
    @param {DS.Snapshot} snapshot
    @param {string} key
    @param {DS.Attribute} attribute
    @param {anything} value
    @param {anything} previousValue
    @return {object}
  */
  serializeArrayAttribute: function(snapshot, key, attribute, value /*, previousValue */) {
    return {set: value};
  }
});