Socket
Socket
Sign inDemoInstall

emberfire

Package Overview
Dependencies
Maintainers
1
Versions
70
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

emberfire - npm Package Compare versions

Comparing version 1.2.5 to 1.2.6

lib/ember-addon/blueprints/emberfire/index.js.original

536

dist/emberfire.js

@@ -6,3 +6,3 @@ /*!

*
* EmberFire 1.2.5
* EmberFire 1.2.6
* https://github.com/firebase/emberfire/

@@ -20,3 +20,3 @@ * License: MIT

var EmberFire = Ember.Namespace.create({
VERSION: '1.2.5'
VERSION: '1.2.6'
});

@@ -28,2 +28,26 @@

//Monkeypatch the store until ED gives us a good way to listen to push events
DS.Store.reopen({
push: function(typeName, data, _partial) {
var record = this._super(typeName, data, _partial);
var adapter = this.adapterFor(record.constructor);
if (adapter.recordWasPushed) {
adapter.recordWasPushed(this, typeName, record);
}
return record;
},
recordWillUnload: function(record) {
var adapter = this.adapterFor(record.constructor);
if (adapter.recordWillUnload) {
adapter.recordWillUnload(this, record);
}
}
});
DS.Model.reopen({
unloadRecord: function() {
this.store.recordWillUnload(this);
return this._super();
}
});
// Shortcuts

@@ -35,2 +59,21 @@ var Promise = Ember.RSVP.Promise;

var toPromise = function(fn, context, _args, errorMsg) {
var args = _args || [];
return new Promise(function(resolve, reject) {
var callback = function(error) {
if (error) {
if (errorMsg && typeof error === 'object') {
error.location = errorMsg;
}
reject(error);
} else {
resolve();
}
};
args.push(callback);
fn.apply(context, args);
});
};
/**

@@ -42,2 +85,61 @@ The Firebase serializer helps normalize relationships and can be extended on

//We need to account for Firebase turning key/value pairs with ids '1' and '0' into arrays
//See https://github.com/firebase/emberfire/issues/124
_normalizeNumberIDs: function(hash, key) {
var newHash = [];
if (hash[key][0] === true) {
newHash.push('0');
}
if (hash[key][1] === true) {
newHash.push('1');
}
hash[key] = newHash;
},
normalizeHasMany: function(type, hash, relationship) {
var key = relationship.key;
if (typeof hash[key] === 'object' && !Ember.isArray(hash[key])) {
hash[key] = Ember.keys(hash[key]);
}
//We need to account for Firebase turning key/value pairs with ids '1' and '0' into arrays
//See https://github.com/firebase/emberfire/issues/124
else if (Ember.isArray(hash[key]) && hash[key].length < 3 && (hash[key][0] === true || hash[key][1] === true)) {
this._normalizeNumberIDs(hash, key);
}
else if (Ember.isArray(hash[key])) {
throw new Error(fmt('%@ relationship %@(\'%@\') must be a key/value map in Firebase. Example: { "%@": { "%@_id": true } }', [type.toString(), relationship.kind, relationship.type.typeKey, key, relationship.type.typeKey]));
}
},
normalizeEmbeddedHasMany: function(type, hash, relationship) {
var key = relationship.key;
var embeddedRecordPayload = hash[key];
var embeddedKey;
if (!hash[key]) {
return;
}
for (embeddedKey in embeddedRecordPayload) {
var record = embeddedRecordPayload[embeddedKey];
if (record !== null && typeof record === 'object') {
record.id = embeddedKey;
}
this.store.push(relationship.type, this.normalize(relationship.type, record));
}
hash[key] = Ember.keys(hash[key]);
},
normalizeEmbeddedBelongsTo: function(type, hash, relationship) {
var key = relationship.key;
if (!hash[key]) {
return;
}
var embeddedRecordPayload = hash[key];
if (typeof embeddedRecordPayload.id !== 'string') {
throw new Error(fmt('Embedded relationship "%@" of "%@" must contain an "id" property in the payload', [relationship.type.typeKey, type]));
}
this.store.push(relationship.type, this.normalize(relationship.type, embeddedRecordPayload));
hash[key] = embeddedRecordPayload.id;
},
normalizeBelongsTo: Ember.K,
/**

@@ -49,10 +151,16 @@ Called after `extractSingle()`. This method checks the model

normalize: function(type, hash) {
var serializer = this;
// Check if the model contains any 'hasMany' relationships
type.eachRelationship(function(key, relationship) {
if (relationship.kind === 'hasMany') {
if (typeof hash[key] === 'object' && !Ember.isArray(hash[key]) && relationship.options.embedded !== true) {
hash[key] = Ember.keys(hash[key]);
if (relationship.options.embedded) {
serializer.normalizeEmbeddedHasMany(type, hash, relationship);
} else {
serializer.normalizeHasMany(type, hash, relationship);
}
else if (Ember.isArray(hash[key])) {
throw new Error(fmt('%@ relationship %@(\'%@\') must be a key/value map in Firebase. Example: { "%@": { "%@_id": true } }', [type.toString(), relationship.kind, relationship.type.typeKey, relationship.key, relationship.type.typeKey]));
} else {
if (relationship.options.embedded) {
serializer.normalizeEmbeddedBelongsTo(type, hash, relationship);
} else {
serializer.normalizeBelongsTo(type, hash, relationship);
}

@@ -73,33 +181,3 @@ }

extractSingle: function(store, type, payload) {
var adapter = store.adapterFor(type);
var normalizedPayload = this.normalize(type, payload);
// Check for embedded records
type.eachRelationship(function(key, relationship) {
if (!Ember.isNone(payload) && !Ember.isNone(payload[key]) && relationship.options.embedded === true) {
var embeddedKey;
var embeddedRecordPayload = normalizedPayload[key];
var records = [];
var record;
if (relationship.kind === 'belongsTo') {
if (typeof embeddedRecordPayload.id !== 'string') {
throw new Error(fmt('Embedded relationship "%@" of "%@" must contain an "id" property in the payload', [relationship.type.typeKey, type]));
}
records.push(embeddedRecordPayload);
normalizedPayload[key] = embeddedRecordPayload.id;
}
else {
for (embeddedKey in embeddedRecordPayload) {
record = embeddedRecordPayload[embeddedKey];
if (record !== null && typeof record === 'object') {
record.id = embeddedKey;
}
records.push(record);
}
normalizedPayload[key] = Ember.keys(normalizedPayload[key]);
}
// Push the embedded records into the store
store.pushMany(relationship.type, records);
}
});
return normalizedPayload;
return this.normalize(type, payload);
},

@@ -125,7 +203,11 @@

var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key;
var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
var relationshipTypes = ['manyToNone', 'manyToMany', 'manyToOne'];
json[payloadKey] = Ember.A(record.get(key)).mapBy('id');
},
if (relationshipTypes.indexOf(relationshipType) > -1) {
json[payloadKey] = Ember.A(record.get(key)).mapBy('id');
serializeBelongsTo: function(record, json, relationship) {
this._super(record, json, relationship);
var key = relationship.key;
var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : relationship.key;
if (typeof json[key] === "undefined" || json[key] === '') {
delete json[key];
}

@@ -213,3 +295,2 @@ }

var adapter = this;
var resolved = false;
var ref = this._getRef(type, id);

@@ -219,45 +300,16 @@ var serializer = store.serializerFor(type);

return new Promise(function(resolve, reject) {
ref.on('value', function(snapshot) {
ref.once('value', function(snapshot) {
var payload = adapter._assignIdToPayload(snapshot);
var record = store.getById(type, snapshot.name());
adapter._updateRecordCacheForType(type, payload);
if (!resolved) {
resolved = true;
// If this is the first event, resolve the promise.
if (payload === null) {
if (store.hasRecordForId(type, id)) {
adapter._enqueue(function() {
store.dematerializeRecord(record);
});
}
var error = new Error(fmt('no record was found at %@', [ref.toString()]));
error.recordId = id;
adapter._enqueue(reject, [error]);
}
else {
adapter._enqueue(resolve, [payload]);
}
if (payload === null) {
var error = new Error(fmt('no record was found at %@', [ref.toString()]));
error.recordId = id;
reject(error);
}
else {
// If the snapshot is null, delete the record from the store
if (payload === null && record && !record.get('isDeleted')) {
adapter._enqueue(function() {
store.getById(type, snapshot.name()).deleteRecord();
});
}
// Otherwise push it into the store
else if (payload !== null) {
adapter._enqueue(function() {
store.push(type, serializer.extractSingle(store, type, payload));
});
}
resolve(payload);
}
},
function(err) {
// Only called in cases of permission related errors.
if (!resolved) {
adapter._enqueue(reject, [err]);
}
reject(err);
});

@@ -267,22 +319,31 @@ }, fmt('DS: FirebaseAdapter#find %@ to %@', [type, ref.toString()]));

recordWasPushed: function(store, type, record) {
if (!record.__listening) {
this.listenForChanges(store, type, record);
}
},
recordWillUnload: function(store, record) {
var ref = this._getRef(record.typeKey, record.get('id'));
ref.off('value');
},
listenForChanges: function(store, type, record) {
record.__listening = true;
var serializer = store.serializerFor(type);
var adapter = this;
var ref = this._getRef(type, record.get('id'));
var called = false;
ref.on('value', function(snapshot) {
if (called) {
adapter._handleChildValue(store, type, serializer, snapshot);
}
called = true;
});
},
/**
findMany
*/
findMany: function(store, type, ids) {
var promises = map(ids, function(id) {
return this.find(store, type, id);
}, this);
return Ember.RSVP.allSettled(promises).then(function(promises) {
// Remove any records that couldn't be fetched
promises = Ember.A(promises);
forEach(promises.filterBy('state', 'rejected'), function(promise) {
var recordId = promise.reason.recordId;
if (store.hasRecordForId(type, recordId)) {
var record = store.getById(type, recordId);
store.dematerializeRecord(record);
}
});
return Ember.A(promises.filterBy('state', 'fulfilled')).mapBy('value');
});
},
findMany: undefined,

@@ -304,24 +365,15 @@ /**

// Listen for child events on the type
var valueEventTriggered;
if (!adapter._findAllHasEventsForType(type)) {
valueEventTriggered = adapter._findAllAddEventListeners(store, type, ref);
}
ref.once('value', function(snapshot) {
if (!adapter._findAllHasEventsForType(type)) {
adapter._findAllAddEventListeners(store, type, ref);
}
var results = [];
if (valueEventTriggered) {
Ember.run(null, valueEventTriggered.resolve);
}
if (snapshot.val() === null) {
adapter._enqueue(resolve, [results]);
}
else {
snapshot.forEach(function(childSnapshot) {
var payload = adapter._assignIdToPayload(childSnapshot);
adapter._updateRecordCacheForType(type, payload);
results.push(payload);
});
adapter._enqueue(resolve, [results]);
}
snapshot.forEach(function(childSnapshot) {
var payload = adapter._assignIdToPayload(childSnapshot);
adapter._updateRecordCacheForType(type, payload);
results.push(payload);
});
resolve(results);
}, function(error) {
adapter._enqueue(reject, [error]);
reject(error);
});

@@ -351,32 +403,10 @@ }, fmt('DS: FirebaseAdapter#findAll %@ to %@', [type, ref.toString()]));

var deferred = Ember.RSVP.defer();
var adapter = this;
var serializer = store.serializerFor(type);
var valueEventTriggered = false;
deferred.promise.then(function() {
valueEventTriggered = true;
});
ref.on('child_added', function(snapshot) {
if (!valueEventTriggered) { return; }
adapter._handleChildValue(store, type, serializer, snapshot);
});
ref.on('child_changed', function(snapshot) {
if (!valueEventTriggered) { return; }
adapter._handleChildValue(store, type, serializer, snapshot);
});
ref.on('child_removed', function(snapshot) {
if (!valueEventTriggered) { return; }
var record = store.getById(type, snapshot.name());
if (record && !record.get('isDeleted')) {
adapter._enqueue(function() {
store.deleteRecord(record);
});
if (!store.hasRecordForId(type, snapshot.name())) {
adapter._handleChildValue(store, type, serializer, snapshot);
}
});
return deferred;
},

@@ -388,6 +418,21 @@

_handleChildValue: function(store, type, serializer, snapshot) {
var payload = this._assignIdToPayload(snapshot);
this._enqueue(function() {
store.push(type, serializer.extractSingle(store, type, payload));
});
//No idea why we need this, we are alredy turning off the callback by
//calling ref.off in recordWillUnload. Something is fishy here
if (store.isDestroying) {
return;
}
var value = snapshot.val();
if (value === null) {
var id = snapshot.name();
var record = store.getById(type, id);
//TODO refactor using ED
if (!record.get('isDeleted')) {
record.deleteRecord();
}
} else {
var payload = this._assignIdToPayload(snapshot);
this._enqueue(function() {
store.push(type, serializer.extractSingle(store, type, payload));
});
}
},

@@ -400,3 +445,6 @@

createRecord: function(store, type, record) {
return this.updateRecord(store, type, record);
var adapter = this;
return this.updateRecord(store, type, record).then(function() {
adapter.listenForChanges(store, type, record);
});
},

@@ -412,76 +460,57 @@

any relationships have been successfully saved to Firebase.
We take an optional record reference, in order for this method to be usable
for saving nested records as well.
*/
updateRecord: function(store, type, record) {
updateRecord: function(store, type, record, _recordRef) {
var adapter = this;
var recordRef = this._getRef(type, record.id);
var recordRef = _recordRef || this._getRef(type, record.id);
var recordCache = Ember.get(adapter._recordCacheForType, fmt('%@.%@', [type.typeKey, record.get('id')])) || {};
return this._getSerializedRecord(record).then(function(serializedRecord) {
return new Promise(function(resolve, reject) {
var savedRelationships = Ember.A();
record.eachRelationship(function(key, relationship) {
var save ;
switch (relationship.kind) {
case 'hasMany':
if (Ember.isArray(serializedRecord[key])) {
save = adapter._saveHasManyRelationship(store, type, relationship, serializedRecord[key], recordRef, recordCache);
savedRelationships.push(save);
// Remove the relationship from the serializedRecord
delete serializedRecord[key];
}
break;
case 'belongsTo':
if (typeof serializedRecord[key] === "undefined" || serializedRecord[key] === null || serializedRecord[key] === '') {
delete serializedRecord[key];
}
else if (relationship.options.embedded === true) {
save = adapter._saveBelongsToRecord(store, type, relationship, serializedRecord[key], recordRef);
savedRelationships.push(save);
delete serializedRecord[key];
}
break;
default:
break;
}
});
// Save the record once all the relationships have saved
Ember.RSVP.allSettled(savedRelationships).then(function(savedRelationships) {
savedRelationships = Ember.A(savedRelationships);
var rejected = Ember.A(savedRelationships.filterBy('state', 'rejected'));
// Throw an error if any of the relationships failed to save
if (rejected.get('length') !== 0) {
var error = new Error(fmt('Some errors were encountered while saving %@ %@', [type, record.id]));
error.errors = rejected.mapBy('reason');
adapter._enqueue(reject, [error]);
}
recordRef.update(serializedRecord, function(error) {
if (error) {
adapter._enqueue(reject, [error]);
} else {
adapter._enqueue(resolve);
var serializedRecord = record.serialize({includeId:false});
return new Promise(function(resolve, reject) {
var savedRelationships = Ember.A();
record.eachRelationship(function(key, relationship) {
var save;
if (relationship.kind === 'hasMany') {
if (serializedRecord[key]) {
save = adapter._saveHasManyRelationship(store, type, relationship, serializedRecord[key], recordRef, recordCache);
savedRelationships.push(save);
// Remove the relationship from the serializedRecord because otherwise we would clobber the entire hasMany
delete serializedRecord[key];
}
});
});
} else {
if (relationship.options.embedded === true && serializedRecord[key]) {
save = adapter._saveBelongsToRecord(store, type, relationship, serializedRecord[key], recordRef);
savedRelationships.push(save);
delete serializedRecord[key];
}
}
});
var relationshipsPromise = Ember.RSVP.allSettled(savedRelationships);
var recordPromise = adapter._updateRecord(recordRef, serializedRecord);
Ember.RSVP.hashSettled({relationships: relationshipsPromise, record: recordPromise}).then(function(promises) {
var rejected = Ember.A(promises.relationships.value).filterBy('state', 'rejected');
if (promises.record.state === 'rejected') {
rejected.push(promises.record);
}
// Throw an error if any of the relationships failed to save
if (rejected.length !== 0) {
var error = new Error(fmt('Some errors were encountered while saving %@ %@', [type, record.id]));
error.errors = rejected.mapBy('reason');
reject(error);
} else {
resolve();
}
});
}, fmt('DS: FirebaseAdapter#updateRecord %@ to %@', [type, recordRef.toString()]));
},
/**
Return a serialized version of the record
*/
_getSerializedRecord: function(record) {
var json = record.serialize({ includeId: false });
var relationships = [];
record.eachRelationship(function(key, relationship) {
switch (relationship.kind) {
case 'hasMany':
relationships.push(Promise.cast(record.get(key)).then(function(hasManyRecords) {
json[key] = Ember.A(hasManyRecords).mapBy('id');
}));
break;
}
});
return Ember.RSVP.all(relationships).then(function() {
return json;
});
//Just update the record itself without caring for the relationships
_updateRecord: function(recordRef, serializedRecord) {
return toPromise(recordRef.update, recordRef, [serializedRecord]);
},

@@ -499,3 +528,5 @@

var idsCache = Ember.A(recordCache[relationship.key]);
ids = Ember.A(ids);
ids = Ember.A(ids);
var dirtyRecords = [];
// Added

@@ -505,4 +536,5 @@ var addedRecords = ids.filter(function(id) {

});
// Dirty
var dirtyRecords = ids.filter(function(id) {
dirtyRecords = ids.filter(function(id) {
var type = relationship.type;

@@ -548,25 +580,10 @@ return store.hasRecordForId(type, id) && store.getById(type, id).get('isDirty') === true;

_saveHasManyRecord: function(store, relationship, parentRef, id) {
var adapter = this;
var ref = this._getRelationshipRef(parentRef, relationship.key, id);
var record = store.getById(relationship.type, id);
var isEmbedded = relationship.options.embedded === true;
var valueToSave = isEmbedded ? record.serialize({ includeId: false }) : true;
return new Promise(function(resolve, reject) {
var _saveHandler = function(error) {
if (error) {
if (typeof error === 'object') {
error.location = ref.toString();
}
adapter._enqueue(reject, [error]);
} else {
adapter._enqueue(resolve);
}
};
if (isEmbedded) {
ref.update(valueToSave, _saveHandler);
}
else {
ref.set(valueToSave, _saveHandler);
}
});
if (isEmbedded) {
return this.updateRecord(store, relationship.type, record, ref);
}
return toPromise(ref.set, ref, [true]);
},

@@ -578,17 +595,4 @@

_removeHasManyRecord: function(store, relationship, parentRef, id) {
var adapter = this;
var ref = this._getRelationshipRef(parentRef, relationship.key, id);
return new Promise(function(resolve, reject) {
var _removeHandler = function(error) {
if (error) {
if (typeof error === 'object') {
error.location = ref.toString();
}
adapter._enqueue(reject, [error]);
} else {
adapter._enqueue(resolve);
}
};
ref.remove(_removeHandler);
});
return toPromise(ref.remove, ref, [], ref.toString());
},

@@ -600,25 +604,5 @@

_saveBelongsToRecord: function(store, type, relationship, id, parentRef) {
var adapter = this;
var ref = parentRef.child(relationship.key);
var record = store.getById(relationship.type, id);
var isEmbedded = relationship.options.embedded === true;
var valueToSave = isEmbedded ? record.serialize({ includeId: true }) : true;
return new Promise(function(resolve, reject) {
var _saveHandler = function(error) {
if (error) {
if (typeof error === 'object') {
error.location = ref.toString();
}
adapter._enqueue(reject, [error]);
} else {
adapter._enqueue(resolve);
}
};
if (isEmbedded) {
ref.update(valueToSave, _saveHandler);
}
else {
ref.set(valueToSave, _saveHandler);
}
});
return this.updateRecord(store, relationship.type, record, ref);
},

@@ -630,13 +614,4 @@

deleteRecord: function(store, type, record) {
var adapter = this;
var ref = this._getRef(type, record.get('id'));
return new Promise(function(resolve, reject) {
ref.remove(function(err) {
if (err) {
adapter._enqueue(reject, [err]);
} else {
adapter._enqueue(resolve);
}
});
}, fmt('DS: FirebaseAdapter#deleteRecord %@ to %@', [type, ref.toString()]));
return toPromise(ref.remove, ref);
},

@@ -702,5 +677,10 @@

_enqueue: function(callback, args) {
var length = this._queue.push([callback, args]);
if (length === 1) {
this._queueScheduleFlush();
//Only do the queueing if we scheduled a delay
if (this._queueFlushDelay) {
var length = this._queue.push([callback, args]);
if (length === 1) {
this._queueScheduleFlush();
}
} else {
callback.apply(null, args);
}

@@ -707,0 +687,0 @@ },

@@ -6,6 +6,6 @@ /*!

*
* EmberFire 1.2.5
* EmberFire 1.2.6
* https://github.com/firebase/emberfire/
* License: MIT
*/
!function(){"use strict";if(void 0!==window.DS){var a=Ember.Namespace.create({VERSION:"1.2.5"});Ember.libraries&&Ember.libraries.registerCoreLibrary("EmberFire",a.VERSION);var b=Ember.RSVP.Promise,c=Ember.EnumerableUtils.map,d=Ember.EnumerableUtils.forEach,e=Ember.String.fmt;DS.FirebaseSerializer=DS.JSONSerializer.extend(Ember.Evented,{normalize:function(a,b){return a.eachRelationship(function(c,d){if("hasMany"===d.kind)if("object"!=typeof b[c]||Ember.isArray(b[c])||d.options.embedded===!0){if(Ember.isArray(b[c]))throw new Error(e('%@ relationship %@(\'%@\') must be a key/value map in Firebase. Example: { "%@": { "%@_id": true } }',[a.toString(),d.kind,d.type.typeKey,d.key,d.type.typeKey]))}else b[c]=Ember.keys(b[c])}),this._super.apply(this,arguments)},extractSingle:function(a,b,c){var d=(a.adapterFor(b),this.normalize(b,c));return b.eachRelationship(function(f,g){if(!Ember.isNone(c)&&!Ember.isNone(c[f])&&g.options.embedded===!0){var h,i,j=d[f],k=[];if("belongsTo"===g.kind){if("string"!=typeof j.id)throw new Error(e('Embedded relationship "%@" of "%@" must contain an "id" property in the payload',[g.type.typeKey,b]));k.push(j),d[f]=j.id}else{for(h in j)i=j[h],null!==i&&"object"==typeof i&&(i.id=h),k.push(i);d[f]=Ember.keys(d[f])}a.pushMany(g.type,k)}}),d},extractArray:function(a,b,d){return c(d,function(c){return this.extractSingle(a,b,c)},this)},serializeHasMany:function(a,b,c){var d=c.key,e=this.keyForRelationship?this.keyForRelationship(d,"hasMany"):d,f=DS.RelationshipChange.determineRelationshipType(a.constructor,c),g=["manyToNone","manyToMany","manyToOne"];g.indexOf(f)>-1&&(b[e]=Ember.A(a.get(d)).mapBy("id"))}}),DS.FirebaseAdapter=DS.Adapter.extend(Ember.Evented,{defaultSerializer:"-firebase",init:function(){if(!this.firebase||"object"!=typeof this.firebase)throw new Error("Please set the `firebase` property on the adapter.");this._ref=this.firebase.ref(),this._findAllMapForType={},this._recordCacheForType={},this._queue=[]},generateIdForRecord:function(){return this._ref.push().name()},_assignIdToPayload:function(a){var b=a.val();return null!==b&&"object"==typeof b&&"undefined"==typeof b.id&&(b.id=a.name()),b},find:function(a,c,d){var f=this,g=!1,h=this._getRef(c,d),i=a.serializerFor(c);return new b(function(b,j){h.on("value",function(k){var l=f._assignIdToPayload(k),m=a.getById(c,k.name());if(f._updateRecordCacheForType(c,l),g)null===l&&m&&!m.get("isDeleted")?f._enqueue(function(){a.getById(c,k.name()).deleteRecord()}):null!==l&&f._enqueue(function(){a.push(c,i.extractSingle(a,c,l))});else if(g=!0,null===l){a.hasRecordForId(c,d)&&f._enqueue(function(){a.dematerializeRecord(m)});var n=new Error(e("no record was found at %@",[h.toString()]));n.recordId=d,f._enqueue(j,[n])}else f._enqueue(b,[l])},function(a){g||f._enqueue(j,[a])})},e("DS: FirebaseAdapter#find %@ to %@",[c,h.toString()]))},findMany:function(a,b,e){var f=c(e,function(c){return this.find(a,b,c)},this);return Ember.RSVP.allSettled(f).then(function(c){return c=Ember.A(c),d(c.filterBy("state","rejected"),function(c){var d=c.reason.recordId;if(a.hasRecordForId(b,d)){var e=a.getById(b,d);a.dematerializeRecord(e)}}),Ember.A(c.filterBy("state","fulfilled")).mapBy("value")})},findAll:function(a,c){var d=this,f=this._getRef(c);return new b(function(b,e){var g;d._findAllHasEventsForType(c)||(g=d._findAllAddEventListeners(a,c,f)),f.once("value",function(a){var e=[];g&&Ember.run(null,g.resolve),null===a.val()?d._enqueue(b,[e]):(a.forEach(function(a){var b=d._assignIdToPayload(a);d._updateRecordCacheForType(c,b),e.push(b)}),d._enqueue(b,[e]))},function(a){d._enqueue(e,[a])})},e("DS: FirebaseAdapter#findAll %@ to %@",[c,f.toString()]))},_findAllMapForType:void 0,_findAllHasEventsForType:function(a){return!Ember.isNone(this._findAllMapForType[a])},_findAllAddEventListeners:function(a,b,c){this._findAllMapForType[b]=!0;var d=Ember.RSVP.defer(),e=this,f=a.serializerFor(b),g=!1;return d.promise.then(function(){g=!0}),c.on("child_added",function(c){g&&e._handleChildValue(a,b,f,c)}),c.on("child_changed",function(c){g&&e._handleChildValue(a,b,f,c)}),c.on("child_removed",function(c){if(g){var d=a.getById(b,c.name());d&&!d.get("isDeleted")&&e._enqueue(function(){a.deleteRecord(d)})}}),d},_handleChildValue:function(a,b,c,d){var e=this._assignIdToPayload(d);this._enqueue(function(){a.push(b,c.extractSingle(a,b,e))})},createRecord:function(a,b,c){return this.updateRecord(a,b,c)},updateRecord:function(a,c,d){var f=this,g=this._getRef(c,d.id),h=Ember.get(f._recordCacheForType,e("%@.%@",[c.typeKey,d.get("id")]))||{};return this._getSerializedRecord(d).then(function(i){return new b(function(b,j){var k=Ember.A();d.eachRelationship(function(b,d){var e;switch(d.kind){case"hasMany":Ember.isArray(i[b])&&(e=f._saveHasManyRelationship(a,c,d,i[b],g,h),k.push(e),delete i[b]);break;case"belongsTo":"undefined"==typeof i[b]||null===i[b]||""===i[b]?delete i[b]:d.options.embedded===!0&&(e=f._saveBelongsToRecord(a,c,d,i[b],g),k.push(e),delete i[b])}}),Ember.RSVP.allSettled(k).then(function(a){a=Ember.A(a);var h=Ember.A(a.filterBy("state","rejected"));if(0!==h.get("length")){var k=new Error(e("Some errors were encountered while saving %@ %@",[c,d.id]));k.errors=h.mapBy("reason"),f._enqueue(j,[k])}g.update(i,function(a){a?f._enqueue(j,[a]):f._enqueue(b)})})})},e("DS: FirebaseAdapter#updateRecord %@ to %@",[c,g.toString()]))},_getSerializedRecord:function(a){var c=a.serialize({includeId:!1}),d=[];return a.eachRelationship(function(e,f){switch(f.kind){case"hasMany":d.push(b.cast(a.get(e)).then(function(a){c[e]=Ember.A(a).mapBy("id")}))}}),Ember.RSVP.all(d).then(function(){return c})},_saveHasManyRelationship:function(a,b,c,d,f,g){if(!Ember.isArray(d))throw new Error("hasMany relationships must must be an array");var h=this,i=Ember.A(g[c.key]);d=Ember.A(d);var j=d.filter(function(a){return!i.contains(a)}),k=d.filter(function(b){var d=c.type;return a.hasRecordForId(d,b)&&a.getById(d,b).get("isDirty")===!0});k=Ember.A(k.concat(j)).uniq().map(function(b){return h._saveHasManyRecord(a,c,f,b)});var l=i.filter(function(a){return!d.contains(a)});l=Ember.A(l).map(function(b){return h._removeHasManyRecord(a,c,f,b)});var m=k.concat(l);return Ember.RSVP.allSettled(m).then(function(a){var b=Ember.A(Ember.A(a).filterBy("state","rejected"));if(0===b.get("length"))return g[c.key]=d,a;var f=new Error(e("Some errors were encountered while saving a hasMany relationship %@ -> %@",[c.parentType,c.type]));throw f.errors=Ember.A(b).mapBy("reason"),f})},_saveHasManyRecord:function(a,c,d,e){var f=this,g=this._getRelationshipRef(d,c.key,e),h=a.getById(c.type,e),i=c.options.embedded===!0,j=i?h.serialize({includeId:!1}):!0;return new b(function(a,b){var c=function(c){c?("object"==typeof c&&(c.location=g.toString()),f._enqueue(b,[c])):f._enqueue(a)};i?g.update(j,c):g.set(j,c)})},_removeHasManyRecord:function(a,c,d,e){var f=this,g=this._getRelationshipRef(d,c.key,e);return new b(function(a,b){var c=function(c){c?("object"==typeof c&&(c.location=g.toString()),f._enqueue(b,[c])):f._enqueue(a)};g.remove(c)})},_saveBelongsToRecord:function(a,c,d,e,f){var g=this,h=f.child(d.key),i=a.getById(d.type,e),j=d.options.embedded===!0,k=j?i.serialize({includeId:!0}):!0;return new b(function(a,b){var c=function(c){c?("object"==typeof c&&(c.location=h.toString()),g._enqueue(b,[c])):g._enqueue(a)};j?h.update(k,c):h.set(k,c)})},deleteRecord:function(a,c,d){var f=this,g=this._getRef(c,d.get("id"));return new b(function(a,b){g.remove(function(c){c?f._enqueue(b,[c]):f._enqueue(a)})},e("DS: FirebaseAdapter#deleteRecord %@ to %@",[c,g.toString()]))},pathForType:function(a){var b=Ember.String.camelize(a);return Ember.String.pluralize(b)},_getRef:function(a,b){var c=this._ref;return a&&(c=c.child(this.pathForType(a.typeKey))),b&&(c=c.child(b)),c},_getRelationshipRef:function(a,b,c){return a.child(b).child(c)},_queueFlushDelay:1e3/60,_queueScheduleFlush:function(){Ember.run.later(this,this._queueFlush,this._queueFlushDelay)},_queueFlush:function(){d(this._queue,function(a){var b=a[0],c=a[1];b.apply(null,c)}),this._queue.length=0},_enqueue:function(a,b){var c=this._queue.push([a,b]);1===c&&this._queueScheduleFlush()},_recordCacheForType:void 0,_updateRecordCacheForType:function(a,b){if(b){var c=this,d=b.id,e=c._recordCacheForType,f=a.typeKey;a.eachRelationship(function(a,c){if("hasMany"===c.kind){var g=b[a];e[f]=e[f]||{},e[f][d]=e[f][d]||{},e[f][d][a]=Ember.isNone(g)?Ember.A():Ember.A(Ember.keys(g))}})}}}),Ember.onLoad("Ember.Application",function(a){a.initializer({name:"firebase",initialize:function(a,b){b.register("adapter:-firebase",DS.FirebaseAdapter),b.register("serializer:-firebase",DS.FirebaseSerializer)}})})}}();
!function(){"use strict";if(void 0!==window.DS){var a=Ember.Namespace.create({VERSION:"1.2.6"});Ember.libraries&&Ember.libraries.registerCoreLibrary("EmberFire",a.VERSION),DS.Store.reopen({push:function(a,b,c){var d=this._super(a,b,c),e=this.adapterFor(d.constructor);return e.recordWasPushed&&e.recordWasPushed(this,a,d),d},recordWillUnload:function(a){var b=this.adapterFor(a.constructor);b.recordWillUnload&&b.recordWillUnload(this,a)}}),DS.Model.reopen({unloadRecord:function(){return this.store.recordWillUnload(this),this._super()}});var b=Ember.RSVP.Promise,c=Ember.EnumerableUtils.map,d=Ember.EnumerableUtils.forEach,e=Ember.String.fmt,f=function(a,c,d,e){var f=d||[];return new b(function(b,d){var g=function(a){a?(e&&"object"==typeof a&&(a.location=e),d(a)):b()};f.push(g),a.apply(c,f)})};DS.FirebaseSerializer=DS.JSONSerializer.extend(Ember.Evented,{_normalizeNumberIDs:function(a,b){var c=[];a[b][0]===!0&&c.push("0"),a[b][1]===!0&&c.push("1"),a[b]=c},normalizeHasMany:function(a,b,c){var d=c.key;if("object"!=typeof b[d]||Ember.isArray(b[d])){if(Ember.isArray(b[d])&&b[d].length<3&&(b[d][0]===!0||b[d][1]===!0))this._normalizeNumberIDs(b,d);else if(Ember.isArray(b[d]))throw new Error(e('%@ relationship %@(\'%@\') must be a key/value map in Firebase. Example: { "%@": { "%@_id": true } }',[a.toString(),c.kind,c.type.typeKey,d,c.type.typeKey]))}else b[d]=Ember.keys(b[d])},normalizeEmbeddedHasMany:function(a,b,c){var d,e=c.key,f=b[e];if(b[e]){for(d in f){var g=f[d];null!==g&&"object"==typeof g&&(g.id=d),this.store.push(c.type,this.normalize(c.type,g))}b[e]=Ember.keys(b[e])}},normalizeEmbeddedBelongsTo:function(a,b,c){var d=c.key;if(b[d]){var f=b[d];if("string"!=typeof f.id)throw new Error(e('Embedded relationship "%@" of "%@" must contain an "id" property in the payload',[c.type.typeKey,a]));this.store.push(c.type,this.normalize(c.type,f)),b[d]=f.id}},normalizeBelongsTo:Ember.K,normalize:function(a,b){var c=this;return a.eachRelationship(function(d,e){"hasMany"===e.kind?e.options.embedded?c.normalizeEmbeddedHasMany(a,b,e):c.normalizeHasMany(a,b,e):e.options.embedded?c.normalizeEmbeddedBelongsTo(a,b,e):c.normalizeBelongsTo(a,b,e)}),this._super.apply(this,arguments)},extractSingle:function(a,b,c){return this.normalize(b,c)},extractArray:function(a,b,d){return c(d,function(c){return this.extractSingle(a,b,c)},this)},serializeHasMany:function(a,b,c){var d=c.key,e=this.keyForRelationship?this.keyForRelationship(d,"hasMany"):d;b[e]=Ember.A(a.get(d)).mapBy("id")},serializeBelongsTo:function(a,b,c){this._super(a,b,c);{var d=c.key;this.keyForRelationship?this.keyForRelationship(d,"belongsTo"):c.key}("undefined"==typeof b[d]||""===b[d])&&delete b[d]}}),DS.FirebaseAdapter=DS.Adapter.extend(Ember.Evented,{defaultSerializer:"-firebase",init:function(){if(!this.firebase||"object"!=typeof this.firebase)throw new Error("Please set the `firebase` property on the adapter.");this._ref=this.firebase.ref(),this._findAllMapForType={},this._recordCacheForType={},this._queue=[]},generateIdForRecord:function(){return this._ref.push().name()},_assignIdToPayload:function(a){var b=a.val();return null!==b&&"object"==typeof b&&"undefined"==typeof b.id&&(b.id=a.name()),b},find:function(a,c,d){{var f=this,g=this._getRef(c,d);a.serializerFor(c)}return new b(function(a,b){g.once("value",function(h){var i=f._assignIdToPayload(h);if(f._updateRecordCacheForType(c,i),null===i){var j=new Error(e("no record was found at %@",[g.toString()]));j.recordId=d,b(j)}else a(i)},function(a){b(a)})},e("DS: FirebaseAdapter#find %@ to %@",[c,g.toString()]))},recordWasPushed:function(a,b,c){c.__listening||this.listenForChanges(a,b,c)},recordWillUnload:function(a,b){var c=this._getRef(b.typeKey,b.get("id"));c.off("value")},listenForChanges:function(a,b,c){c.__listening=!0;var d=a.serializerFor(b),e=this,f=this._getRef(b,c.get("id")),g=!1;f.on("value",function(c){g&&e._handleChildValue(a,b,d,c),g=!0})},findMany:void 0,findAll:function(a,c){var d=this,f=this._getRef(c);return new b(function(b,e){f.once("value",function(e){d._findAllHasEventsForType(c)||d._findAllAddEventListeners(a,c,f);var g=[];e.forEach(function(a){var b=d._assignIdToPayload(a);d._updateRecordCacheForType(c,b),g.push(b)}),b(g)},function(a){e(a)})},e("DS: FirebaseAdapter#findAll %@ to %@",[c,f.toString()]))},_findAllMapForType:void 0,_findAllHasEventsForType:function(a){return!Ember.isNone(this._findAllMapForType[a])},_findAllAddEventListeners:function(a,b,c){this._findAllMapForType[b]=!0;var d=this,e=a.serializerFor(b);c.on("child_added",function(c){a.hasRecordForId(b,c.name())||d._handleChildValue(a,b,e,c)})},_handleChildValue:function(a,b,c,d){if(!a.isDestroying){var e=d.val();if(null===e){var f=d.name(),g=a.getById(b,f);g.get("isDeleted")||g.deleteRecord()}else{var h=this._assignIdToPayload(d);this._enqueue(function(){a.push(b,c.extractSingle(a,b,h))})}}},createRecord:function(a,b,c){var d=this;return this.updateRecord(a,b,c).then(function(){d.listenForChanges(a,b,c)})},updateRecord:function(a,c,d,f){var g=this,h=f||this._getRef(c,d.id),i=Ember.get(g._recordCacheForType,e("%@.%@",[c.typeKey,d.get("id")]))||{},j=d.serialize({includeId:!1});return new b(function(b,f){var k=Ember.A();d.eachRelationship(function(b,d){var e;"hasMany"===d.kind?j[b]&&(e=g._saveHasManyRelationship(a,c,d,j[b],h,i),k.push(e),delete j[b]):d.options.embedded===!0&&j[b]&&(e=g._saveBelongsToRecord(a,c,d,j[b],h),k.push(e),delete j[b])});var l=Ember.RSVP.allSettled(k),m=g._updateRecord(h,j);Ember.RSVP.hashSettled({relationships:l,record:m}).then(function(a){var g=Ember.A(a.relationships.value).filterBy("state","rejected");if("rejected"===a.record.state&&g.push(a.record),0!==g.length){var h=new Error(e("Some errors were encountered while saving %@ %@",[c,d.id]));h.errors=g.mapBy("reason"),f(h)}else b()})},e("DS: FirebaseAdapter#updateRecord %@ to %@",[c,h.toString()]))},_updateRecord:function(a,b){return f(a.update,a,[b])},_saveHasManyRelationship:function(a,b,c,d,f,g){if(!Ember.isArray(d))throw new Error("hasMany relationships must must be an array");var h=this,i=Ember.A(g[c.key]);d=Ember.A(d);var j=[],k=d.filter(function(a){return!i.contains(a)});j=d.filter(function(b){var d=c.type;return a.hasRecordForId(d,b)&&a.getById(d,b).get("isDirty")===!0}),j=Ember.A(j.concat(k)).uniq().map(function(b){return h._saveHasManyRecord(a,c,f,b)});var l=i.filter(function(a){return!d.contains(a)});l=Ember.A(l).map(function(b){return h._removeHasManyRecord(a,c,f,b)});var m=j.concat(l);return Ember.RSVP.allSettled(m).then(function(a){var b=Ember.A(Ember.A(a).filterBy("state","rejected"));if(0===b.get("length"))return g[c.key]=d,a;var f=new Error(e("Some errors were encountered while saving a hasMany relationship %@ -> %@",[c.parentType,c.type]));throw f.errors=Ember.A(b).mapBy("reason"),f})},_saveHasManyRecord:function(a,b,c,d){var e=this._getRelationshipRef(c,b.key,d),g=a.getById(b.type,d),h=b.options.embedded===!0;return h?this.updateRecord(a,b.type,g,e):f(e.set,e,[!0])},_removeHasManyRecord:function(a,b,c,d){var e=this._getRelationshipRef(c,b.key,d);return f(e.remove,e,[],e.toString())},_saveBelongsToRecord:function(a,b,c,d,e){var f=e.child(c.key),g=a.getById(c.type,d);return this.updateRecord(a,c.type,g,f)},deleteRecord:function(a,b,c){var d=this._getRef(b,c.get("id"));return f(d.remove,d)},pathForType:function(a){var b=Ember.String.camelize(a);return Ember.String.pluralize(b)},_getRef:function(a,b){var c=this._ref;return a&&(c=c.child(this.pathForType(a.typeKey))),b&&(c=c.child(b)),c},_getRelationshipRef:function(a,b,c){return a.child(b).child(c)},_queueFlushDelay:1e3/60,_queueScheduleFlush:function(){Ember.run.later(this,this._queueFlush,this._queueFlushDelay)},_queueFlush:function(){d(this._queue,function(a){var b=a[0],c=a[1];b.apply(null,c)}),this._queue.length=0},_enqueue:function(a,b){if(this._queueFlushDelay){var c=this._queue.push([a,b]);1===c&&this._queueScheduleFlush()}else a.apply(null,b)},_recordCacheForType:void 0,_updateRecordCacheForType:function(a,b){if(b){var c=this,d=b.id,e=c._recordCacheForType,f=a.typeKey;a.eachRelationship(function(a,c){if("hasMany"===c.kind){var g=b[a];e[f]=e[f]||{},e[f][d]=e[f][d]||{},e[f][d][a]=Ember.isNone(g)?Ember.A():Ember.A(Ember.keys(g))}})}}}),Ember.onLoad("Ember.Application",function(a){a.initializer({name:"firebase",initialize:function(a,b){b.register("adapter:-firebase",DS.FirebaseAdapter),b.register("serializer:-firebase",DS.FirebaseSerializer)}})})}}();

@@ -11,4 +11,4 @@ 'use strict';

afterInstall: function() {
return this.addBowerPackageToProject('emberfire', '~1.2.5');
return this.addBowerPackageToProject('emberfire', '~1.2.6');
}
};
{
"name": "emberfire",
"description": "The officially supported Ember binding for Firebase",
"version": "1.2.5",
"version": "1.2.6",
"author": "Firebase <support@firebase.com> (https://www.firebase.com/)",

@@ -6,0 +6,0 @@ "homepage": "https://github.com/firebase/emberfire/",

@@ -35,3 +35,3 @@ # EmberFire (Firebase + Ember Data)

<!-- EmberFire -->
<script src="https://cdn.firebase.com/libs/emberfire/1.2.5/emberfire.min.js"></script>
<script src="https://cdn.firebase.com/libs/emberfire/1.2.6/emberfire.min.js"></script>
```

@@ -38,0 +38,0 @@

@@ -26,2 +26,26 @@ /*!

//Monkeypatch the store until ED gives us a good way to listen to push events
DS.Store.reopen({
push: function(typeName, data, _partial) {
var record = this._super(typeName, data, _partial);
var adapter = this.adapterFor(record.constructor);
if (adapter.recordWasPushed) {
adapter.recordWasPushed(this, typeName, record);
}
return record;
},
recordWillUnload: function(record) {
var adapter = this.adapterFor(record.constructor);
if (adapter.recordWillUnload) {
adapter.recordWillUnload(this, record);
}
}
});
DS.Model.reopen({
unloadRecord: function() {
this.store.recordWillUnload(this);
return this._super();
}
});
// Shortcuts

@@ -33,2 +57,21 @@ var Promise = Ember.RSVP.Promise;

var toPromise = function(fn, context, _args, errorMsg) {
var args = _args || [];
return new Promise(function(resolve, reject) {
var callback = function(error) {
if (error) {
if (errorMsg && typeof error === 'object') {
error.location = errorMsg;
}
reject(error);
} else {
resolve();
}
};
args.push(callback);
fn.apply(context, args);
});
};
/**

@@ -40,2 +83,61 @@ The Firebase serializer helps normalize relationships and can be extended on

//We need to account for Firebase turning key/value pairs with ids '1' and '0' into arrays
//See https://github.com/firebase/emberfire/issues/124
_normalizeNumberIDs: function(hash, key) {
var newHash = [];
if (hash[key][0] === true) {
newHash.push('0');
}
if (hash[key][1] === true) {
newHash.push('1');
}
hash[key] = newHash;
},
normalizeHasMany: function(type, hash, relationship) {
var key = relationship.key;
if (typeof hash[key] === 'object' && !Ember.isArray(hash[key])) {
hash[key] = Ember.keys(hash[key]);
}
//We need to account for Firebase turning key/value pairs with ids '1' and '0' into arrays
//See https://github.com/firebase/emberfire/issues/124
else if (Ember.isArray(hash[key]) && hash[key].length < 3 && (hash[key][0] === true || hash[key][1] === true)) {
this._normalizeNumberIDs(hash, key);
}
else if (Ember.isArray(hash[key])) {
throw new Error(fmt('%@ relationship %@(\'%@\') must be a key/value map in Firebase. Example: { "%@": { "%@_id": true } }', [type.toString(), relationship.kind, relationship.type.typeKey, key, relationship.type.typeKey]));
}
},
normalizeEmbeddedHasMany: function(type, hash, relationship) {
var key = relationship.key;
var embeddedRecordPayload = hash[key];
var embeddedKey;
if (!hash[key]) {
return;
}
for (embeddedKey in embeddedRecordPayload) {
var record = embeddedRecordPayload[embeddedKey];
if (record !== null && typeof record === 'object') {
record.id = embeddedKey;
}
this.store.push(relationship.type, this.normalize(relationship.type, record));
}
hash[key] = Ember.keys(hash[key]);
},
normalizeEmbeddedBelongsTo: function(type, hash, relationship) {
var key = relationship.key;
if (!hash[key]) {
return;
}
var embeddedRecordPayload = hash[key];
if (typeof embeddedRecordPayload.id !== 'string') {
throw new Error(fmt('Embedded relationship "%@" of "%@" must contain an "id" property in the payload', [relationship.type.typeKey, type]));
}
this.store.push(relationship.type, this.normalize(relationship.type, embeddedRecordPayload));
hash[key] = embeddedRecordPayload.id;
},
normalizeBelongsTo: Ember.K,
/**

@@ -47,10 +149,16 @@ Called after `extractSingle()`. This method checks the model

normalize: function(type, hash) {
var serializer = this;
// Check if the model contains any 'hasMany' relationships
type.eachRelationship(function(key, relationship) {
if (relationship.kind === 'hasMany') {
if (typeof hash[key] === 'object' && !Ember.isArray(hash[key]) && relationship.options.embedded !== true) {
hash[key] = Ember.keys(hash[key]);
if (relationship.options.embedded) {
serializer.normalizeEmbeddedHasMany(type, hash, relationship);
} else {
serializer.normalizeHasMany(type, hash, relationship);
}
else if (Ember.isArray(hash[key])) {
throw new Error(fmt('%@ relationship %@(\'%@\') must be a key/value map in Firebase. Example: { "%@": { "%@_id": true } }', [type.toString(), relationship.kind, relationship.type.typeKey, relationship.key, relationship.type.typeKey]));
} else {
if (relationship.options.embedded) {
serializer.normalizeEmbeddedBelongsTo(type, hash, relationship);
} else {
serializer.normalizeBelongsTo(type, hash, relationship);
}

@@ -71,33 +179,3 @@ }

extractSingle: function(store, type, payload) {
var adapter = store.adapterFor(type);
var normalizedPayload = this.normalize(type, payload);
// Check for embedded records
type.eachRelationship(function(key, relationship) {
if (!Ember.isNone(payload) && !Ember.isNone(payload[key]) && relationship.options.embedded === true) {
var embeddedKey;
var embeddedRecordPayload = normalizedPayload[key];
var records = [];
var record;
if (relationship.kind === 'belongsTo') {
if (typeof embeddedRecordPayload.id !== 'string') {
throw new Error(fmt('Embedded relationship "%@" of "%@" must contain an "id" property in the payload', [relationship.type.typeKey, type]));
}
records.push(embeddedRecordPayload);
normalizedPayload[key] = embeddedRecordPayload.id;
}
else {
for (embeddedKey in embeddedRecordPayload) {
record = embeddedRecordPayload[embeddedKey];
if (record !== null && typeof record === 'object') {
record.id = embeddedKey;
}
records.push(record);
}
normalizedPayload[key] = Ember.keys(normalizedPayload[key]);
}
// Push the embedded records into the store
store.pushMany(relationship.type, records);
}
});
return normalizedPayload;
return this.normalize(type, payload);
},

@@ -123,7 +201,11 @@

var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key;
var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
var relationshipTypes = ['manyToNone', 'manyToMany', 'manyToOne'];
json[payloadKey] = Ember.A(record.get(key)).mapBy('id');
},
if (relationshipTypes.indexOf(relationshipType) > -1) {
json[payloadKey] = Ember.A(record.get(key)).mapBy('id');
serializeBelongsTo: function(record, json, relationship) {
this._super(record, json, relationship);
var key = relationship.key;
var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : relationship.key;
if (typeof json[key] === "undefined" || json[key] === '') {
delete json[key];
}

@@ -211,3 +293,2 @@ }

var adapter = this;
var resolved = false;
var ref = this._getRef(type, id);

@@ -217,45 +298,16 @@ var serializer = store.serializerFor(type);

return new Promise(function(resolve, reject) {
ref.on('value', function(snapshot) {
ref.once('value', function(snapshot) {
var payload = adapter._assignIdToPayload(snapshot);
var record = store.getById(type, snapshot.name());
adapter._updateRecordCacheForType(type, payload);
if (!resolved) {
resolved = true;
// If this is the first event, resolve the promise.
if (payload === null) {
if (store.hasRecordForId(type, id)) {
adapter._enqueue(function() {
store.dematerializeRecord(record);
});
}
var error = new Error(fmt('no record was found at %@', [ref.toString()]));
error.recordId = id;
adapter._enqueue(reject, [error]);
}
else {
adapter._enqueue(resolve, [payload]);
}
if (payload === null) {
var error = new Error(fmt('no record was found at %@', [ref.toString()]));
error.recordId = id;
reject(error);
}
else {
// If the snapshot is null, delete the record from the store
if (payload === null && record && !record.get('isDeleted')) {
adapter._enqueue(function() {
store.getById(type, snapshot.name()).deleteRecord();
});
}
// Otherwise push it into the store
else if (payload !== null) {
adapter._enqueue(function() {
store.push(type, serializer.extractSingle(store, type, payload));
});
}
resolve(payload);
}
},
function(err) {
// Only called in cases of permission related errors.
if (!resolved) {
adapter._enqueue(reject, [err]);
}
reject(err);
});

@@ -265,22 +317,31 @@ }, fmt('DS: FirebaseAdapter#find %@ to %@', [type, ref.toString()]));

recordWasPushed: function(store, type, record) {
if (!record.__listening) {
this.listenForChanges(store, type, record);
}
},
recordWillUnload: function(store, record) {
var ref = this._getRef(record.typeKey, record.get('id'));
ref.off('value');
},
listenForChanges: function(store, type, record) {
record.__listening = true;
var serializer = store.serializerFor(type);
var adapter = this;
var ref = this._getRef(type, record.get('id'));
var called = false;
ref.on('value', function(snapshot) {
if (called) {
adapter._handleChildValue(store, type, serializer, snapshot);
}
called = true;
});
},
/**
findMany
*/
findMany: function(store, type, ids) {
var promises = map(ids, function(id) {
return this.find(store, type, id);
}, this);
return Ember.RSVP.allSettled(promises).then(function(promises) {
// Remove any records that couldn't be fetched
promises = Ember.A(promises);
forEach(promises.filterBy('state', 'rejected'), function(promise) {
var recordId = promise.reason.recordId;
if (store.hasRecordForId(type, recordId)) {
var record = store.getById(type, recordId);
store.dematerializeRecord(record);
}
});
return Ember.A(promises.filterBy('state', 'fulfilled')).mapBy('value');
});
},
findMany: undefined,

@@ -302,24 +363,15 @@ /**

// Listen for child events on the type
var valueEventTriggered;
if (!adapter._findAllHasEventsForType(type)) {
valueEventTriggered = adapter._findAllAddEventListeners(store, type, ref);
}
ref.once('value', function(snapshot) {
if (!adapter._findAllHasEventsForType(type)) {
adapter._findAllAddEventListeners(store, type, ref);
}
var results = [];
if (valueEventTriggered) {
Ember.run(null, valueEventTriggered.resolve);
}
if (snapshot.val() === null) {
adapter._enqueue(resolve, [results]);
}
else {
snapshot.forEach(function(childSnapshot) {
var payload = adapter._assignIdToPayload(childSnapshot);
adapter._updateRecordCacheForType(type, payload);
results.push(payload);
});
adapter._enqueue(resolve, [results]);
}
snapshot.forEach(function(childSnapshot) {
var payload = adapter._assignIdToPayload(childSnapshot);
adapter._updateRecordCacheForType(type, payload);
results.push(payload);
});
resolve(results);
}, function(error) {
adapter._enqueue(reject, [error]);
reject(error);
});

@@ -349,32 +401,10 @@ }, fmt('DS: FirebaseAdapter#findAll %@ to %@', [type, ref.toString()]));

var deferred = Ember.RSVP.defer();
var adapter = this;
var serializer = store.serializerFor(type);
var valueEventTriggered = false;
deferred.promise.then(function() {
valueEventTriggered = true;
});
ref.on('child_added', function(snapshot) {
if (!valueEventTriggered) { return; }
adapter._handleChildValue(store, type, serializer, snapshot);
});
ref.on('child_changed', function(snapshot) {
if (!valueEventTriggered) { return; }
adapter._handleChildValue(store, type, serializer, snapshot);
});
ref.on('child_removed', function(snapshot) {
if (!valueEventTriggered) { return; }
var record = store.getById(type, snapshot.name());
if (record && !record.get('isDeleted')) {
adapter._enqueue(function() {
store.deleteRecord(record);
});
if (!store.hasRecordForId(type, snapshot.name())) {
adapter._handleChildValue(store, type, serializer, snapshot);
}
});
return deferred;
},

@@ -386,6 +416,21 @@

_handleChildValue: function(store, type, serializer, snapshot) {
var payload = this._assignIdToPayload(snapshot);
this._enqueue(function() {
store.push(type, serializer.extractSingle(store, type, payload));
});
//No idea why we need this, we are alredy turning off the callback by
//calling ref.off in recordWillUnload. Something is fishy here
if (store.isDestroying) {
return;
}
var value = snapshot.val();
if (value === null) {
var id = snapshot.name();
var record = store.getById(type, id);
//TODO refactor using ED
if (!record.get('isDeleted')) {
record.deleteRecord();
}
} else {
var payload = this._assignIdToPayload(snapshot);
this._enqueue(function() {
store.push(type, serializer.extractSingle(store, type, payload));
});
}
},

@@ -398,3 +443,6 @@

createRecord: function(store, type, record) {
return this.updateRecord(store, type, record);
var adapter = this;
return this.updateRecord(store, type, record).then(function() {
adapter.listenForChanges(store, type, record);
});
},

@@ -410,76 +458,57 @@

any relationships have been successfully saved to Firebase.
We take an optional record reference, in order for this method to be usable
for saving nested records as well.
*/
updateRecord: function(store, type, record) {
updateRecord: function(store, type, record, _recordRef) {
var adapter = this;
var recordRef = this._getRef(type, record.id);
var recordRef = _recordRef || this._getRef(type, record.id);
var recordCache = Ember.get(adapter._recordCacheForType, fmt('%@.%@', [type.typeKey, record.get('id')])) || {};
return this._getSerializedRecord(record).then(function(serializedRecord) {
return new Promise(function(resolve, reject) {
var savedRelationships = Ember.A();
record.eachRelationship(function(key, relationship) {
var save ;
switch (relationship.kind) {
case 'hasMany':
if (Ember.isArray(serializedRecord[key])) {
save = adapter._saveHasManyRelationship(store, type, relationship, serializedRecord[key], recordRef, recordCache);
savedRelationships.push(save);
// Remove the relationship from the serializedRecord
delete serializedRecord[key];
}
break;
case 'belongsTo':
if (typeof serializedRecord[key] === "undefined" || serializedRecord[key] === null || serializedRecord[key] === '') {
delete serializedRecord[key];
}
else if (relationship.options.embedded === true) {
save = adapter._saveBelongsToRecord(store, type, relationship, serializedRecord[key], recordRef);
savedRelationships.push(save);
delete serializedRecord[key];
}
break;
default:
break;
}
});
// Save the record once all the relationships have saved
Ember.RSVP.allSettled(savedRelationships).then(function(savedRelationships) {
savedRelationships = Ember.A(savedRelationships);
var rejected = Ember.A(savedRelationships.filterBy('state', 'rejected'));
// Throw an error if any of the relationships failed to save
if (rejected.get('length') !== 0) {
var error = new Error(fmt('Some errors were encountered while saving %@ %@', [type, record.id]));
error.errors = rejected.mapBy('reason');
adapter._enqueue(reject, [error]);
}
recordRef.update(serializedRecord, function(error) {
if (error) {
adapter._enqueue(reject, [error]);
} else {
adapter._enqueue(resolve);
var serializedRecord = record.serialize({includeId:false});
return new Promise(function(resolve, reject) {
var savedRelationships = Ember.A();
record.eachRelationship(function(key, relationship) {
var save;
if (relationship.kind === 'hasMany') {
if (serializedRecord[key]) {
save = adapter._saveHasManyRelationship(store, type, relationship, serializedRecord[key], recordRef, recordCache);
savedRelationships.push(save);
// Remove the relationship from the serializedRecord because otherwise we would clobber the entire hasMany
delete serializedRecord[key];
}
});
});
} else {
if (relationship.options.embedded === true && serializedRecord[key]) {
save = adapter._saveBelongsToRecord(store, type, relationship, serializedRecord[key], recordRef);
savedRelationships.push(save);
delete serializedRecord[key];
}
}
});
var relationshipsPromise = Ember.RSVP.allSettled(savedRelationships);
var recordPromise = adapter._updateRecord(recordRef, serializedRecord);
Ember.RSVP.hashSettled({relationships: relationshipsPromise, record: recordPromise}).then(function(promises) {
var rejected = Ember.A(promises.relationships.value).filterBy('state', 'rejected');
if (promises.record.state === 'rejected') {
rejected.push(promises.record);
}
// Throw an error if any of the relationships failed to save
if (rejected.length !== 0) {
var error = new Error(fmt('Some errors were encountered while saving %@ %@', [type, record.id]));
error.errors = rejected.mapBy('reason');
reject(error);
} else {
resolve();
}
});
}, fmt('DS: FirebaseAdapter#updateRecord %@ to %@', [type, recordRef.toString()]));
},
/**
Return a serialized version of the record
*/
_getSerializedRecord: function(record) {
var json = record.serialize({ includeId: false });
var relationships = [];
record.eachRelationship(function(key, relationship) {
switch (relationship.kind) {
case 'hasMany':
relationships.push(Promise.cast(record.get(key)).then(function(hasManyRecords) {
json[key] = Ember.A(hasManyRecords).mapBy('id');
}));
break;
}
});
return Ember.RSVP.all(relationships).then(function() {
return json;
});
//Just update the record itself without caring for the relationships
_updateRecord: function(recordRef, serializedRecord) {
return toPromise(recordRef.update, recordRef, [serializedRecord]);
},

@@ -497,3 +526,5 @@

var idsCache = Ember.A(recordCache[relationship.key]);
ids = Ember.A(ids);
ids = Ember.A(ids);
var dirtyRecords = [];
// Added

@@ -503,4 +534,5 @@ var addedRecords = ids.filter(function(id) {

});
// Dirty
var dirtyRecords = ids.filter(function(id) {
dirtyRecords = ids.filter(function(id) {
var type = relationship.type;

@@ -546,25 +578,10 @@ return store.hasRecordForId(type, id) && store.getById(type, id).get('isDirty') === true;

_saveHasManyRecord: function(store, relationship, parentRef, id) {
var adapter = this;
var ref = this._getRelationshipRef(parentRef, relationship.key, id);
var record = store.getById(relationship.type, id);
var isEmbedded = relationship.options.embedded === true;
var valueToSave = isEmbedded ? record.serialize({ includeId: false }) : true;
return new Promise(function(resolve, reject) {
var _saveHandler = function(error) {
if (error) {
if (typeof error === 'object') {
error.location = ref.toString();
}
adapter._enqueue(reject, [error]);
} else {
adapter._enqueue(resolve);
}
};
if (isEmbedded) {
ref.update(valueToSave, _saveHandler);
}
else {
ref.set(valueToSave, _saveHandler);
}
});
if (isEmbedded) {
return this.updateRecord(store, relationship.type, record, ref);
}
return toPromise(ref.set, ref, [true]);
},

@@ -576,17 +593,4 @@

_removeHasManyRecord: function(store, relationship, parentRef, id) {
var adapter = this;
var ref = this._getRelationshipRef(parentRef, relationship.key, id);
return new Promise(function(resolve, reject) {
var _removeHandler = function(error) {
if (error) {
if (typeof error === 'object') {
error.location = ref.toString();
}
adapter._enqueue(reject, [error]);
} else {
adapter._enqueue(resolve);
}
};
ref.remove(_removeHandler);
});
return toPromise(ref.remove, ref, [], ref.toString());
},

@@ -598,25 +602,5 @@

_saveBelongsToRecord: function(store, type, relationship, id, parentRef) {
var adapter = this;
var ref = parentRef.child(relationship.key);
var record = store.getById(relationship.type, id);
var isEmbedded = relationship.options.embedded === true;
var valueToSave = isEmbedded ? record.serialize({ includeId: true }) : true;
return new Promise(function(resolve, reject) {
var _saveHandler = function(error) {
if (error) {
if (typeof error === 'object') {
error.location = ref.toString();
}
adapter._enqueue(reject, [error]);
} else {
adapter._enqueue(resolve);
}
};
if (isEmbedded) {
ref.update(valueToSave, _saveHandler);
}
else {
ref.set(valueToSave, _saveHandler);
}
});
return this.updateRecord(store, relationship.type, record, ref);
},

@@ -628,13 +612,4 @@

deleteRecord: function(store, type, record) {
var adapter = this;
var ref = this._getRef(type, record.get('id'));
return new Promise(function(resolve, reject) {
ref.remove(function(err) {
if (err) {
adapter._enqueue(reject, [err]);
} else {
adapter._enqueue(resolve);
}
});
}, fmt('DS: FirebaseAdapter#deleteRecord %@ to %@', [type, ref.toString()]));
return toPromise(ref.remove, ref);
},

@@ -700,5 +675,10 @@

_enqueue: function(callback, args) {
var length = this._queue.push([callback, args]);
if (length === 1) {
this._queueScheduleFlush();
//Only do the queueing if we scheduled a delay
if (this._queueFlushDelay) {
var length = this._queue.push([callback, args]);
if (length === 1) {
this._queueScheduleFlush();
}
} else {
callback.apply(null, args);
}

@@ -705,0 +685,0 @@ },

@@ -10,2 +10,2 @@ /*!

*/
!function(){"use strict";if(void 0!==window.DS){var a=Ember.Namespace.create({VERSION:"0.0.0"});Ember.libraries&&Ember.libraries.registerCoreLibrary("EmberFire",a.VERSION);var b=Ember.RSVP.Promise,c=Ember.EnumerableUtils.map,d=Ember.EnumerableUtils.forEach,e=Ember.String.fmt;DS.FirebaseSerializer=DS.JSONSerializer.extend(Ember.Evented,{normalize:function(a,b){return a.eachRelationship(function(c,d){if("hasMany"===d.kind)if("object"!=typeof b[c]||Ember.isArray(b[c])||d.options.embedded===!0){if(Ember.isArray(b[c]))throw new Error(e('%@ relationship %@(\'%@\') must be a key/value map in Firebase. Example: { "%@": { "%@_id": true } }',[a.toString(),d.kind,d.type.typeKey,d.key,d.type.typeKey]))}else b[c]=Ember.keys(b[c])}),this._super.apply(this,arguments)},extractSingle:function(a,b,c){var d=(a.adapterFor(b),this.normalize(b,c));return b.eachRelationship(function(f,g){if(!Ember.isNone(c)&&!Ember.isNone(c[f])&&g.options.embedded===!0){var h,i,j=d[f],k=[];if("belongsTo"===g.kind){if("string"!=typeof j.id)throw new Error(e('Embedded relationship "%@" of "%@" must contain an "id" property in the payload',[g.type.typeKey,b]));k.push(j),d[f]=j.id}else{for(h in j)i=j[h],null!==i&&"object"==typeof i&&(i.id=h),k.push(i);d[f]=Ember.keys(d[f])}a.pushMany(g.type,k)}}),d},extractArray:function(a,b,d){return c(d,function(c){return this.extractSingle(a,b,c)},this)},serializeHasMany:function(a,b,c){var d=c.key,e=this.keyForRelationship?this.keyForRelationship(d,"hasMany"):d,f=DS.RelationshipChange.determineRelationshipType(a.constructor,c),g=["manyToNone","manyToMany","manyToOne"];g.indexOf(f)>-1&&(b[e]=Ember.A(a.get(d)).mapBy("id"))}}),DS.FirebaseAdapter=DS.Adapter.extend(Ember.Evented,{defaultSerializer:"-firebase",init:function(){if(!this.firebase||"object"!=typeof this.firebase)throw new Error("Please set the `firebase` property on the adapter.");this._ref=this.firebase.ref(),this._findAllMapForType={},this._recordCacheForType={},this._queue=[]},generateIdForRecord:function(){return this._ref.push().name()},_assignIdToPayload:function(a){var b=a.val();return null!==b&&"object"==typeof b&&"undefined"==typeof b.id&&(b.id=a.name()),b},find:function(a,c,d){var f=this,g=!1,h=this._getRef(c,d),i=a.serializerFor(c);return new b(function(b,j){h.on("value",function(k){var l=f._assignIdToPayload(k),m=a.getById(c,k.name());if(f._updateRecordCacheForType(c,l),g)null===l&&m&&!m.get("isDeleted")?f._enqueue(function(){a.getById(c,k.name()).deleteRecord()}):null!==l&&f._enqueue(function(){a.push(c,i.extractSingle(a,c,l))});else if(g=!0,null===l){a.hasRecordForId(c,d)&&f._enqueue(function(){a.dematerializeRecord(m)});var n=new Error(e("no record was found at %@",[h.toString()]));n.recordId=d,f._enqueue(j,[n])}else f._enqueue(b,[l])},function(a){g||f._enqueue(j,[a])})},e("DS: FirebaseAdapter#find %@ to %@",[c,h.toString()]))},findMany:function(a,b,e){var f=c(e,function(c){return this.find(a,b,c)},this);return Ember.RSVP.allSettled(f).then(function(c){return c=Ember.A(c),d(c.filterBy("state","rejected"),function(c){var d=c.reason.recordId;if(a.hasRecordForId(b,d)){var e=a.getById(b,d);a.dematerializeRecord(e)}}),Ember.A(c.filterBy("state","fulfilled")).mapBy("value")})},findAll:function(a,c){var d=this,f=this._getRef(c);return new b(function(b,e){var g;d._findAllHasEventsForType(c)||(g=d._findAllAddEventListeners(a,c,f)),f.once("value",function(a){var e=[];g&&Ember.run(null,g.resolve),null===a.val()?d._enqueue(b,[e]):(a.forEach(function(a){var b=d._assignIdToPayload(a);d._updateRecordCacheForType(c,b),e.push(b)}),d._enqueue(b,[e]))},function(a){d._enqueue(e,[a])})},e("DS: FirebaseAdapter#findAll %@ to %@",[c,f.toString()]))},_findAllMapForType:void 0,_findAllHasEventsForType:function(a){return!Ember.isNone(this._findAllMapForType[a])},_findAllAddEventListeners:function(a,b,c){this._findAllMapForType[b]=!0;var d=Ember.RSVP.defer(),e=this,f=a.serializerFor(b),g=!1;return d.promise.then(function(){g=!0}),c.on("child_added",function(c){g&&e._handleChildValue(a,b,f,c)}),c.on("child_changed",function(c){g&&e._handleChildValue(a,b,f,c)}),c.on("child_removed",function(c){if(g){var d=a.getById(b,c.name());d&&!d.get("isDeleted")&&e._enqueue(function(){a.deleteRecord(d)})}}),d},_handleChildValue:function(a,b,c,d){var e=this._assignIdToPayload(d);this._enqueue(function(){a.push(b,c.extractSingle(a,b,e))})},createRecord:function(a,b,c){return this.updateRecord(a,b,c)},updateRecord:function(a,c,d){var f=this,g=this._getRef(c,d.id),h=Ember.get(f._recordCacheForType,e("%@.%@",[c.typeKey,d.get("id")]))||{};return this._getSerializedRecord(d).then(function(i){return new b(function(b,j){var k=Ember.A();d.eachRelationship(function(b,d){var e;switch(d.kind){case"hasMany":Ember.isArray(i[b])&&(e=f._saveHasManyRelationship(a,c,d,i[b],g,h),k.push(e),delete i[b]);break;case"belongsTo":"undefined"==typeof i[b]||null===i[b]||""===i[b]?delete i[b]:d.options.embedded===!0&&(e=f._saveBelongsToRecord(a,c,d,i[b],g),k.push(e),delete i[b])}}),Ember.RSVP.allSettled(k).then(function(a){a=Ember.A(a);var h=Ember.A(a.filterBy("state","rejected"));if(0!==h.get("length")){var k=new Error(e("Some errors were encountered while saving %@ %@",[c,d.id]));k.errors=h.mapBy("reason"),f._enqueue(j,[k])}g.update(i,function(a){a?f._enqueue(j,[a]):f._enqueue(b)})})})},e("DS: FirebaseAdapter#updateRecord %@ to %@",[c,g.toString()]))},_getSerializedRecord:function(a){var c=a.serialize({includeId:!1}),d=[];return a.eachRelationship(function(e,f){switch(f.kind){case"hasMany":d.push(b.cast(a.get(e)).then(function(a){c[e]=Ember.A(a).mapBy("id")}))}}),Ember.RSVP.all(d).then(function(){return c})},_saveHasManyRelationship:function(a,b,c,d,f,g){if(!Ember.isArray(d))throw new Error("hasMany relationships must must be an array");var h=this,i=Ember.A(g[c.key]);d=Ember.A(d);var j=d.filter(function(a){return!i.contains(a)}),k=d.filter(function(b){var d=c.type;return a.hasRecordForId(d,b)&&a.getById(d,b).get("isDirty")===!0});k=Ember.A(k.concat(j)).uniq().map(function(b){return h._saveHasManyRecord(a,c,f,b)});var l=i.filter(function(a){return!d.contains(a)});l=Ember.A(l).map(function(b){return h._removeHasManyRecord(a,c,f,b)});var m=k.concat(l);return Ember.RSVP.allSettled(m).then(function(a){var b=Ember.A(Ember.A(a).filterBy("state","rejected"));if(0===b.get("length"))return g[c.key]=d,a;var f=new Error(e("Some errors were encountered while saving a hasMany relationship %@ -> %@",[c.parentType,c.type]));throw f.errors=Ember.A(b).mapBy("reason"),f})},_saveHasManyRecord:function(a,c,d,e){var f=this,g=this._getRelationshipRef(d,c.key,e),h=a.getById(c.type,e),i=c.options.embedded===!0,j=i?h.serialize({includeId:!1}):!0;return new b(function(a,b){var c=function(c){c?("object"==typeof c&&(c.location=g.toString()),f._enqueue(b,[c])):f._enqueue(a)};i?g.update(j,c):g.set(j,c)})},_removeHasManyRecord:function(a,c,d,e){var f=this,g=this._getRelationshipRef(d,c.key,e);return new b(function(a,b){var c=function(c){c?("object"==typeof c&&(c.location=g.toString()),f._enqueue(b,[c])):f._enqueue(a)};g.remove(c)})},_saveBelongsToRecord:function(a,c,d,e,f){var g=this,h=f.child(d.key),i=a.getById(d.type,e),j=d.options.embedded===!0,k=j?i.serialize({includeId:!0}):!0;return new b(function(a,b){var c=function(c){c?("object"==typeof c&&(c.location=h.toString()),g._enqueue(b,[c])):g._enqueue(a)};j?h.update(k,c):h.set(k,c)})},deleteRecord:function(a,c,d){var f=this,g=this._getRef(c,d.get("id"));return new b(function(a,b){g.remove(function(c){c?f._enqueue(b,[c]):f._enqueue(a)})},e("DS: FirebaseAdapter#deleteRecord %@ to %@",[c,g.toString()]))},pathForType:function(a){var b=Ember.String.camelize(a);return Ember.String.pluralize(b)},_getRef:function(a,b){var c=this._ref;return a&&(c=c.child(this.pathForType(a.typeKey))),b&&(c=c.child(b)),c},_getRelationshipRef:function(a,b,c){return a.child(b).child(c)},_queueFlushDelay:1e3/60,_queueScheduleFlush:function(){Ember.run.later(this,this._queueFlush,this._queueFlushDelay)},_queueFlush:function(){d(this._queue,function(a){var b=a[0],c=a[1];b.apply(null,c)}),this._queue.length=0},_enqueue:function(a,b){var c=this._queue.push([a,b]);1===c&&this._queueScheduleFlush()},_recordCacheForType:void 0,_updateRecordCacheForType:function(a,b){if(b){var c=this,d=b.id,e=c._recordCacheForType,f=a.typeKey;a.eachRelationship(function(a,c){if("hasMany"===c.kind){var g=b[a];e[f]=e[f]||{},e[f][d]=e[f][d]||{},e[f][d][a]=Ember.isNone(g)?Ember.A():Ember.A(Ember.keys(g))}})}}}),Ember.onLoad("Ember.Application",function(a){a.initializer({name:"firebase",initialize:function(a,b){b.register("adapter:-firebase",DS.FirebaseAdapter),b.register("serializer:-firebase",DS.FirebaseSerializer)}})})}}();
!function(){"use strict";if(void 0!==window.DS){var a=Ember.Namespace.create({VERSION:"0.0.0"});Ember.libraries&&Ember.libraries.registerCoreLibrary("EmberFire",a.VERSION),DS.Store.reopen({push:function(a,b,c){var d=this._super(a,b,c),e=this.adapterFor(d.constructor);return e.recordWasPushed&&e.recordWasPushed(this,a,d),d},recordWillUnload:function(a){var b=this.adapterFor(a.constructor);b.recordWillUnload&&b.recordWillUnload(this,a)}}),DS.Model.reopen({unloadRecord:function(){return this.store.recordWillUnload(this),this._super()}});var b=Ember.RSVP.Promise,c=Ember.EnumerableUtils.map,d=Ember.EnumerableUtils.forEach,e=Ember.String.fmt,f=function(a,c,d,e){var f=d||[];return new b(function(b,d){var g=function(a){a?(e&&"object"==typeof a&&(a.location=e),d(a)):b()};f.push(g),a.apply(c,f)})};DS.FirebaseSerializer=DS.JSONSerializer.extend(Ember.Evented,{_normalizeNumberIDs:function(a,b){var c=[];a[b][0]===!0&&c.push("0"),a[b][1]===!0&&c.push("1"),a[b]=c},normalizeHasMany:function(a,b,c){var d=c.key;if("object"!=typeof b[d]||Ember.isArray(b[d])){if(Ember.isArray(b[d])&&b[d].length<3&&(b[d][0]===!0||b[d][1]===!0))this._normalizeNumberIDs(b,d);else if(Ember.isArray(b[d]))throw new Error(e('%@ relationship %@(\'%@\') must be a key/value map in Firebase. Example: { "%@": { "%@_id": true } }',[a.toString(),c.kind,c.type.typeKey,d,c.type.typeKey]))}else b[d]=Ember.keys(b[d])},normalizeEmbeddedHasMany:function(a,b,c){var d,e=c.key,f=b[e];if(b[e]){for(d in f){var g=f[d];null!==g&&"object"==typeof g&&(g.id=d),this.store.push(c.type,this.normalize(c.type,g))}b[e]=Ember.keys(b[e])}},normalizeEmbeddedBelongsTo:function(a,b,c){var d=c.key;if(b[d]){var f=b[d];if("string"!=typeof f.id)throw new Error(e('Embedded relationship "%@" of "%@" must contain an "id" property in the payload',[c.type.typeKey,a]));this.store.push(c.type,this.normalize(c.type,f)),b[d]=f.id}},normalizeBelongsTo:Ember.K,normalize:function(a,b){var c=this;return a.eachRelationship(function(d,e){"hasMany"===e.kind?e.options.embedded?c.normalizeEmbeddedHasMany(a,b,e):c.normalizeHasMany(a,b,e):e.options.embedded?c.normalizeEmbeddedBelongsTo(a,b,e):c.normalizeBelongsTo(a,b,e)}),this._super.apply(this,arguments)},extractSingle:function(a,b,c){return this.normalize(b,c)},extractArray:function(a,b,d){return c(d,function(c){return this.extractSingle(a,b,c)},this)},serializeHasMany:function(a,b,c){var d=c.key,e=this.keyForRelationship?this.keyForRelationship(d,"hasMany"):d;b[e]=Ember.A(a.get(d)).mapBy("id")},serializeBelongsTo:function(a,b,c){this._super(a,b,c);{var d=c.key;this.keyForRelationship?this.keyForRelationship(d,"belongsTo"):c.key}("undefined"==typeof b[d]||""===b[d])&&delete b[d]}}),DS.FirebaseAdapter=DS.Adapter.extend(Ember.Evented,{defaultSerializer:"-firebase",init:function(){if(!this.firebase||"object"!=typeof this.firebase)throw new Error("Please set the `firebase` property on the adapter.");this._ref=this.firebase.ref(),this._findAllMapForType={},this._recordCacheForType={},this._queue=[]},generateIdForRecord:function(){return this._ref.push().name()},_assignIdToPayload:function(a){var b=a.val();return null!==b&&"object"==typeof b&&"undefined"==typeof b.id&&(b.id=a.name()),b},find:function(a,c,d){{var f=this,g=this._getRef(c,d);a.serializerFor(c)}return new b(function(a,b){g.once("value",function(h){var i=f._assignIdToPayload(h);if(f._updateRecordCacheForType(c,i),null===i){var j=new Error(e("no record was found at %@",[g.toString()]));j.recordId=d,b(j)}else a(i)},function(a){b(a)})},e("DS: FirebaseAdapter#find %@ to %@",[c,g.toString()]))},recordWasPushed:function(a,b,c){c.__listening||this.listenForChanges(a,b,c)},recordWillUnload:function(a,b){var c=this._getRef(b.typeKey,b.get("id"));c.off("value")},listenForChanges:function(a,b,c){c.__listening=!0;var d=a.serializerFor(b),e=this,f=this._getRef(b,c.get("id")),g=!1;f.on("value",function(c){g&&e._handleChildValue(a,b,d,c),g=!0})},findMany:void 0,findAll:function(a,c){var d=this,f=this._getRef(c);return new b(function(b,e){f.once("value",function(e){d._findAllHasEventsForType(c)||d._findAllAddEventListeners(a,c,f);var g=[];e.forEach(function(a){var b=d._assignIdToPayload(a);d._updateRecordCacheForType(c,b),g.push(b)}),b(g)},function(a){e(a)})},e("DS: FirebaseAdapter#findAll %@ to %@",[c,f.toString()]))},_findAllMapForType:void 0,_findAllHasEventsForType:function(a){return!Ember.isNone(this._findAllMapForType[a])},_findAllAddEventListeners:function(a,b,c){this._findAllMapForType[b]=!0;var d=this,e=a.serializerFor(b);c.on("child_added",function(c){a.hasRecordForId(b,c.name())||d._handleChildValue(a,b,e,c)})},_handleChildValue:function(a,b,c,d){if(!a.isDestroying){var e=d.val();if(null===e){var f=d.name(),g=a.getById(b,f);g.get("isDeleted")||g.deleteRecord()}else{var h=this._assignIdToPayload(d);this._enqueue(function(){a.push(b,c.extractSingle(a,b,h))})}}},createRecord:function(a,b,c){var d=this;return this.updateRecord(a,b,c).then(function(){d.listenForChanges(a,b,c)})},updateRecord:function(a,c,d,f){var g=this,h=f||this._getRef(c,d.id),i=Ember.get(g._recordCacheForType,e("%@.%@",[c.typeKey,d.get("id")]))||{},j=d.serialize({includeId:!1});return new b(function(b,f){var k=Ember.A();d.eachRelationship(function(b,d){var e;"hasMany"===d.kind?j[b]&&(e=g._saveHasManyRelationship(a,c,d,j[b],h,i),k.push(e),delete j[b]):d.options.embedded===!0&&j[b]&&(e=g._saveBelongsToRecord(a,c,d,j[b],h),k.push(e),delete j[b])});var l=Ember.RSVP.allSettled(k),m=g._updateRecord(h,j);Ember.RSVP.hashSettled({relationships:l,record:m}).then(function(a){var g=Ember.A(a.relationships.value).filterBy("state","rejected");if("rejected"===a.record.state&&g.push(a.record),0!==g.length){var h=new Error(e("Some errors were encountered while saving %@ %@",[c,d.id]));h.errors=g.mapBy("reason"),f(h)}else b()})},e("DS: FirebaseAdapter#updateRecord %@ to %@",[c,h.toString()]))},_updateRecord:function(a,b){return f(a.update,a,[b])},_saveHasManyRelationship:function(a,b,c,d,f,g){if(!Ember.isArray(d))throw new Error("hasMany relationships must must be an array");var h=this,i=Ember.A(g[c.key]);d=Ember.A(d);var j=[],k=d.filter(function(a){return!i.contains(a)});j=d.filter(function(b){var d=c.type;return a.hasRecordForId(d,b)&&a.getById(d,b).get("isDirty")===!0}),j=Ember.A(j.concat(k)).uniq().map(function(b){return h._saveHasManyRecord(a,c,f,b)});var l=i.filter(function(a){return!d.contains(a)});l=Ember.A(l).map(function(b){return h._removeHasManyRecord(a,c,f,b)});var m=j.concat(l);return Ember.RSVP.allSettled(m).then(function(a){var b=Ember.A(Ember.A(a).filterBy("state","rejected"));if(0===b.get("length"))return g[c.key]=d,a;var f=new Error(e("Some errors were encountered while saving a hasMany relationship %@ -> %@",[c.parentType,c.type]));throw f.errors=Ember.A(b).mapBy("reason"),f})},_saveHasManyRecord:function(a,b,c,d){var e=this._getRelationshipRef(c,b.key,d),g=a.getById(b.type,d),h=b.options.embedded===!0;return h?this.updateRecord(a,b.type,g,e):f(e.set,e,[!0])},_removeHasManyRecord:function(a,b,c,d){var e=this._getRelationshipRef(c,b.key,d);return f(e.remove,e,[],e.toString())},_saveBelongsToRecord:function(a,b,c,d,e){var f=e.child(c.key),g=a.getById(c.type,d);return this.updateRecord(a,c.type,g,f)},deleteRecord:function(a,b,c){var d=this._getRef(b,c.get("id"));return f(d.remove,d)},pathForType:function(a){var b=Ember.String.camelize(a);return Ember.String.pluralize(b)},_getRef:function(a,b){var c=this._ref;return a&&(c=c.child(this.pathForType(a.typeKey))),b&&(c=c.child(b)),c},_getRelationshipRef:function(a,b,c){return a.child(b).child(c)},_queueFlushDelay:1e3/60,_queueScheduleFlush:function(){Ember.run.later(this,this._queueFlush,this._queueFlushDelay)},_queueFlush:function(){d(this._queue,function(a){var b=a[0],c=a[1];b.apply(null,c)}),this._queue.length=0},_enqueue:function(a,b){if(this._queueFlushDelay){var c=this._queue.push([a,b]);1===c&&this._queueScheduleFlush()}else a.apply(null,b)},_recordCacheForType:void 0,_updateRecordCacheForType:function(a,b){if(b){var c=this,d=b.id,e=c._recordCacheForType,f=a.typeKey;a.eachRelationship(function(a,c){if("hasMany"===c.kind){var g=b[a];e[f]=e[f]||{},e[f][d]=e[f][d]||{},e[f][d][a]=Ember.isNone(g)?Ember.A():Ember.A(Ember.keys(g))}})}}}),Ember.onLoad("Ember.Application",function(a){a.initializer({name:"firebase",initialize:function(a,b){b.register("adapter:-firebase",DS.FirebaseAdapter),b.register("serializer:-firebase",DS.FirebaseSerializer)}})})}}();

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc