Repository: goldibex/targaryen
Pull request #27 (2016-05-04 18:21:58)

Merge data snapshots
Fixes https://github.com/goldibex/targaryen/issues/26 by merging root and newData when trying writes.


Patch:
diff --git a/lib/helpers.js b/lib/helpers.js
new file mode 100644
index 0000000..3e0486e
--- /dev/null
+++ b/lib/helpers.js
@@ -0,0 +1,42 @@
+'use strict';
+
+var RuleDataSnapshot = require('./rule-data-snapshot');
+
+exports.pathSplitter = function(path) {
+
+  if (path[0] === '/') {
+    path = path.substr(1);
+  }
+
+  return path.split('/');
+};
+
+exports.makeNewDataSnap = function(path, newData) {
+
+  path = path.replace(/^\/+/, '');
+  newData = RuleDataSnapshot.convert(newData)
+
+  var result;
+
+  if (path.length === 0) {
+    result = newData;
+  } else {
+
+    var workObject = {};
+    result = workObject;
+
+    exports.pathSplitter(path).forEach(function(pathPart, i, pathParts) {
+
+      if (pathParts.length - i === 1) {
+        workObject[pathPart] = newData;
+      } else {
+        workObject[pathPart] = {};
+      }
+      workObject = workObject[pathPart];
+
+    });
+
+  }
+
+  return new RuleDataSnapshot(result);
+};
diff --git a/lib/rule-data-snapshot.js b/lib/rule-data-snapshot.js
index 4cad53d..643b3b2 100644
--- a/lib/rule-data-snapshot.js
+++ b/lib/rule-data-snapshot.js
@@ -61,6 +61,15 @@ RuleDataSnapshot.convert = function(data) {
 };
 
 
+RuleDataSnapshot.prototype.merge = function(other) {
+  if (this._path || other._path) {
+    throw new Error('can only merge top-level RuleDataSnapshots');
+  }
+
+  var data = extend(true, {}, this._data, other._data);
+  return new RuleDataSnapshot(data);
+}
+
 RuleDataSnapshot.prototype._getVal = function() {
 
   var pathParts;
diff --git a/lib/ruleset.js b/lib/ruleset.js
index 54b9e6e..835f3e8 100644
--- a/lib/ruleset.js
+++ b/lib/ruleset.js
@@ -3,7 +3,9 @@
 
 var extend = require('extend'),
   Rule = require('./parser/rule'),
-  RuleDataSnapshot = require('./rule-data-snapshot');
+  RuleDataSnapshot = require('./rule-data-snapshot'),
+  pathSplitter = require('./helpers').pathSplitter,
+  makeNewDataSnap = require('./helpers').makeNewDataSnap;
 
 var validRuleKinds = {
   '.read': true,
@@ -20,47 +22,6 @@ function ruleError(rulePath, message) {
 
 }
 
-function pathSplitter(path)
-{
-
-  if (path[0] === '/') {
-    path = path.substr(1);
-  }
-
-  return path.split('/');
-
-}
-
-function makeNewDataSnap(path, newData) {
-
-  path = path.replace(/^\/+/, '');
-  var result;
-
-  if (path.length === 0) {
-    result = newData;
-  } else {
-
-    var workObject = {};
-    result = workObject;
-
-    pathSplitter(path).forEach(function(pathPart, i, pathParts) {
-
-      if (pathParts.length - i === 1) {
-        workObject[pathPart] = newData;
-      } else {
-        workObject[pathPart] = {};
-      }
-      workObject = workObject[pathPart];
-
-    });
-
-  }
-
-  return new RuleDataSnapshot(result);
-
-}
-
-
 function Ruleset(rulesDefinition) {
 
   if (typeof rulesDefinition !== 'object' ||
@@ -153,7 +114,6 @@ function Ruleset(rulesDefinition) {
 
 }
 
-
 Ruleset.prototype.get = function(path, kind) {
 
   var rules = [];
@@ -278,7 +238,7 @@ Ruleset.prototype.tryWrite = function(path, root, newData, auth, skipWrite, skip
   // write encompasses both the cascading write rules and the
   // non-cascading validate rules
 
-  var newDataRoot = makeNewDataSnap(path, RuleDataSnapshot.convert(newData));
+  var newDataRoot = root.merge(makeNewDataSnap(path, newData));
 
   var result = {
     path: path,


Test patch:
diff --git a/lib/test-helpers.js b/lib/test-helpers.js
index 73e91ec..6f4e535 100644
--- a/lib/test-helpers.js
+++ b/lib/test-helpers.js
@@ -4,7 +4,8 @@
 var root, rules,
   debug = true,
   Ruleset = require('./ruleset'),
-  RuleDataSnapshot = require('./rule-data-snapshot');
+  RuleDataSnapshot = require('./rule-data-snapshot'),
+  makeNewDataSnap = require('./helpers').makeNewDataSnap;
 
 var userDefinitions = exports.userDefinitions = {
 
@@ -165,3 +166,5 @@ exports.setFirebaseRules = function(ruleDefinition) {
 exports.getFirebaseRules = function() {
   return rules;
 };
+
+exports.makeNewDataSnap = makeNewDataSnap;