Skip to content

Instantly share code, notes, and snippets.

@icholy
Last active December 14, 2015 07:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save icholy/5050533 to your computer and use it in GitHub Desktop.
Save icholy/5050533 to your computer and use it in GitHub Desktop.
Json Pointer Slices

The json-pointer draft is missing a very important piece: slices.

Example Data:

var obj = {
  foo: [
    { bar: 1 },
    { bar: 2 },
    { bar: 3 }
  ]
};

The way it is now

You can only drill down into an array with a specific index.

  • pointer /foo/1/bar
  • value 2
  • javascript equivalent foo[1].bar

The way it should be

With a slice you can grab a range of values.

  • pointer /foo/1:3/bar
  • value [2, 3]
  • javascript equivalent foo.slice(1, 3).map(function (obj) { return obj.bar; });

Why?

The json-pointer draft is used by the json-patch. Without slices, you are restricted to treating arrays like pojo's.

Say for example you wanted to write a patch that removes 100 elements from an array. Currently you have to write 100 separate remove operations with each one specifying the index. I think we can do better.

How?

Edit: Here's a better one

Here is a naive implementation. demo

var getPointedValue = function (pointer, obj) {
  
  if (pointer.length === 0)
    return obj;

  var sepIndex = pointer.indexOf('/');
  
  if (sepIndex === 0)
    return getPointedValue(pointer.substr(1), obj);
  
  if (sepIndex === -1)
    sepIndex = pointer.length;
  
  var firstPart = pointer.substr(0, sepIndex),
      restParts = pointer.substr(sepIndex + 1),
      colIndex  = firstPart.indexOf(':');
  
  if (colIndex === -1)
    return getPointedValue(restParts, obj[firstPart]);

  var sliceStart = parseInt(firstPart.substr(0, colIndex), 10),
      sliceEnd   = parseInt(firstPart.substr(colIndex + 1), 10);
  
  if (isNaN(sliceStart) || !isFinite(sliceStart)) sliceStart = 0;
  if (isNaN(sliceEnd)   || !isFinite(sliceEnd))   sliceEnd   = 0;
  
  return obj.slice(sliceStart, sliceEnd).map(function (obj) {
    return getPointedValue(restParts, obj);
  });
};

Object.prototype.pointer = function (p) { return getPointedValue(p, this); }

Example Usage:

var pointers = [
  '/foo/0:1',
  '/foo/0:2',
  '/foo/0:1/bar',
  '/foo/1:2/bar'
];

pointers.forEach(function (p) {
  var val = obj.pointer(p);
  console.log([
    p, "=>", JSON.stringify(val)
  ].join(" "));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment