From aafa3d3af1de8f68fd4c430442a519b152670566 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Mon, 24 Mar 2014 15:40:15 -0700 Subject: [PATCH 1/2] added the jsonbath bower component's source --- src/bower_components/jsonpath/.bower.json | 13 ++ src/bower_components/jsonpath/.gitignore | 9 + src/bower_components/jsonpath/.npmignore | 2 + src/bower_components/jsonpath/.travis.yml | 4 + src/bower_components/jsonpath/CHANGES.md | 14 ++ src/bower_components/jsonpath/README.md | 111 +++++++++++ src/bower_components/jsonpath/lib/jsonpath.js | 172 +++++++++++++++++ src/bower_components/jsonpath/package.json | 36 ++++ .../jsonpath/test/test.arr.js | 35 ++++ .../jsonpath/test/test.at_and_dollar.js | 54 ++++++ .../jsonpath/test/test.eval.js | 45 +++++ .../jsonpath/test/test.examples.js | 177 ++++++++++++++++++ src/bower_components/jsonpath/test/test.html | 59 ++++++ .../jsonpath/test/test.intermixed.arr.js | 53 ++++++ .../jsonpath/test/test.parent-selector.js | 64 +++++++ 15 files changed, 848 insertions(+) create mode 100644 src/bower_components/jsonpath/.bower.json create mode 100644 src/bower_components/jsonpath/.gitignore create mode 100644 src/bower_components/jsonpath/.npmignore create mode 100644 src/bower_components/jsonpath/.travis.yml create mode 100644 src/bower_components/jsonpath/CHANGES.md create mode 100644 src/bower_components/jsonpath/README.md create mode 100644 src/bower_components/jsonpath/lib/jsonpath.js create mode 100644 src/bower_components/jsonpath/package.json create mode 100644 src/bower_components/jsonpath/test/test.arr.js create mode 100644 src/bower_components/jsonpath/test/test.at_and_dollar.js create mode 100644 src/bower_components/jsonpath/test/test.eval.js create mode 100644 src/bower_components/jsonpath/test/test.examples.js create mode 100644 src/bower_components/jsonpath/test/test.html create mode 100644 src/bower_components/jsonpath/test/test.intermixed.arr.js create mode 100644 src/bower_components/jsonpath/test/test.parent-selector.js diff --git a/src/bower_components/jsonpath/.bower.json b/src/bower_components/jsonpath/.bower.json new file mode 100644 index 0000000000000..23a93b46cfd79 --- /dev/null +++ b/src/bower_components/jsonpath/.bower.json @@ -0,0 +1,13 @@ +{ + "name": "jsonpath", + "homepage": "https://github.com/s3u/JSONPath", + "_release": "308ef21860", + "_resolution": { + "type": "branch", + "branch": "master", + "commit": "308ef21860ae21584c0f808d67cf63006101149a" + }, + "_source": "git://github.com/s3u/JSONPath.git", + "_target": "*", + "_originalSource": "jsonpath" +} \ No newline at end of file diff --git a/src/bower_components/jsonpath/.gitignore b/src/bower_components/jsonpath/.gitignore new file mode 100644 index 0000000000000..1578bf2089958 --- /dev/null +++ b/src/bower_components/jsonpath/.gitignore @@ -0,0 +1,9 @@ +*.iml +.DS_Store +.idea +temp +node_modules +pids +reports +target +*.log diff --git a/src/bower_components/jsonpath/.npmignore b/src/bower_components/jsonpath/.npmignore new file mode 100644 index 0000000000000..f05b1f265dc7e --- /dev/null +++ b/src/bower_components/jsonpath/.npmignore @@ -0,0 +1,2 @@ +node_modules +test diff --git a/src/bower_components/jsonpath/.travis.yml b/src/bower_components/jsonpath/.travis.yml new file mode 100644 index 0000000000000..811124587afbf --- /dev/null +++ b/src/bower_components/jsonpath/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 \ No newline at end of file diff --git a/src/bower_components/jsonpath/CHANGES.md b/src/bower_components/jsonpath/CHANGES.md new file mode 100644 index 0000000000000..3457fa28e0fa6 --- /dev/null +++ b/src/bower_components/jsonpath/CHANGES.md @@ -0,0 +1,14 @@ + +## Oct 23, 2013 + +* Support for parent selection via `^` +* Access current path via `@path` in test statements +* Allowing for multi-statement evals +* Performance improvements +* Version 0.10 + +## Mar 28, 2012 + +* Support a sandbox arg to eval +* Use vm.runInNewContext in place of eval +* Version 0.9.0 diff --git a/src/bower_components/jsonpath/README.md b/src/bower_components/jsonpath/README.md new file mode 100644 index 0000000000000..38b0565f716b1 --- /dev/null +++ b/src/bower_components/jsonpath/README.md @@ -0,0 +1,111 @@ +JSONPath [![build status](https://secure.travis-ci.org/s3u/JSONPath.png)](http://travis-ci.org/s3u/JSONPath) +======== + +Analyse, transform, and selectively extract data from JSON documents (and JavaScript objects). + +Install +------- + + npm install JSONPath + +Usage +----- + +In node.js: + +```js +var jsonPath = require('JSONPath'); +jsonPath.eval(obj, path); +``` + +For browser usage you can directly include `lib/jsonpath.js`, no browserify +magic necessary: + +```html + + +``` + +Examples +-------- + +Given the following JSON, taken from http://goessner.net/articles/JsonPath/ : + +```json +{ + "store": { + "book": [ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { + "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + } +} +``` + + +XPath | JSONPath | Result +------------------- | ---------------------- | ------------------------------------- +/store/book/author | $.store.book[*].author | the authors of all books in the store +//author | $..author | all authors +/store/* | $.store.* | all things in store, which are some books and a red bicycle. +/store//price | $.store..price | the price of everything in the store. +//book[3] | $..book[2] | the third book +//book[last()] | $..book[(@.length-1)] | the last book in order. + | $..book[-1:] | +//book[position()<3]| $..book[0,1] | the first two books + | $..book[:2] | +//book[isbn] | $..book[?(@.isbn)] | filter all books with isbn number +//book[price<10] | $..book[?(@.price<10)] | filter all books cheapier than 10 +//*[price>19]/.. | $..[?(@.price>19)]^ | categories with things more expensive than 19 +//* | $..* | all Elements in XML document. All members of JSON structure. + +Development +----------- + +Running the tests on node: `npm test`. For in-browser tests: + +* Ensure that nodeunit is browser-compiled: `cd node_modules/nodeunit; make browser;` +* Serve the js/html files: + +```sh + node -e "require('http').createServer(function(req,res) { \ + var s = require('fs').createReadStream('.' + req.url); \ + s.pipe(res); s.on('error', function() {}); }).listen(8082);" +``` +* To run the tests visit [http://localhost:8082/test/test.html](). + + +License +------- + +[MIT License](http://www.opensource.org/licenses/mit-license.php). diff --git a/src/bower_components/jsonpath/lib/jsonpath.js b/src/bower_components/jsonpath/lib/jsonpath.js new file mode 100644 index 0000000000000..fb7c6597507e4 --- /dev/null +++ b/src/bower_components/jsonpath/lib/jsonpath.js @@ -0,0 +1,172 @@ +/* JSONPath 0.8.0 - XPath for JSON + * + * Copyright (c) 2007 Stefan Goessner (goessner.net) + * Licensed under the MIT (MIT-LICENSE.txt) licence. + */ + +var isNode = false; +(function(exports, require) { + +// Keep compatibility with old browsers +if (!Array.isArray) { + Array.isArray = function(vArg) { + return Object.prototype.toString.call(vArg) === "[object Array]"; + }; +} + +// Make sure to know if we are in real node or not (the `require` variable +// could actually be require.js, for example. +var isNode = typeof module !== 'undefined' && !!module.exports; + +var vm = isNode ? + require('vm') : { + runInNewContext: function(expr, context) { with (context) return eval(expr); } + }; +exports.eval = jsonPath; + +var cache = {}; + +function push(arr, elem) { arr = arr.slice(); arr.push(elem); return arr; } +function unshift(elem, arr) { arr = arr.slice(); arr.unshift(elem); return arr; } + +function jsonPath(obj, expr, arg) { + var P = { + resultType: arg && arg.resultType || "VALUE", + flatten: arg && arg.flatten || false, + wrap: (arg && arg.hasOwnProperty('wrap')) ? arg.wrap : true, + sandbox: (arg && arg.sandbox) ? arg.sandbox : {}, + normalize: function(expr) { + if (cache[expr]) return cache[expr]; + var subx = []; + var normalized = expr.replace(/[\['](\??\(.*?\))[\]']/g, function($0,$1){return "[#"+(subx.push($1)-1)+"]";}) + .replace(/'?\.'?|\['?/g, ";") + .replace(/(;)?(\^+)(;)?/g, function(_, front, ups, back) { return ';' + ups.split('').join(';') + ';'; }) + .replace(/;;;|;;/g, ";..;") + .replace(/;$|'?\]|'$/g, ""); + var exprList = normalized.split(';').map(function(expr) { + var match = expr.match(/#([0-9]+)/); + return !match || !match[1] ? expr : subx[match[1]]; + }) + return cache[expr] = exprList; + }, + asPath: function(path) { + var x = path, p = "$"; + for (var i=1,n=x.length; i -1) { // [name1,name2,...] + for (var parts = loc.split(','), i = 0; i < parts.length; i++) + addRet(P.trace(unshift(parts[i], x), val, path)); + } + else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) { // [start:end:step] python slice syntax + addRet(P.slice(loc, x, val, path)); + } + + // we check the resulting values for parent selections. for parent + // selections we discard the value object and continue the trace with the + // current val object + return ret.reduce(function(all, ea) { + return all.concat(ea.isParentSelector ? P.trace(ea.expr, val, ea.path) : [ea]); + }, []); + }, + walk: function(loc, expr, val, path, f) { + if (Array.isArray(val)) + for (var i = 0, n = val.length; i < n; i++) + f(i, loc, expr, val, path); + else if (typeof val === "object") + for (var m in val) + if (val.hasOwnProperty(m)) + f(m, loc, expr, val, path); + }, + slice: function(loc, expr, val, path) { + if (!Array.isArray(val)) return; + var len = val.length, parts = loc.split(':'), + start = (parts[0] && parseInt(parts[0])) || 0, + end = (parts[1] && parseInt(parts[1])) || len, + step = (parts[2] && parseInt(parts[2])) || 1; + start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start); + end = (end < 0) ? Math.max(0,end+len) : Math.min(len,end); + var ret = []; + for (var i = start; i < end; i += step) + ret = ret.concat(P.trace(unshift(i,expr), val, path)); + return ret; + }, + eval: function(code, _v, _vname, path) { + if (!$ || !_v) return false; + if (code.indexOf("@path") > -1) { + P.sandbox["_path"] = P.asPath(path.concat([_vname])); + code = code.replace(/@path/g, "_path"); + } + if (code.indexOf("@") > -1) { + P.sandbox["_v"] = _v; + code = code.replace(/@/g, "_v"); + } + try { + return vm.runInNewContext(code, P.sandbox); + } + catch(e) { + console.log(e); + throw new Error("jsonPath: " + e.message + ": " + code); + } + } + }; + + var $ = obj; + var resultType = P.resultType.toLowerCase(); + if (expr && obj && (resultType == "value" || resultType == "path")) { + var exprList = P.normalize(expr); + if (exprList[0] === "$" && exprList.length > 1) exprList.shift(); + var result = P.trace(exprList, obj, ["$"]); + result = result.filter(function(ea) { return ea && !ea.isParentSelector; }); + if (!result.length) return P.wrap ? [] : false; + if (result.length === 1 && !P.wrap && !Array.isArray(result[0].value)) return result[0][resultType] || false; + return result.reduce(function(result, ea) { + var valOrPath = ea[resultType]; + if (resultType === 'path') valOrPath = P.asPath(valOrPath); + if (P.flatten && Array.isArray(valOrPath)) { + result = result.concat(valOrPath); + } else { + result.push(valOrPath); + } + return result; + }, []); + } +} +})(typeof exports === 'undefined' ? this['jsonPath'] = {} : exports, typeof require == "undefined" ? null : require); diff --git a/src/bower_components/jsonpath/package.json b/src/bower_components/jsonpath/package.json new file mode 100644 index 0000000000000..e5231e45b03c6 --- /dev/null +++ b/src/bower_components/jsonpath/package.json @@ -0,0 +1,36 @@ +{ + "author": "Stefan Goessner", + "name": "JSONPath", + "description": "A JS implementation of JSONPath", + "contributors": [ + { + "name": "Prof. Gössner", + "email": "stefan.goessner@fh-dortmund.de" + }, + { + "name": "Subbu Allamaraju", + "email": "subbu@subbu.org" + }, + { + "name": "Mike Brevoort", + "email": "mike@brevoort.com" + }, + { + "name": "Robert Krahn", + "email": "robert.krahn@gmail.com" + } + ], + "version": "0.10.0", + "repository": { + "type": "git", + "url": "git://github.com/s3u/JSONPath.git" + }, + "main": "./lib/jsonpath", + "dependencies": { + "underscore": "*" + }, + "devDependencies": { + "nodeunit": "*" + }, + "scripts": {"test": "node_modules/nodeunit/bin/nodeunit test/test.*.js"} +} diff --git a/src/bower_components/jsonpath/test/test.arr.js b/src/bower_components/jsonpath/test/test.arr.js new file mode 100644 index 0000000000000..4314fd236d4b6 --- /dev/null +++ b/src/bower_components/jsonpath/test/test.arr.js @@ -0,0 +1,35 @@ +var jsonpath = require("../").eval, + testCase = require('nodeunit').testCase + +var json = { + "store": { + "book": { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": [8.95, 8.94, 8.93] + }, + "books": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": [8.95, 8.94, 8.93] + } + ] + } +}; + +module.exports = testCase({ + "get single": function (test) { + var expected = json.store.book; + var result = jsonpath(json, "store.book", {flatten: true, wrap: false}); + test.deepEqual(expected, result); + test.done(); + }, + + "get arr": function (test) { + var expected = json.store.books; + var result = jsonpath(json, "store.books", {flatten: true, wrap: false}); + test.deepEqual(expected, result); + test.done(); + } +}); diff --git a/src/bower_components/jsonpath/test/test.at_and_dollar.js b/src/bower_components/jsonpath/test/test.at_and_dollar.js new file mode 100644 index 0000000000000..e99d7dbf6d677 --- /dev/null +++ b/src/bower_components/jsonpath/test/test.at_and_dollar.js @@ -0,0 +1,54 @@ +var jsonpath = require("../").eval + , testCase = require('nodeunit').testCase + + +var t1 = { + simpleString: "simpleString", + "@" : "@asPropertyName", + "$" : "$asPropertyName", + "a$a": "$inPropertyName", + "$": { + "@": "withboth", + }, + a: { + b: { + c: "food" + } + } +}; + + +module.exports = testCase({ + + + // ============================================================================ + "test undefined, null": function(test) { + // ============================================================================ + test.expect(5); + test.equal(undefined, jsonpath(undefined, "foo")); + test.equal(null, jsonpath(null, "foo")); + test.equal(undefined, jsonpath({}, "foo")[0]); + test.equal(undefined, jsonpath({ a: "b" }, "foo")[0]); + test.equal(undefined, jsonpath({ a: "b" }, "foo")[100]); + test.done(); + }, + + + // ============================================================================ + "test $ and @": function(test) { + // ============================================================================ + test.expect(7); + test.equal(t1["$"], jsonpath(t1, "\$")[0]); + test.equal(t1["$"], jsonpath(t1, "$")[0]); + test.equal(t1["a$a"], jsonpath(t1, "a$a")[0]); + test.equal(t1["@"], jsonpath(t1, "\@")[0]); + test.equal(t1["@"], jsonpath(t1, "@")[0]); + test.equal(t1["$"]["@"], jsonpath(t1, "$.$.@")[0]); + test.equal(undefined, jsonpath(t1, "\@")[1]); + + test.done(); + } + +}); + + diff --git a/src/bower_components/jsonpath/test/test.eval.js b/src/bower_components/jsonpath/test/test.eval.js new file mode 100644 index 0000000000000..8da68e90879e4 --- /dev/null +++ b/src/bower_components/jsonpath/test/test.eval.js @@ -0,0 +1,45 @@ +var jsonpath = require("../").eval, + testCase = require('nodeunit').testCase + +var json = { + "store": { + "book": { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": [8.95, 8.94] + }, + "books": [{ + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": [10.99, 12.29] + }, { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": [8.99, 6.95] + }] + } +}; + + +module.exports = testCase({ + "multi statement eval": function (test) { + var expected = json.store.books[0]; + var selector = "$..[?(" + + "var sum = @.price && @.price[0]+@.price[1];" + + "sum > 20;)]" + var result = jsonpath(json, selector, {wrap: false}); + test.deepEqual(expected, result); + test.done(); + }, + + "accessing current path": function (test) { + var expected = json.store.books[1]; + var result = jsonpath(json, "$..[?(@path==\"$['store']['books'][1]\")]", {wrap: false}); + test.deepEqual(expected, result); + test.done(); + } +}); diff --git a/src/bower_components/jsonpath/test/test.examples.js b/src/bower_components/jsonpath/test/test.examples.js new file mode 100644 index 0000000000000..0532725684789 --- /dev/null +++ b/src/bower_components/jsonpath/test/test.examples.js @@ -0,0 +1,177 @@ +var jsonpath = require("../").eval + , testCase = require('nodeunit').testCase + +// tests based on examples at http://goessner.net/articles/JsonPath/ + +var json = {"store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + } +}; + + +module.exports = testCase({ + + // ============================================================================ + "wildcards": function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0].author, books[1].author, books[2].author, books[3].author]; + var result = jsonpath(json, "$.store.book[*].author"); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + "all properties, entire tree": function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0].author, books[1].author, books[2].author, books[3].author]; + var result = jsonpath(json, "$..author"); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + "all sub properties, single level": function(test) { + // ============================================================================ + test.expect(1); + var expected = [json.store.book, json.store.bicycle]; + var result = jsonpath(json, "$.store.*"); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + "all sub properties, entire tree": function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0].price, books[1].price, books[2].price, books[3].price, json.store.bicycle.price]; + var result = jsonpath(json, "$.store..price"); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + "n property of entire tree": function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[2]]; + var result = jsonpath(json, "$..book[2]"); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + "last property of entire tree": function(test) { + // ============================================================================ + test.expect(2); + var books = json.store.book; + var expected = [books[3]]; + var result = jsonpath(json, "$..book[(@.length-1)]"); + test.deepEqual(expected, result); + + result = jsonpath(json, "$..book[-1:]"); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + "range of property of entire tree": function(test) { + // ============================================================================ + test.expect(2); + var books = json.store.book; + var expected = [books[0], books[1]]; + var result = jsonpath(json, "$..book[0,1]"); + test.deepEqual(expected, result); + + result = jsonpath(json, "$..book[:2]"); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + "filter all properties if sub property exists,o entire tree": function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[2], books[3]]; + var result = jsonpath(json, "$..book[?(@.isbn)]"); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + "filter all properties if sub property greater than of entire tree": function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0], books[2]]; + var result = jsonpath(json, "$..book[?(@.price<10)]"); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + "all properties of a json structure": function(test) { + // ============================================================================ + // test.expect(1); + var expected = [ + json.store, + json.store.book, + json.store.bicycle, + ]; + json.store.book.forEach(function(book) { expected.push(book); }); + json.store.book.forEach(function(book) { Object.keys(book).forEach(function(p) { expected.push(book[p]); })}); + expected.push(json.store.bicycle.color); + expected.push(json.store.bicycle.price); + + var result = jsonpath(json, "$..*"); + test.deepEqual(expected, result); + + test.done(); + } + + + + +}); diff --git a/src/bower_components/jsonpath/test/test.html b/src/bower_components/jsonpath/test/test.html new file mode 100644 index 0000000000000..be5cdd4a96275 --- /dev/null +++ b/src/bower_components/jsonpath/test/test.html @@ -0,0 +1,59 @@ + + + JSONPath Tests + + + + + + + +

JSONPath Tests

+ + + \ No newline at end of file diff --git a/src/bower_components/jsonpath/test/test.intermixed.arr.js b/src/bower_components/jsonpath/test/test.intermixed.arr.js new file mode 100644 index 0000000000000..1cf622d5d798f --- /dev/null +++ b/src/bower_components/jsonpath/test/test.intermixed.arr.js @@ -0,0 +1,53 @@ +var jsonpath = require("../").eval, + testCase = require('nodeunit').testCase + +// tests based on examples at http://goessner.net/articles/JsonPath/ + +var json = {"store":{ + "book":[ + { "category":"reference", + "author":"Nigel Rees", + "title":"Sayings of the Century", + "price":[8.95, 8.94, 8.93] + }, + { "category":"fiction", + "author":"Evelyn Waugh", + "title":"Sword of Honour", + "price":12.99 + }, + { "category":"fiction", + "author":"Herman Melville", + "title":"Moby Dick", + "isbn":"0-553-21311-3", + "price":8.99 + }, + { "category":"fiction", + "author":"J. R. R. Tolkien", + "title":"The Lord of the Rings", + "isbn":"0-395-19395-8", + "price":22.99 + } + ], + "bicycle":{ + "color":"red", + "price":19.95 + } +} +}; + + +module.exports = testCase({ + + // ============================================================================ + "all sub properties, entire tree":function (test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[1].price, books[2].price, books[3].price, json.store.bicycle.price]; + expected = books[0].price.concat(expected); + var result = jsonpath(json, "$.store..price", {flatten: true}); + test.deepEqual(expected, result); + + test.done(); + } +}); diff --git a/src/bower_components/jsonpath/test/test.parent-selector.js b/src/bower_components/jsonpath/test/test.parent-selector.js new file mode 100644 index 0000000000000..678c9e3f883b8 --- /dev/null +++ b/src/bower_components/jsonpath/test/test.parent-selector.js @@ -0,0 +1,64 @@ +var jsonpath = require("../").eval, + testCase = require('nodeunit').testCase + +var json = { + "name": "root", + "children": [ + {"name": "child1", "children": [{"name": "child1_1"},{"name": "child1_2"}]}, + {"name": "child2", "children": [{"name": "child2_1"}]}, + {"name": "child3", "children": [{"name": "child3_1"}, {"name": "child3_2"}]} + ] +}; + + +module.exports = testCase({ + + // ============================================================================ + "simple parent selection": function(test) { + // ============================================================================ + test.expect(1); + var result = jsonpath(json, "$.children[0]^", {flatten: true}); + test.deepEqual(json.children, result); + test.done(); + }, + + // ============================================================================ + "parent selection with multiple matches": function(test) { + // ============================================================================ + test.expect(1); + var expected = [json.children,json.children]; + var result = jsonpath(json, "$.children[1:3]^"); + test.deepEqual(expected, result); + test.done(); + }, + + // ============================================================================ + "select sibling via parent": function(test) { + // ============================================================================ + test.expect(1); + var expected = [{"name": "child3_2"}]; + var result = jsonpath(json, "$..[?(@.name && @.name.match(/3_1$/))]^[?(@.name.match(/_2$/))]"); + test.deepEqual(expected, result); + test.done(); + }, + + // ============================================================================ + "parent parent parent": function(test) { + // ============================================================================ + test.expect(1); + var expected = json.children[0].children; + var result = jsonpath(json, "$..[?(@.name && @.name.match(/1_1$/))].name^^", {flatten: true}); + test.deepEqual(expected, result); + test.done(); + }, + + // ============================================================================ + "no such parent": function(test) { + // ============================================================================ + test.expect(1); + var result = jsonpath(json, "name^^"); + test.deepEqual([], result); + test.done(); + } + +}); From e7eb964c44988e8c82f4a9706d8fd8f5c0974abb Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Mon, 24 Mar 2014 15:41:38 -0700 Subject: [PATCH 2/2] added saved searches (saved dataSources) --- src/courier/data_source/data_source.js | 31 +-- src/courier/data_source/doc.js | 14 +- .../apps/discover/controllers/discover.js | 217 +++++++++++++++++ .../apps/discover/factories/saved_search.js | 116 +++++++++ src/kibana/apps/discover/index.js | 220 +----------------- .../apps/discover/partials/settings.html | 26 ++- .../apps/discover/services/saved_searches.js | 25 ++ .../apps/visualize/controllers/visualize.js | 114 +++++---- .../visualize/directives/visualization.js | 2 + src/kibana/apps/visualize/factories/vis.js | 6 +- src/kibana/directives/table.js | 3 +- src/kibana/index.js | 1 + src/kibana/services/saved_searches.js | 43 ---- 13 files changed, 488 insertions(+), 330 deletions(-) create mode 100644 src/kibana/apps/discover/controllers/discover.js create mode 100644 src/kibana/apps/discover/factories/saved_search.js create mode 100644 src/kibana/apps/discover/services/saved_searches.js delete mode 100644 src/kibana/services/saved_searches.js diff --git a/src/courier/data_source/data_source.js b/src/courier/data_source/data_source.js index 438b353a11aaa..742dc9391626a 100644 --- a/src/courier/data_source/data_source.js +++ b/src/courier/data_source/data_source.js @@ -6,22 +6,22 @@ define(function (require) { var nextTick = require('utils/next_tick'); function DataSource(courier, initialState) { - var state; - EventEmitter.call(this); - // state can be serialized as JSON, and passed back in to restore - if (initialState) { - if (typeof initialState === 'string') { - state = JSON.parse(initialState); + this._state = (function () { + // state can be serialized as JSON, and passed back in to restore + if (initialState) { + if (typeof initialState === 'string') { + return JSON.parse(initialState); + } else { + return _.cloneDeep(initialState); + } } else { - state = _.cloneDeep(initialState); + return {}; } - } else { - state = {}; - } + }()); - this._state = state; + this._dynamicState = this._dynamicState || {}; this._courier = courier; // before newListener to prevent unnecessary "emit" when added @@ -64,9 +64,9 @@ define(function (require) { this._methods.forEach(function (name) { this[name] = function (val) { if (val == null) { - delete state[name]; + delete this._state[name]; } else { - state[name] = val; + this._state[name] = val; } return this; @@ -87,6 +87,7 @@ define(function (require) { var current = this; while (current) { if (current._state[name] !== void 0) return current._state[name]; + if (current._dynamicState[name] !== void 0) return current._dynamicState[name](); current = current._parent; } }; @@ -108,7 +109,7 @@ define(function (require) { * Clear the disabled flag, you do not need to call this unless you * explicitly disabled the DataSource */ - DataSource.prototype.enableFetch = function () { + DataSource.prototype.enableAuthFetch = function () { delete this._fetchDisabled; return this; }; @@ -116,7 +117,7 @@ define(function (require) { /** * Disable the DataSource, preventing it or any of it's children from being searched */ - DataSource.prototype.disableFetch = function () { + DataSource.prototype.disableAutoFetch = function () { this._fetchDisabled = true; return this; }; diff --git a/src/courier/data_source/doc.js b/src/courier/data_source/doc.js index 4c101b809b642..bb25ef6b2e000 100644 --- a/src/courier/data_source/doc.js +++ b/src/courier/data_source/doc.js @@ -210,16 +210,16 @@ define(function (require) { * @param {Function} cb - callback */ DocSource.prototype._sendToEs = function (method, validateVersion, body, cb) { + cb = this._wrapcb(cb) + var source = this; var courier = this._courier; var client = courier._getClient(); - var params = { - id: this._state.id, - type: this._state.type, - index: this._state.index, - body: body, - ignore: [409] - }; + + // straight assignment will causes undefined values + var params = _.pick(this._state, 'id', 'type', 'index'); + params.body = body; + params.ignore = [409]; if (validateVersion) { params.version = source._getVersion(); diff --git a/src/kibana/apps/discover/controllers/discover.js b/src/kibana/apps/discover/controllers/discover.js new file mode 100644 index 0000000000000..ee5a349e5a07c --- /dev/null +++ b/src/kibana/apps/discover/controllers/discover.js @@ -0,0 +1,217 @@ +define(function (require) { + var _ = require('utils/mixins'); + + var settingsHtml = require('text!../partials/settings.html'); + + var app = require('modules').get('app/discover'); + + var intervals = [ + { display: '', val: null }, + { display: 'Hourly', val: 'hourly' }, + { display: 'Daily', val: 'daily' }, + { display: 'Weekly', val: 'weekly' }, + { display: 'Monthly', val: 'monthly' }, + { display: 'Yearly', val: 'yearly' } + ]; + + app.controller('discover', function ($scope, config, $q, $route, savedSearches, courier, createNotifier, $location) { + var notify = createNotifier({ + location: 'Discover' + }); + + var search = $route.current.locals.search; + if (!search) return notify.fatal('search failed to load'); + + $scope.opts = { + // number of records to fetch, then paginate through + sampleSize: 500, + // max length for summaries in the table + maxSummaryLength: 100, + // Index to match + index: 'logstash-*', + timefield: '@timestamp', + savedSearch: search + }; + + // track the initial state of the search + var searchIsPhantom = search.phantom; + $scope.opts.saveDataSource = function () { + search.save() + .then(function () { + notify.info('Saved Data Source "' + search.details.name + '"'); + if (searchIsPhantom) { + searchIsPhantom = false; + $location.url('/discover/' + search.get('id')); + } + }, notify.error); + }; + + // stores the complete list of fields + $scope.fields = null; + + // stores the fields we want to fetch + $scope.columns = null; + + // index pattern interval options + $scope.intervals = intervals; + $scope.interval = intervals[0]; + + var initialQuery = search.get('query'); + $scope.query = initialQuery ? initialQuery.query_string.query : ''; + + // the index to use when they don't specify one + config.$watch('discover.defaultIndex', function (val) { + if (!val) return config.set('discover.defaultIndex', '_all'); + if (!$scope.opts.index) { + $scope.opts.index = val; + $scope.fetch(); + } + }); + + search + .$scope($scope) + .inherits(courier.rootSearchSource) + .on('results', function (res) { + if (!$scope.fields) getFields(); + + $scope.rows = res.hits.hits; + }); + + $scope.sort = ['_score', 'desc']; + + $scope.getSort = function () { + return $scope.sort; + }; + + $scope.setSort = function (field, order) { + var sort = {}; + sort[field] = order; + search.sort([sort]); + $scope.sort = [field, order]; + $scope.fetch(); + }; + + $scope.toggleConfig = function () { + // Close if already open + if ($scope.configTemplate === settingsHtml) { + delete $scope.configTemplate; + } else { + $scope.configTemplate = settingsHtml; + } + }; + + + $scope.fetch = function () { + if (!$scope.fields) getFields(); + search + .size($scope.opts.sampleSize) + .query(!$scope.query ? null : { + query_string: { + query: $scope.query + } + }); + + if ($scope.opts.index !== search.get('index')) { + // set the index on the savedSearch + search.index($scope.opts.index); + // clear the columns and fields, then refetch when we do a search + $scope.columns = $scope.fields = null; + } + + // fetch just this savedSearch + search.fetch(); + }; + + var activeGetFields; + function getFields() { + var defer = $q.defer(); + + if (activeGetFields) { + activeGetFields.then(function () { + defer.resolve(); + }); + return; + } + + var currentState = _.transform($scope.fields || [], function (current, field) { + current[field.name] = { + display: field.display + }; + }, {}); + + search + .getFields() + .then(function (fields) { + if (!fields) return; + + $scope.fields = []; + $scope.columns = $scope.columns || []; + + // Inject source into list; + $scope.fields.push({name: '_source', type: 'source', display: false}); + + _(fields) + .keys() + .sort() + .each(function (name) { + var field = fields[name]; + field.name = name; + + _.defaults(field, currentState[name]); + $scope.fields.push(field); + }); + + + refreshColumns(); + defer.resolve(); + }, defer.reject); + + return defer.promise.then(function () { + activeGetFields = null; + }); + } + + $scope.toggleField = function (name) { + var field = _.find($scope.fields, { name: name }); + + // toggle the display property + field.display = !field.display; + + if ($scope.columns.length === 1 && $scope.columns[0] === '_source') { + $scope.columns = _.toggleInOut($scope.columns, name); + $scope.columns = _.toggleInOut($scope.columns, '_source'); + _.find($scope.fields, {name: '_source'}).display = false; + + } else { + $scope.columns = _.toggleInOut($scope.columns, name); + } + + refreshColumns(); + }; + + $scope.refreshFieldList = function () { + search.clearFieldCache(function () { + getFields(function () { + $scope.fetch(); + }); + }); + }; + + function refreshColumns() { + // Get all displayed field names; + var fields = _.pluck(_.filter($scope.fields, function (field) { + return field.display; + }), 'name'); + + // Make sure there are no columns added that aren't in the displayed field list. + $scope.columns = _.intersection($scope.columns, fields); + + // If no columns remain, use _source + if (!$scope.columns.length) { + $scope.toggleField('_source'); + } + } + + $scope.$emit('application.load'); + }); +}); \ No newline at end of file diff --git a/src/kibana/apps/discover/factories/saved_search.js b/src/kibana/apps/discover/factories/saved_search.js new file mode 100644 index 0000000000000..f8d19189293f5 --- /dev/null +++ b/src/kibana/apps/discover/factories/saved_search.js @@ -0,0 +1,116 @@ +define(function (require) { + var app = require('modules').get('app/discover'); + var bind = require('lodash').bind; + var assign = require('lodash').assign; + var nextTick = require('utils/next_tick'); + + app.factory('SavedSearch', function (configFile, courier, $q) { + + function SavedSearch(id) { + var search = courier.createSource('search'); + search._doc = courier.createSource('doc') + .index(configFile.kibanaIndex) + .type('saved_searches') + .id(id || void 0) + .on('results', function onResults(resp) { + if (!resp.found) { + search._doc.removeListener('results', onResults); + search.emit('noconfig', new Error('Unable to find that Saved Search...')); + } + + search.set(resp._source.state); + search.details = resp._source.details; + assign(search.deatils, resp._source.details); + + if (!id) { + id = resp._id; + // it's no longer a phantom + search.phantom = false; + } + + if (!search.ready()) { + search.ready(true); + // allow the search to be fetched automatically + search.enableAuthFetch(); + } + }); + + search._dynamicState.id = function () { + return search._doc.get('id'); + }; + + search.phantom = true; + search.details = { + name: '', + hits: 0 + }; + + search.ready = (function () { + var queue = id ? [] : false; + var err; + return function (cb) { + switch (typeof cb) { + // check if we are ready yet + case 'undefined': + return !queue; + + // call or queue a function once ready + case 'function': + if (queue) { + // queue will be false once complete + queue.push(cb); + } else { + // always callback async + nextTick(cb, err); + } + return; + + // indicate that we are ready, or there was a failure loading + default: + if (queue && cb) { + if (cb instanceof Error) { + err = cb; + } + + // if queued functions are confused, and ask us if + // we are ready, we should tell them yes + var fns = queue; + queue = false; + + // be sure to send out the error we got if there was one + fns.forEach(function (fn) { fn(err); }); + } + } + }; + }()); + + search.save = function () { + var defer = $q.defer(); + + search._doc.doIndex({ + details: search.details, + state: search.toJSON() + }, function (err, id) { + if (err) return defer.reject(err); + + search._doc.id(id); + defer.resolve(); + }); + + return defer.promise; + }; + + if (!id) { + // we have nothing left to load + search.ready(true); + } else { + // before this search is fetched, it's config needs to be loaded + search.disableAutoFetch(); + // get the config doc now + search._doc.fetch(); + } + return search; + } + return SavedSearch; + }); +}); \ No newline at end of file diff --git a/src/kibana/apps/discover/index.js b/src/kibana/apps/discover/index.js index 3dd0b8962f024..705b3abb34d9f 100644 --- a/src/kibana/apps/discover/index.js +++ b/src/kibana/apps/discover/index.js @@ -1,222 +1,20 @@ define(function (require, module, exports) { - var _ = require('lodash'); - require('directives/table'); require('./field_chooser'); - require('services/saved_searches'); - require('utils/mixins'); - + require('./services/saved_searches'); require('./timechart'); + require('./controllers/discover'); var app = require('modules').get('app/discover'); - var intervals = [ - { display: '', val: null }, - { display: 'Hourly', val: 'hourly' }, - { display: 'Daily', val: 'daily' }, - { display: 'Weekly', val: 'weekly' }, - { display: 'Monthly', val: 'monthly' }, - { display: 'Yearly', val: 'yearly' } - ]; - - app.controller('discover', function ($scope, config, $q, $routeParams, savedSearches, courier) { - var source; - if ($routeParams.id) { - source = savedSearches.get($routeParams.id); - } else { - source = savedSearches.create(); - } - - $scope.opts = { - // number of records to fetch, then paginate through - sampleSize: 500, - // max length for summaries in the table - maxSummaryLength: 100, - // Index to match - index: '_all', - timefield: '@timestamp' - }; - - // stores the complete list of fields - $scope.fields = null; - - // stores the fields we want to fetch - $scope.columns = null; - - // index pattern interval options - $scope.intervals = intervals; - $scope.interval = $scope.intervals[0]; - - // the index to use when they don't specify one - config.$watch('discover.defaultIndex', function (val) { - if (!val) return config.set('discover.defaultIndex', '_all'); - if (!$scope.opts.index) { - $scope.opts.index = val; - $scope.fetch(); + app.config(function ($routeProvider) { + $routeProvider.when('/discover/:id?', { + templateUrl: 'kibana/apps/discover/index.html', + resolve: { + search: function (savedSearches, $route) { + return savedSearches.get($route.current.params.id); + } } }); - - source - .$scope($scope) - .inherits(courier.rootSearchSource) - .on('results', function (res) { - if (!$scope.fields) getFields(); - - $scope.rows = res.hits.hits; - }); - - - var init = function () { - $scope.fetch(); - }; - - $scope.sort = ['_score', 'desc']; - - $scope.getSort = function () { - return $scope.sort; - }; - - $scope.setSort = function (field, order) { - var sort = {}; - sort[field] = order; - source.sort([sort]); - $scope.sort = [field, order]; - $scope.fetch(); - }; - - var setConfigTemplate = function (template) { - // Close if already open - if ($scope.configTemplate === template) { - delete $scope.configTemplate; - return; - } else { - $scope.configTemplate = template; - } - }; - - $scope.toggleConfig = function () { - setConfigTemplate(require('text!./partials/settings.html')); - /* - $scope.configSubmit = function () { - $scope.save($scope.dashboard.title); - }; - */ - }; - - - $scope.fetch = function () { - if (!$scope.fields) getFields(); - source - .size($scope.opts.sampleSize) - .query(!$scope.query ? null : { - query_string: { - query: $scope.query - } - }); - - if ($scope.opts.index !== source.get('index')) { - // set the index on the data source - source.index($scope.opts.index); - // clear the columns and fields, then refetch when we do a search - $scope.columns = $scope.fields = null; - } - - // fetch just this datasource - source.fetch(); - }; - - var activeGetFields; - function getFields() { - var defer = $q.defer(); - - if (activeGetFields) { - activeGetFields.then(function () { - defer.resolve(); - }); - return; - } - - var currentState = _.transform($scope.fields || [], function (current, field) { - current[field.name] = { - display: field.display - }; - }, {}); - - source - .getFields() - .then(function (fields) { - if (!fields) return; - - $scope.fields = []; - $scope.columns = $scope.columns || []; - - // Inject source into list; - $scope.fields.push({name: '_source', type: 'source', display: false}); - - _(fields) - .keys() - .sort() - .each(function (name) { - var field = fields[name]; - field.name = name; - - _.defaults(field, currentState[name]); - $scope.fields.push(field); - }); - - - refreshColumns(); - defer.resolve(); - }, defer.reject); - - return defer.promise.then(function () { - activeGetFields = null; - }); - } - - $scope.toggleField = function (name) { - var field = _.find($scope.fields, { name: name }); - - // toggle the display property - field.display = !field.display; - - if ($scope.columns.length === 1 && $scope.columns[0] === '_source') { - $scope.columns = _.toggleInOut($scope.columns, name); - $scope.columns = _.toggleInOut($scope.columns, '_source'); - _.find($scope.fields, {name: '_source'}).display = false; - - } else { - $scope.columns = _.toggleInOut($scope.columns, name); - } - - refreshColumns(); - }; - - $scope.refreshFieldList = function () { - source.clearFieldCache(function () { - getFields(function () { - $scope.fetch(); - }); - }); - }; - - function refreshColumns() { - // Get all displayed field names; - var fields = _.pluck(_.filter($scope.fields, function (field) { - return field.display; - }), 'name'); - - // Make sure there are no columns added that aren't in the displayed field list. - $scope.columns = _.intersection($scope.columns, fields); - - // If no columns remain, use _source - if (!$scope.columns.length) { - $scope.toggleField('_source'); - } - } - - init(); - - $scope.$emit('application.load'); }); }); \ No newline at end of file diff --git a/src/kibana/apps/discover/partials/settings.html b/src/kibana/apps/discover/partials/settings.html index 9c16b97be2330..bc3576fc86974 100644 --- a/src/kibana/apps/discover/partials/settings.html +++ b/src/kibana/apps/discover/partials/settings.html @@ -1,7 +1,19 @@ - - - - \ No newline at end of file +
+
+
+ + +
+
+
+ + +
+
+ +
+
+
+
\ No newline at end of file diff --git a/src/kibana/apps/discover/services/saved_searches.js b/src/kibana/apps/discover/services/saved_searches.js new file mode 100644 index 0000000000000..9c520219c54ec --- /dev/null +++ b/src/kibana/apps/discover/services/saved_searches.js @@ -0,0 +1,25 @@ +define(function (require) { + + var module = require('modules').get('kibana/services'); + var _ = require('lodash'); + + require('../factories/saved_search'); + + module.service('savedSearches', function (courier, configFile, $q, createNotifier, SavedSearch) { + var notify = createNotifier({ + location: 'Saved Searches' + }); + + this.get = function (id) { + var defer = $q.defer(); + var search = new SavedSearch(id); + + search.ready(function (err) { + if (err) defer.reject(err); + else defer.resolve(search); + }); + + return defer.promise; + }; + }); +}); \ No newline at end of file diff --git a/src/kibana/apps/visualize/controllers/visualize.js b/src/kibana/apps/visualize/controllers/visualize.js index 70588d921fdae..3c141ead3f425 100644 --- a/src/kibana/apps/visualize/controllers/visualize.js +++ b/src/kibana/apps/visualize/controllers/visualize.js @@ -10,55 +10,81 @@ define(function (require) { location: 'Visualize Controller' }); - // the object detailing the visualization var vis = $scope.vis = window.vis = new Vis({ - metric: { - label: 'Y-Axis', - min: 1, - max: 1 - }, - segment: { - label: 'X-Axis', - min: 1, - max: 1 - }, - group: { - label: 'Color', - max: 10 - }, - split: { - label: 'Rows & Columns', - max: 2 - } - }, { - split: [ - { - field: 'response', - size: 5, - agg: 'terms' + config: { + metric: { + label: 'Y-Axis', + min: 1, + max: 1 }, - { - field: '_type', - size: 5, - agg: 'terms' - } - ], - segment: [ - { - field: '@timestamp', - interval: 'week' - } - ], - group: [ - { - field: 'extension', - size: 5, - agg: 'terms', - global: true + segment: { + label: 'X-Axis', + min: 1, + max: 1 + }, + group: { + label: 'Color', + max: 1 + }, + split: { + label: 'Rows & Columns', + max: 2 } - ] + } }); + // the object detailing the visualization + // var vis = $scope.vis = window.vis = new Vis({ + // config: { + // metric: { + // label: 'Y-Axis', + // min: 1, + // max: 1 + // }, + // segment: { + // label: 'X-Axis', + // min: 1, + // max: 1 + // }, + // group: { + // label: 'Color', + // max: 10 + // }, + // split: { + // label: 'Rows & Columns', + // max: 2 + // } + // }, + // state: { + // split: [ + // { + // field: 'response', + // size: 5, + // agg: 'terms' + // }, + // { + // field: '_type', + // size: 5, + // agg: 'terms' + // } + // ], + // segment: [ + // { + // field: '@timestamp', + // interval: 'week' + // } + // ], + // group: [ + // { + // field: 'extension', + // size: 5, + // agg: 'terms', + // global: true + // } + // ] + // } + // }); + vis.dataSource.$scope($scope); $scope.refreshFields = function () { diff --git a/src/kibana/apps/visualize/directives/visualization.js b/src/kibana/apps/visualize/directives/visualization.js index b080eb5ee2a4b..916a8a8d55420 100644 --- a/src/kibana/apps/visualize/directives/visualization.js +++ b/src/kibana/apps/visualize/directives/visualization.js @@ -22,6 +22,8 @@ define(function (require) { // only link if the dataSource isn't already linked vis.dataSource.$scope($scope); } + + vis.dataSource.fetch(); } }; } diff --git a/src/kibana/apps/visualize/factories/vis.js b/src/kibana/apps/visualize/factories/vis.js index 3bc79127ce1e3..b81a37fe55670 100644 --- a/src/kibana/apps/visualize/factories/vis.js +++ b/src/kibana/apps/visualize/factories/vis.js @@ -9,8 +9,10 @@ define(function (require) { location: 'Visualization' }); - function Vis(config, state) { - config = config || {}; + function Vis(opts) { + opts = opts || {}; + var config = opts.config || {}; + var state = opts.state || null; // the visualization type this.type = config.type || 'histogram'; diff --git a/src/kibana/directives/table.js b/src/kibana/directives/table.js index c85983264e3a9..5f059d675539c 100644 --- a/src/kibana/directives/table.js +++ b/src/kibana/directives/table.js @@ -118,7 +118,8 @@ define(function (require) { var rendering = false; return function renderRows(rows) { - [].push.apply(queue, rows); + // overwrite the queue, don't keep old rows + queue = rows.slice(0); if (!rendering) { onTick(); } diff --git a/src/kibana/index.js b/src/kibana/index.js index b946e1223c70b..e58a578743188 100644 --- a/src/kibana/index.js +++ b/src/kibana/index.js @@ -34,6 +34,7 @@ define(function (require) { }); configFile.apps.forEach(function (app) { + if (app.id === 'discover') return; $routeProvider.when('/' + app.id, { templateUrl: 'kibana/apps/' + app.id + '/index.html' }); diff --git a/src/kibana/services/saved_searches.js b/src/kibana/services/saved_searches.js deleted file mode 100644 index 1820c3ed5b506..0000000000000 --- a/src/kibana/services/saved_searches.js +++ /dev/null @@ -1,43 +0,0 @@ -define(function (require) { - - var module = require('modules').get('kibana/services'); - - module.service('savedSearches', function (courier, configFile, $q) { - this.get = function (id) { - var docLoaded = id ? false : true; - var doc = courier.createSource('doc') - .index(configFile.kibanaIndex) - .type('saved_searches') - .id(id) - .on('results', function (doc) { - search.set(doc._source.state); - - // set the - id = doc._id; - if (!docLoaded) { - docLoaded = true; - search.enable(); - } - }); - - var search = courier.createSource('search'); - search.save = function () { - var defer = $q.defer(); - - doc.doIndex({ - state: search.toJSON() - }, function (err, id) { - if (err) return defer.reject(err); - defer.resolve(); - }); - - return defer.promise; - }; - - if (!docLoaded) search.disableFetch(); - return search; - }; - - this.create = this.get; - }); -}); \ No newline at end of file