# GG-843 Merged with ignite-961.
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/17a681c7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/17a681c7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/17a681c7 Branch: refs/heads/ignite-843 Commit: 17a681c78d87101c328ce2a139662600beb204ae Parents: 494f978 Author: Andrey <anovi...@gridgain.com> Authored: Fri Aug 21 18:03:04 2015 +0700 Committer: Andrey <anovi...@gridgain.com> Committed: Fri Aug 21 18:03:04 2015 +0700 ---------------------------------------------------------------------- examples/pom.xml | 8 + .../ignite/examples/NodeJsExamplesSelfTest.java | 94 ++++++++++ .../JettyRestProcessorAbstractSelfTest.java | 59 ++++++- .../src/main/js/controllers/sql-controller.js | 141 ++++++++------- .../src/main/js/public/stylesheets/style.scss | 69 +++++++- .../src/main/js/routes/agent.js | 21 +++ .../src/main/js/views/sql/sql.jade | 149 ++++++---------- .../processors/rest/GridRestCommand.java | 3 + .../processors/rest/GridRestProcessor.java | 3 +- .../handlers/query/QueryCommandHandler.java | 100 +++++++++-- .../rest/request/RestQueryRequest.java | 175 +++++++++++++++++++ .../rest/request/RestSqlQueryRequest.java | 125 ------------- modules/nodejs/src/main/js/apache-ignite.js | 5 +- modules/nodejs/src/main/js/cache.js | 32 +++- modules/nodejs/src/main/js/query.js | 52 ++++++ modules/nodejs/src/main/js/scan-query.js | 52 ++++++ modules/nodejs/src/main/js/server.js | 4 +- modules/nodejs/src/main/js/sql-fields-query.js | 70 +------- modules/nodejs/src/test/js/test-query.js | 51 +++++- modules/nodejs/src/test/js/test-runner.js | 4 +- .../nodejs/src/test/js/test-script-runner.js | 39 +++++ .../http/jetty/GridJettyRestHandler.java | 35 +++- 22 files changed, 888 insertions(+), 403 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/examples/pom.xml ---------------------------------------------------------------------- diff --git a/examples/pom.xml b/examples/pom.xml index 8204a36..54dc2ea 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -63,6 +63,14 @@ <dependency> <groupId>org.apache.ignite</groupId> + <artifactId>ignite-nodejs</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.ignite</groupId> <artifactId>ignite-spring</artifactId> <version>${project.version}</version> </dependency> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/examples/src/test/java/org/apache/ignite/examples/NodeJsExamplesSelfTest.java ---------------------------------------------------------------------- diff --git a/examples/src/test/java/org/apache/ignite/examples/NodeJsExamplesSelfTest.java b/examples/src/test/java/org/apache/ignite/examples/NodeJsExamplesSelfTest.java new file mode 100644 index 0000000..53f194f --- /dev/null +++ b/examples/src/test/java/org/apache/ignite/examples/NodeJsExamplesSelfTest.java @@ -0,0 +1,94 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. See the NOTICE file distributed with + * * this work for additional information regarding copyright ownership. + * * The ASF licenses this file to You under the Apache License, Version 2.0 + * * (the "License"); you may not use this file except in compliance with + * * the License. You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package org.apache.ignite.examples; + +import org.apache.ignite.configuration.*; +import org.apache.ignite.internal.*; +import org.apache.ignite.internal.util.typedef.internal.*; + +/** + * Test for nodejs examples. + */ +public class NodeJsExamplesSelfTest extends NodeJsAbstractTest { + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { + return loadConfiguration("examples/config/js/example-query.xml"); + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGrid(0); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + stopAllGrids(); + } + + /** + * @throws Exception If failed. + */ + public void testCacheApiExample() throws Exception { + run("cache-api-example.js"); + } + + /** + * @throws Exception If failed. + */ + public void testCachePutGetExample() throws Exception { + run("cache-put-get-example.js"); + } + + /** + * @throws Exception If failed. + */ + public void testQueryExample() throws Exception { + run("cache-query-example.js"); + } + + /** + * @throws Exception If failed. + */ + public void testFieldsQueryExample() throws Exception { + run("cache-sql-fields-query-example.js"); + } + + /** + * @throws Exception If failed. + */ + public void testComputeRunExample() throws Exception { + run("compute-run-example.js"); + } + + /** + * @throws Exception If failed. + */ + public void testComputeMapReduceExample() throws Exception { + run("map-reduce-example.js"); + } + + /** + * @param fileName Example file name. + * @throws Exception If failed. + */ + private void run(String fileName) throws Exception { + runJsScript(null, U.getIgniteHome() + "/examples/src/main/js/" + fileName, ">>> end"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java index 26c22af..4dc3bdc 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java @@ -27,6 +27,7 @@ import org.apache.ignite.configuration.*; import org.apache.ignite.internal.processors.json.*; import org.apache.ignite.internal.processors.rest.handlers.*; import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.lang.*; import org.apache.ignite.testframework.*; import java.io.*; @@ -1333,6 +1334,52 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro /** * @throws Exception If failed. */ + public void testQueryScan() throws Exception { + Map<String, String> params = new HashMap<>(); + params.put("cmd", GridRestCommand.EXECUTE_SCAN_QUERY.key()); + params.put("pageSize", "10"); + params.put("cacheName", "person"); + params.put("classname", ScanFilter.class.getName()); + + String ret = content(params); + + assertNotNull(ret); + assertTrue(!ret.isEmpty()); + + JSONObject json = JSONObject.fromObject(ret); + + List items = (List)((Map)json.get("response")).get("items"); + + assertEquals(2, items.size()); + + assertFalse(queryCursorFound()); + } + + /** + * @throws Exception If failed. + */ + public void testIncorrectQueryScan() throws Exception { + Map<String, String> params = new HashMap<>(); + params.put("cmd", GridRestCommand.EXECUTE_SCAN_QUERY.key()); + params.put("pageSize", "10"); + params.put("cacheName", "person"); + params.put("classname", ScanFilter.class.getName() + 1); + + String ret = content(params); + + assertNotNull(ret); + assertTrue(!ret.isEmpty()); + + JSONObject json = JSONObject.fromObject(ret); + + String err = (String)json.get("error"); + + assertTrue(err.contains("Failed to find target class")); + } + + /** + * @throws Exception If failed. + */ public void testQuery() throws Exception { grid(0).cache(null).put("1", "1"); grid(0).cache(null).put("2", "2"); @@ -1648,7 +1695,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro String qry = "salary > ? and salary <= ?"; String ret = makePostRequest(F.asMap("cmd", GridRestCommand.EXECUTE_SQL_QUERY.key(), - "type", "Person", "psz", "10", "cacheName", "person", + "type", "Person", "pageSize", "10", "cacheName", "person", "qry", URLEncoder.encode(qry)), "{\"arg\": [1000, 2000]}"); assertNotNull(ret); @@ -1775,4 +1822,14 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro return id; } } + + /** + * Test filter for scan query. + */ + public static class ScanFilter implements IgniteBiPredicate<Integer, Person> { + /** {@inheritDoc} */ + @Override public boolean apply(Integer integer, Person person) { + return person.salary > 1000; + } + } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/control-center-web/src/main/js/controllers/sql-controller.js ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/controllers/sql-controller.js b/modules/control-center-web/src/main/js/controllers/sql-controller.js index d02dec0..7a1eb49 100644 --- a/modules/control-center-web/src/main/js/controllers/sql-controller.js +++ b/modules/control-center-web/src/main/js/controllers/sql-controller.js @@ -38,9 +38,6 @@ controlCenterModule.controller('sqlController', ['$scope', '$controller', '$http $scope.notebook = notebook; $scope.notebook_name = notebook.name; - - if (notebook.paragraphs) - notebook.paragraphs = [{name: 'Query'}]; }) .error(function (errMsg) { $common.showError(errMsg); @@ -50,50 +47,63 @@ controlCenterModule.controller('sqlController', ['$scope', '$controller', '$http loadNotebook(); $scope.renameNotebook = function(name) { - $scope.notebook_edit = false; + if ($scope.notebook.name != name) { + $scope.notebook.name = name; - $scope.notebook.name = name; + $http.post('/notebooks/save', $scope.notebook) + .success(function () { + var idx = _.findIndex($scope.$root.notebooks, function (item) { + return item._id == $scope.notebook._id; + }); - $http.post('/notebooks/save', $scope.notebook) - .success(function () { - var idx = _.findIndex($scope.$root.notebooks, function (item) { - return item._id == $scope.notebook._id; - }); + if (idx >= 0) { + $scope.$root.notebooks[idx].name = name; - if (idx >= 0) { - $scope.$root.notebooks[idx].name = name; + $scope.$root.rebuildDropdown(); + } - $scope.$root.rebuildDropdown(); - } - }) - .error(function (errMsg) { - $common.showError(errMsg); - }); + $scope.notebook.edit = false; + }) + .error(function (errMsg) { + $common.showError(errMsg); + }); + } + else + $scope.notebook.edit = false }; - $scope.resetNotebookName = function() { - $scope.notebook_edit = false; + $scope.renameParagraph = function(paragraph, newName) { + if (paragraph.name != newName) { + paragraph.name = newName; - $scope.notebook_name = $scope.notebook.name; + $http.post('/notebooks/save', $scope.notebook) + .success(function () { + paragraph.edit = false; + }) + .error(function (errMsg) { + $common.showError(errMsg); + }); + } + else + paragraph.edit = false }; - $scope.addParagraph = function(notebook) { - notebook.paragraphs.push({}); - }; + $scope.addParagraph = function() { + if (!$scope.notebook.paragraphs) + $scope.notebook.paragraphs = []; - $scope.tabs = []; + var sz = $scope.notebook.paragraphs.length; - $scope.addTab = function() { - var tab = {query: "", pageSize: $scope.pageSizes[0]}; + var paragraph = {name: 'Query' + (sz ==0 ? '' : sz), editor: true, query: '', pageSize: $scope.pageSizes[0]}; if ($scope.caches.length > 0) - tab.selectedItem = $scope.caches[0]; + paragraph.cache = $scope.caches[0]; - $scope.tabs.push(tab); + $scope.notebook.paragraphs.push(paragraph); }; - $scope.removeTab = function(idx) { - $scope.tabs.splice(idx, 1); + $scope.removeParagraph = function(idx) { + $scope.notebook.splice(idx, 1); }; $http.get('/models/sql.json') @@ -113,8 +123,8 @@ controlCenterModule.controller('sqlController', ['$scope', '$controller', '$http $scope.caches = node.caches; - if ($scope.tabs.length == 0) - $scope.addTab(); + $scope.addParagraph(); + $scope.addParagraph(); }) .error(function (err, status) { $scope.caches = undefined; @@ -125,59 +135,60 @@ controlCenterModule.controller('sqlController', ['$scope', '$controller', '$http $common.showError('Receive agent error: ' + err); }); - $scope.execute = function(tab) { - $http.post('/agent/query', {query: tab.query, pageSize: tab.pageSize, cacheName: tab.selectedItem.name}) - .success(function (res) { - tab.meta = []; + var _processQueryResult = function(item) { + return function(res) { + item.meta = []; - if (res.meta) - tab.meta = res.meta; + if (res.meta) + item.meta = res.meta; - tab.page = 1; + item.page = 1; - tab.total = 0; + item.total = 0; - tab.queryId = res.queryId; + item.queryId = res.queryId; - tab.rows = res.rows; - }) + item.rows = res.rows; + + item.result = 'table'; + } + }; + + $scope.execute = function(item) { + $http.post('/agent/query', {query: item.query, pageSize: item.pageSize, cacheName: item.cache.name}) + .success(_processQueryResult(item)) .error(function (errMsg) { $common.showError(errMsg); }); }; - $scope.explain = function(tab) { - $http.post('/agent/query', {query: 'EXPLAIN ' + tab.query, pageSize: tab.pageSize, cacheName: tab.selectedItem.name}) - .success(function (res) { - tab.meta = []; - - if (res.meta) - tab.meta = res.meta; - - tab.page = 1; - - tab.total = 0; - - tab.queryId = res.queryId; + $scope.explain = function(item) { + $http.post('/agent/query', {query: 'EXPLAIN ' + item.query, pageSize: item.pageSize, cacheName: item.cache.name}) + .success(_processQueryResult) + .error(function (errMsg) { + $common.showError(errMsg); + }); + }; - tab.rows = res.rows; - }) + $scope.scan = function(item) { + $http.post('/agent/scan', {pageSize: item.pageSize, cacheName: item.cache.name}) + .success(_processQueryResult(item)) .error(function (errMsg) { $common.showError(errMsg); }); }; - $scope.nextPage = function(tab) { - $http.post('/agent/query/fetch', {queryId: tab.queryId, pageSize: tab.pageSize, cacheName: tab.selectedItem.name}) + $scope.nextPage = function(item) { + $http.post('/agent/query/fetch', {queryId: item.queryId, pageSize: item.pageSize, cacheName: item.cache.name}) .success(function (res) { - tab.page++; + item.page++; - tab.total += tab.rows.length; + item.total += item.rows.length; - tab.rows = res.rows; + item.rows = res.rows; if (res.last) - delete tab.queryId; + delete item.queryId; }) .error(function (errMsg) { $common.showError(errMsg); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/control-center-web/src/main/js/public/stylesheets/style.scss ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/public/stylesheets/style.scss b/modules/control-center-web/src/main/js/public/stylesheets/style.scss index e42e91f..1ebb373 100644 --- a/modules/control-center-web/src/main/js/public/stylesheets/style.scss +++ b/modules/control-center-web/src/main/js/public/stylesheets/style.scss @@ -15,6 +15,8 @@ * limitations under the License. */ +@import "../../node_modules/bootstrap-sass/assets/stylesheets/bootstrap"; + $logo-path: "https://www.filepicker.io/api/file/QagunjDGRFul2JgNCAli"; $input-height: 28px; $ignite-red: #ec1c24; @@ -675,6 +677,12 @@ button .caret, .btn .caret { height: $input-height; } +.sql-name-input { + @extend .form-control; + + width: auto; +} + .form-control { @extend .base-control; @@ -685,12 +693,36 @@ button .caret, .btn .caret { } } -.form-control-h1 { - @extend .form-control; +.theme-line .notebook-header { + color: black; + border-color: #eee; - width: auto; font-size: 22px; + line-height: 44px; height: 44px; + + h1 { + padding: 0; + line-height: 44px; + height: 44px; + margin: 0; + } + + i { + line-height: 44px; + height: 44px; + font-size: 14px; + } + + input { + font-size: 22px; + line-height: 44px; + height: 44px; + } +} + +.theme-line .paragraph-header { + } .line-control { @@ -703,11 +735,25 @@ button .caret, .btn .caret { h3 { margin-bottom: 0; + + .result { + float: right; + i { + font-size: 14px; + line-height: 14px; + } + } } h3 > a { color: black; } + + i { + font-size: 14px; + } + + } .theme-line .panel-body { @@ -859,6 +905,23 @@ button .caret, .btn .caret { line-height: $input-height; } + + tfoot > tr > td { + padding: 0; + + .pagination { + margin: 10px 0 0 0; + + > .active > a { + color: $ignite-red; + font-weight: bold; + border-color: #ddd; + background-color: #eee; + } + } + } + + margin: 0; } .panel-title a { http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/control-center-web/src/main/js/routes/agent.js ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/routes/agent.js b/modules/control-center-web/src/main/js/routes/agent.js index d0fba45..4b23b2e 100644 --- a/modules/control-center-web/src/main/js/routes/agent.js +++ b/modules/control-center-web/src/main/js/routes/agent.js @@ -20,6 +20,7 @@ var agentManager = require('../agents/agent-manager'); var apacheIgnite = require('apache-ignite'); var SqlFieldsQuery = apacheIgnite.SqlFieldsQuery; +var ScanQuery = apacheIgnite.ScanQuery; function _client(req, res) { var client = agentManager.getAgentManager().findClient(req.currentUserId()); @@ -77,6 +78,26 @@ router.post('/query', function (req, res) { } }); +/* Execute query. */ +router.post('/scan', function (req, res) { + var client = _client(req, res); + + if (client) { + // Create sql query. + var qry = new ScanQuery(); + + // Set page size for query. + qry.setPageSize(req.body.pageSize); + + // Get query cursor. + client.ignite().cache(req.body.cacheName).query(qry).nextPage().then(function (cursor) { + res.json({meta: cursor.fieldsMetadata(), rows: cursor.page(), queryId: cursor.queryId()}); + }, function (err) { + res.status(500).send(err); + }); + } +}); + /* Get next query page. */ router.post('/query/fetch', function (req, res) { var client = _client(req, res); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/control-center-web/src/main/js/views/sql/sql.jade ---------------------------------------------------------------------- diff --git a/modules/control-center-web/src/main/js/views/sql/sql.jade b/modules/control-center-web/src/main/js/views/sql/sql.jade index aa770ae..e49e3ad 100644 --- a/modules/control-center-web/src/main/js/views/sql/sql.jade +++ b/modules/control-center-web/src/main/js/views/sql/sql.jade @@ -25,34 +25,46 @@ block container .row .col-sm-12(ng-init='noteId = "#{noteId}";') .docs-content(ng-controller='sqlController' ) - .docs-header - h1 - a(ng-hide='notebook_edit' ng-click='notebook_edit = true;' style='line-height: 44px;') {{notebook.name}} - div(ng-show='notebook_edit') - input.form-control-h1(ng-model='notebook_name' on-enter='renameNotebook(notebook_name)' on-escape='resetNotebookName()') + .docs-header.notebook-header + h1.col-sm-6(ng-hide='notebook.edit') + a {{notebook.name}} + i.fa.fa-pencil.tipLabel(ng-click='notebook.edit = true;notebook.edit_name = notebook.name' bs-tooltip data-title='Rename notebook' data-trigger='hover') + h1.col-sm-6(ng-show='notebook.edit') + input.sql-name-input(ng-model='notebook.edit_name' on-enter='renameNotebook(notebook.edit_name)' on-escape='notebook.edit = false;') + i.tipLabel.fa.fa-floppy-o(ng-click='renameNotebook(notebook.edit_name)' bs-tooltip data-title='Save notebook name' data-trigger='hover') + h1.col-sm-6 + i.tipField.fa.fa-plus(ng-click='addParagraph()' bs-tooltip data-title='Add new paragraph' data-trigger='hover') + .docs-body(style='margin-top: 20px;') hr - .docs-body - .panel-group(bs-collapse ng-model='notebook.activeIdx') + .panel-group(bs-collapse ng-model='notebook.activeIdx' data-allow-multiple='true' data-start-collapsed='false') .panel.panel-default(ng-repeat='paragraph in notebook.paragraphs') .panel-heading - h3 + h3(ng-hide='paragraph.edit') a(bs-collapse-toggle ng-click='hidePopover()') {{paragraph.name}} + i.fa.fa-pencil.tipLabel(ng-click='paragraph.edit = true; paragraph.edit_name = paragraph.name;' bs-tooltip data-title='Rename paragraph' data-trigger='hover') + .result.btn-group(ng-model='paragraph.result') + i.btn.btn-default.fa.fa-table(ng-click='paragraph.result="table"' bs-tooltip data-title='Show table' data-trigger='hover') + i.btn.btn-default.fa.fa-bar-chart(ng-click='paragraph.result="bar"' bs-tooltip data-title='Show bar chart' data-trigger='hover') + h3(ng-show='paragraph.edit') + input.sql-name-input(ng-model='paragraph.edit_name' on-enter='renameParagraph(paragraph, paragraph.edit_name)' on-escape='paragraph.edit = false;') + i.tipLabel.fa.fa-floppy-o(ng-click='renameParagraph(paragraph, paragraph.edit_name)' bs-tooltip data-title='Save paragraph name' data-trigger='hover') .panel-collapse(role='tabpanel' bs-collapse-target) - .panel-body + .panel-body(ng-show='paragraph.editor') .row .col-xs-8.col-sm-9(style='border-right: 1px solid #eee') div(style='height: 200px' ui-ace='{ theme: "chrome", mode: "sql",' + 'require: ["ace/ext/language_tools"],' + 'rendererOptions: {showPrintMargin: false, highlightGutterLine: false, fontSize: 14},' + - 'advanced: {enableSnippets: false, enableBasicAutocompletion: true, enableLiveAutocompletion: true}}' ng-model='paragraph.query') + 'advanced: {enableSnippets: false, enableBasicAutocompletion: true, enableLiveAutocompletion: true}}' ng-model='paragraph.query' + ng-class='{"disable": paragraph.status == "RUNNING" || paragraph.status == "PENDING" }') .col-xs-4.col-sm-3 div(ng-hide='caches.length == 0' style='margin-top: 0.65em') lable.labelHeader Caches: table.links(st-table='caches') tbody tr(ng-repeat='cache in caches track by cache.name') - td.col-sm-6(ng-class='{active: cache.name == paragraph.activeCache.name}') - a(ng-click='paragraph.activeCache = row') {{$index + 1}}) {{::cache.name}}, {{::cache.mode}} + td.col-sm-6(ng-class='{active: cache.name == paragraph.cache.name}') + a(ng-click='paragraph.cache = cache') {{$index + 1}}) {{::cache.name}}, {{::cache.mode}} hr(style='margin: 0') .settings-row label Page Size: @@ -61,90 +73,29 @@ block container button.btn.btn-primary(ng-click='explain(paragraph)') Explain button.btn.btn-primary(ng-click='execute(paragraph)') Execute button.btn.btn-primary(ng-click='scan(paragraph)') Scan - - // div(ng-show='#{tab}.rows.length > 0' style='margin-top: 0.65em') - // hr - // div - // table.table.table-striped.col-sm-12.sql-results(st-table='displayedCollection' st-safe-src='#{tab}.rows') - // thead - // tr(style='border-size: 0') - // td(colspan='{{#{tab}.meta.length}}') - // .col-sm-8 - // lable Page #: - // b {{#{tab}.page}} - // | Results: - // b {{#{tab}.rows.length + #{tab}.total}} - // .col-sm-4 - // button.btn.btn-primary.fieldButton(ng-click='nextPage(#{tab})' ng-disabled='!#{tab}.queryId') Next page - // //.input-tip - // // input.form-control(st-search placeholder='Filter...' type='search') - // tr - // th(ng-repeat='col in #{tab}.meta track by $index' st-sort='getter' data-ng-bind='::col.fieldName' bs-tooltip='col.schemaName + "." + col.typeName + "." + col.fieldName') - // tbody - // //tr - // // td(colspan='{{#{tab}.cols.length}}') - // // .loading-indicator - // tr(ng-repeat='row in displayedCollection track by $index') - // td(ng-repeat='val in row track by $index') {{ val }} - // - // - // - //div(ng-if='!caches') - // .block-callout-right.margin-bottom-dflt(style='width: 100%') - // p(ng-bind-html='joinTip(missingClientTip)') - //div(ng-if='caches') - // .block-callout-parent.block-callout-border.margin-bottom-dflt - // .block-callout - // p(ng-bind-html='joinTip(screenTip)') - // - // - var tab = 'tabs[tabs.activeIdx]' - // - // .tabs-below(bs-tabs bs-active-pane='tabs.activeIdx' data-template='/tab') - // div(ng-repeat='tab in tabs' title='Query' bs-pane) - // .row - // .col-xs-8.col-sm-9(style='border-right: 1px solid #eee') - // div(style='height: 200px' ui-ace='{ theme: "chrome", mode: "sql",' + - // 'require: ["ace/ext/language_tools"],' + - // 'rendererOptions: {showPrintMargin: false, highlightGutterLine: false, fontSize: 14},' + - // 'advanced: {enableSnippets: false, enableBasicAutocompletion: true, enableLiveAutocompletion: true}}' ng-model='#{tab}.query') - // .col-xs-4.col-sm-3 - // div(ng-hide='caches.length == 0' style='margin-top: 0.65em') - // lable.labelHeader Caches: - // table.links(st-table='caches') - // tbody - // tr(ng-repeat='row in caches track by row.name') - // td.col-sm-6(ng-class='{active: row.name == #{tab}.selectedItem.name}') - // a(ng-click='#{tab}.selectedItem = row') {{$index + 1}}) {{::row.name}}, {{::row.mode}} - // hr(style='margin: 0') - // .settings-row - // label Page Size: - // button.btn.btn-default.base-control(ng-model='#{tab}.pageSize' bs-options='item for item in pageSizes' bs-select) - // .settings-row - // button.btn.btn-primary(ng-click='explain(#{tab})') Explain - // button.btn.btn-primary(ng-click='execute(#{tab})') Execute - // button.btn.btn-primary(ng-click='scan(#{tab})' disabled) Scan - // - // div(ng-show='#{tab}.rows.length > 0' style='margin-top: 0.65em') - // hr - // div - // table.table.table-striped.col-sm-12.sql-results(st-table='displayedCollection' st-safe-src='#{tab}.rows') - // thead - // tr(style='border-size: 0') - // td(colspan='{{#{tab}.meta.length}}') - // .col-sm-8 - // lable Page #: - // b {{#{tab}.page}} - // | Results: - // b {{#{tab}.rows.length + #{tab}.total}} - // .col-sm-4 - // button.btn.btn-primary.fieldButton(ng-click='nextPage(#{tab})' ng-disabled='!#{tab}.queryId') Next page - // //.input-tip - // // input.form-control(st-search placeholder='Filter...' type='search') - // tr - // th(ng-repeat='col in #{tab}.meta track by $index' st-sort='getter' data-ng-bind='::col.fieldName' bs-tooltip='col.schemaName + "." + col.typeName + "." + col.fieldName') - // tbody - // //tr - // // td(colspan='{{#{tab}.cols.length}}') - // // .loading-indicator - // tr(ng-repeat='row in displayedCollection track by $index') - // td(ng-repeat='val in row track by $index') {{ val }} + .panel-body(ng-show='paragraph.result == "table') + table.table.table-striped.col-sm-12.sql-results(st-table='displayedCollection' st-safe-src='paragraph.rows') + thead + tr(style='border-size: 0') + td(colspan='{{paragraph.meta.length}}') + .col-sm-8 + lable Page #: + b {{paragraph.page}} + | Results: + b {{paragraph.rows.length + paragraph.total}} + .col-sm-4 + button.btn.btn-primary.fieldButton(ng-click='nextPage(paragraph)' ng-disabled='!paragraph.queryId') Next page + //.input-tip + // input.form-control(st-search placeholder='Filter...' type='search') + tr + th(ng-repeat='col in paragraph.meta track by $index' st-sort='getter' data-ng-bind='::col.fieldName' bs-tooltip='col.schemaName + "." + col.typeName + "." + col.fieldName') + tbody + //tr + // td(colspan='{{#{tab}.cols.length}}') + // .loading-indicator + tr(ng-repeat='row in displayedCollection track by $index') + td(ng-repeat='val in row track by $index') {{ val }} + tfoot + tr + td.text-right(colspan='{{paragraph.meta.length}}') + div(st-pagination st-items-by-page='10' st-displayed-pages='5') http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestCommand.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestCommand.java index d28119a..cabe5fd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestCommand.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestCommand.java @@ -153,6 +153,9 @@ public enum GridRestCommand { /** Execute sql fields query. */ EXECUTE_SQL_FIELDS_QUERY("qryfldexe"), + /** Execute scan query. */ + EXECUTE_SCAN_QUERY("qryscanexe"), + /** Fetch query results. */ FETCH_SQL_QUERY("qryfetch"), http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java index 5937c14..ccf4d47 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java @@ -540,10 +540,11 @@ public class GridRestProcessor extends GridProcessorAdapter { case EXECUTE_SQL_QUERY: case EXECUTE_SQL_FIELDS_QUERY: + case EXECUTE_SCAN_QUERY: case CLOSE_SQL_QUERY: case FETCH_SQL_QUERY: perm = SecurityPermission.CACHE_READ; - name = ((RestSqlQueryRequest)req).cacheName(); + name = ((RestQueryRequest)req).cacheName(); break; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java index 43ecc0c..e121b23 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/query/QueryCommandHandler.java @@ -29,6 +29,7 @@ import org.apache.ignite.internal.util.future.*; import org.apache.ignite.internal.util.typedef.internal.*; import org.apache.ignite.lang.*; +import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -42,6 +43,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { /** Supported commands. */ private static final Collection<GridRestCommand> SUPPORTED_COMMANDS = U.sealList(EXECUTE_SQL_QUERY, EXECUTE_SQL_FIELDS_QUERY, + EXECUTE_SCAN_QUERY, FETCH_SQL_QUERY, CLOSE_SQL_QUERY); @@ -68,23 +70,24 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { assert req != null; assert SUPPORTED_COMMANDS.contains(req.command()); - assert req instanceof RestSqlQueryRequest : "Invalid type of query request."; + assert req instanceof RestQueryRequest : "Invalid type of query request."; switch (req.command()) { case EXECUTE_SQL_QUERY: - case EXECUTE_SQL_FIELDS_QUERY: { + case EXECUTE_SQL_FIELDS_QUERY: + case EXECUTE_SCAN_QUERY: { return ctx.closure().callLocalSafe( - new ExecuteQueryCallable(ctx, (RestSqlQueryRequest)req, qryCurs), false); + new ExecuteQueryCallable(ctx, (RestQueryRequest)req, qryCurs), false); } case FETCH_SQL_QUERY: { return ctx.closure().callLocalSafe( - new FetchQueryCallable(ctx, (RestSqlQueryRequest)req, qryCurs), false); + new FetchQueryCallable(ctx, (RestQueryRequest)req, qryCurs), false); } case CLOSE_SQL_QUERY: { return ctx.closure().callLocalSafe( - new CloseQueryCallable((RestSqlQueryRequest)req, qryCurs), false); + new CloseQueryCallable((RestQueryRequest)req, qryCurs), false); } } @@ -99,7 +102,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { private GridKernalContext ctx; /** Execute query request. */ - private RestSqlQueryRequest req; + private RestQueryRequest req; /** Queries cursors. */ private ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs; @@ -109,7 +112,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { * @param req Execute query request. * @param qryCurs Queries cursors. */ - public ExecuteQueryCallable(GridKernalContext ctx, RestSqlQueryRequest req, + public ExecuteQueryCallable(GridKernalContext ctx, RestQueryRequest req, ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs) { this.ctx = ctx; this.req = req; @@ -123,15 +126,33 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { try { Query qry; - if (req.typeName() != null) { - qry = new SqlQuery(req.typeName(), req.sqlQuery()); + switch (req.queryType()) { + case SQL: + qry = new SqlQuery(req.typeName(), req.sqlQuery()); - ((SqlQuery)qry).setArgs(req.arguments()); - } - else { - qry = new SqlFieldsQuery(req.sqlQuery()); + ((SqlQuery)qry).setArgs(req.arguments()); + + break; + + case SQL_FIELDS: + qry = new SqlFieldsQuery(req.sqlQuery()); + + ((SqlFieldsQuery)qry).setArgs(req.arguments()); + + break; + + case SCAN: + IgniteBiPredicate pred = null; - ((SqlFieldsQuery)qry).setArgs(req.arguments()); + if (req.className() != null) + pred = instance(IgniteBiPredicate.class, req.className()); + + qry = new ScanQuery(pred); + + break; + + default: + throw new IgniteException("Incorrect query type [type=" + req.queryType() + "]"); } IgniteCache<Object, Object> cache = ctx.grid().cache(req.cacheName()); @@ -182,7 +203,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { */ private static class CloseQueryCallable implements Callable<GridRestResponse> { /** Execute query request. */ - private RestSqlQueryRequest req; + private RestQueryRequest req; /** Queries cursors. */ private final ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs; @@ -191,7 +212,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { * @param req Execute query request. * @param qryCurs Queries cursors. */ - public CloseQueryCallable(RestSqlQueryRequest req, + public CloseQueryCallable(RestQueryRequest req, ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs) { this.req = req; this.qryCurs = qryCurs; @@ -225,7 +246,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { */ private static class FetchQueryCallable implements Callable<GridRestResponse> { /** Execute query request. */ - private RestSqlQueryRequest req; + private RestQueryRequest req; /** Queries cursors. */ private final ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs; @@ -238,7 +259,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { * @param req Execute query request. * @param qryCurs Queries cursors. */ - public FetchQueryCallable(GridKernalContext ctx, RestSqlQueryRequest req, + public FetchQueryCallable(GridKernalContext ctx, RestQueryRequest req, ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs) { this.ctx = ctx; this.req = req; @@ -276,7 +297,7 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { */ private static CacheQueryResult createQueryResult( ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs, - Iterator cur, RestSqlQueryRequest req, Long qryId, GridKernalContext ctx) { + Iterator cur, RestQueryRequest req, Long qryId, GridKernalContext ctx) { CacheQueryResult res = new CacheQueryResult(); List<Object> items = new ArrayList<>(); @@ -295,4 +316,45 @@ public class QueryCommandHandler extends GridRestCommandHandlerAdapter { return res; } + + /** + * Creates class instance. + * + * @param cls Target class. + * @param clsName Implementing class name. + * @return Class instance. + * @throws IgniteException If failed. + */ + private static <T> T instance(Class<? extends T> cls, String clsName) throws IgniteException { + try { + Class<?> implCls = Class.forName(clsName); + + if (!cls.isAssignableFrom(implCls)) + throw new IgniteException("Failed to create instance (target class does not extend or implement " + + "required class or interface) [cls=" + cls.getName() + ", clsName=" + clsName + ']'); + + Constructor<?> ctor = implCls.getConstructor(); + + return (T)ctor.newInstance(); + } + catch (ClassNotFoundException e) { + throw new IgniteException("Failed to find target class: " + clsName, e); + } + catch (NoSuchMethodException e) { + throw new IgniteException("Failed to find constructor for provided arguments " + + "[clsName=" + clsName + ']', e); + } + catch (InstantiationException e) { + throw new IgniteException("Failed to instantiate target class " + + "[clsName=" + clsName + ']', e); + } + catch (IllegalAccessException e) { + throw new IgniteException("Failed to instantiate class (constructor is not available) " + + "[clsName=" + clsName + ']', e); + } + catch (InvocationTargetException e) { + throw new IgniteException("Failed to instantiate class (constructor threw an exception) " + + "[clsName=" + clsName + ']', e.getCause()); + } + } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestQueryRequest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestQueryRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestQueryRequest.java new file mode 100644 index 0000000..a719776 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestQueryRequest.java @@ -0,0 +1,175 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. See the NOTICE file distributed with + * * this work for additional information regarding copyright ownership. + * * The ASF licenses this file to You under the Apache License, Version 2.0 + * * (the "License"); you may not use this file except in compliance with + * * the License. You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package org.apache.ignite.internal.processors.rest.request; + +/** + * Sql query request. + */ +public class RestQueryRequest extends GridRestRequest { + /** Sql query. */ + private String sqlQry; + + /** Sql query arguments. */ + private Object[] args; + + /** Page size. */ + private Integer pageSize; + + /** Cache name. */ + private String cacheName; + + /** Query id. */ + private Long qryId; + + /** Query type name. */ + private String typeName; + + /** Predicate class name for scan query. */ + private String className; + + /** Query type. */ + private QueryType type; + + /** + * @param sqlQry Sql query. + */ + public void sqlQuery(String sqlQry) { + this.sqlQry = sqlQry; + } + + /** + * @return Sql query. + */ + public String sqlQuery() { + return sqlQry; + } + + /** + * @param args Sql query arguments. + */ + public void arguments(Object[] args) { + this.args = args; + } + + /** + * @return Sql query arguments. + */ + public Object[] arguments() { + return args; + } + + /** + * @param pageSize Page size. + */ + public void pageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + /** + * @return Page size. + */ + public int pageSize() { + return pageSize; + } + + /** + * @param cacheName Cache name. + */ + public void cacheName(String cacheName) { + this.cacheName = cacheName; + } + + /** + * @return Cache name. + */ + public String cacheName() { + return cacheName; + } + + /** + * @param id Query id. + */ + public void queryId(Long id) { + this.qryId = id; + } + + /** + * @return Query id. + */ + public Long queryId() { + return qryId; + } + + /** + * @param typeName Query type name. + */ + public void typeName(String typeName) { + this.typeName = typeName; + } + + /** + * @return Query type name. + */ + public String typeName() { + return typeName; + } + + /** + * @return Predicate class name for scan query. + */ + public String className() { + return className; + } + + /** + * @param className Predicate class name for scan query. + */ + public void className(String className) { + this.className = className; + } + + /** + * @param type Query type. + */ + public void queryType(QueryType type) { + this.type = type; + } + + /** + * @return Query type. + */ + public QueryType queryType() { + return type; + } + + /** + * Supported query types. + */ + public enum QueryType { + /** Sql query. */ + SQL, + + /** Sql fields query. */ + SQL_FIELDS, + + /** Scan query. */ + SCAN + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestSqlQueryRequest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestSqlQueryRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestSqlQueryRequest.java deleted file mode 100644 index 5ba3a50..0000000 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/request/RestSqlQueryRequest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.internal.processors.rest.request; - -/** - * Sql query request. - */ -public class RestSqlQueryRequest extends GridRestRequest { - /** Sql query. */ - private String sqlQry; - - /** Sql query arguments. */ - private Object[] args; - - /** Page size. */ - private Integer pageSize; - - /** Cache name. */ - private String cacheName; - - /** Query id. */ - private Long qryId; - - /** Query type name. */ - private String typeName; - - /** - * @param sqlQry Sql query. - */ - public void sqlQuery(String sqlQry) { - this.sqlQry = sqlQry; - } - - /** - * @return Sql query. - */ - public String sqlQuery() { - return sqlQry; - } - - /** - * @param args Sql query arguments. - */ - public void arguments(Object[] args) { - this.args = args; - } - - /** - * @return Sql query arguments. - */ - public Object[] arguments() { - return args; - } - - /** - * @param pageSize Page size. - */ - public void pageSize(Integer pageSize) { - this.pageSize = pageSize; - } - - /** - * @return Page size. - */ - public int pageSize() { - return pageSize; - } - - /** - * @param cacheName Cache name. - */ - public void cacheName(String cacheName) { - this.cacheName = cacheName; - } - - /** - * @return Cache name. - */ - public String cacheName() { - return cacheName; - } - - /** - * @param id Query id. - */ - public void queryId(Long id) { - this.qryId = id; - } - - /** - * @return Query id. - */ - public Long queryId() { - return qryId; - } - - /** - * @param typeName Query type name. - */ - public void typeName(String typeName) { - this.typeName = typeName; - } - - /** - * @return Query type name. - */ - public String typeName() { - return typeName; - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/nodejs/src/main/js/apache-ignite.js ---------------------------------------------------------------------- diff --git a/modules/nodejs/src/main/js/apache-ignite.js b/modules/nodejs/src/main/js/apache-ignite.js index 053b88a..5c54c33 100644 --- a/modules/nodejs/src/main/js/apache-ignite.js +++ b/modules/nodejs/src/main/js/apache-ignite.js @@ -22,5 +22,6 @@ module.exports = { Ignite : require('./ignite.js').Ignite, Compute : require('./compute.js').Compute, SqlQuery : require('./sql-query.js').SqlQuery, - SqlFieldsQuery : require('./sql-fields-query.js').SqlFieldsQuery -} \ No newline at end of file + SqlFieldsQuery : require('./sql-fields-query.js').SqlFieldsQuery, + ScanQuery : require('./scan-query.js').ScanQuery +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/nodejs/src/main/js/cache.js ---------------------------------------------------------------------- diff --git a/modules/nodejs/src/main/js/cache.js b/modules/nodejs/src/main/js/cache.js index 7c04843..0a6dae2 100644 --- a/modules/nodejs/src/main/js/cache.js +++ b/modules/nodejs/src/main/js/cache.js @@ -274,7 +274,7 @@ Cache.prototype.metadata = function(callback) { /** * Execute sql query * - * @param {SqlQuery|SqlFieldsQuery} qry Query + * @param {SqlQuery|SqlFieldsQuery|ScanQuery} qry Query * @returns {QueryCursor} Cursor for current query. */ Cache.prototype.query = function(qry) { @@ -308,7 +308,7 @@ Cache.prototype._createCommand = function(name) { * @constructor * @this {QueryCursor} * @param {Cache} cache Cache that runs query - * @param {SqlQuery|SqlFieldsQuery} qry Sql query + * @param {SqlQuery|SqlFieldsQuery|ScanQuery} qry Sql query * @param {boolean} init True if query is not started * @param {Object[]} res Current page result * @param fieldsMeta Fields metadata. @@ -485,17 +485,23 @@ QueryCursor.prototype.isFinished = function() { QueryCursor.prototype._getQueryCommand = function() { if (this._init) { + this._init = false; + if (this._qry.type() === "Sql") { return this._sqlQuery(this._qry); } + else if (this._qry.type() == "SqlFields") { + return this._sqlFieldsQuery(this._qry); + } + else if (this._qry.type() == "Scan") { + return this._scanQuery(this._qry); + } - this._init = false; - - return this._sqlFieldsQuery(this._qry); + return null; } return this._cache._createCommand("qryfetch").addParam("qryId", this._res.queryId). - addParam("psz", this._qry.pageSize()); + addParam("pageSize", this._qry.pageSize()); } QueryCursor.prototype._sqlFieldsQuery = function(qry) { @@ -508,9 +514,19 @@ QueryCursor.prototype._sqlQuery = function(qry) { setPostData(JSON.stringify({"arg" : qry.arguments()})); } +QueryCursor.prototype._scanQuery = function(qry) { + var cmd = new Command("qryscanexe").addParam("cacheName", this._cache._cacheName). + addParam("pageSize", qry.pageSize()); + + if (qry.filterClassName() != null) + cmd.addParam("classname", qry.filterClassName()); + + return cmd; +} + QueryCursor.prototype._createQueryCommand = function(name, qry) { return new Command(name).addParam("cacheName", this._cache._cacheName). - addParam("qry", qry.query()).addParam("psz", qry.pageSize()); + addParam("qry", qry.query()).addParam("pageSize", qry.pageSize()); } /** @@ -524,4 +540,4 @@ function CacheEntry(key0, val0) { } exports.Cache = Cache -exports.CacheEntry = CacheEntry \ No newline at end of file +exports.CacheEntry = CacheEntry http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/nodejs/src/main/js/query.js ---------------------------------------------------------------------- diff --git a/modules/nodejs/src/main/js/query.js b/modules/nodejs/src/main/js/query.js new file mode 100644 index 0000000..221dd76 --- /dev/null +++ b/modules/nodejs/src/main/js/query.js @@ -0,0 +1,52 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. See the NOTICE file distributed with + * * this work for additional information regarding copyright ownership. + * * The ASF licenses this file to You under the Apache License, Version 2.0 + * * (the "License"); you may not use this file except in compliance with + * * the License. You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +/** + * @this {Query} + */ +function Query() { + this._qryType = ""; + this._pageSz = 1; +} + +/** + * @this {Query} + * @param {int} pageSz Page size. + */ +Query.prototype.setPageSize = function(pageSz) { + this._pageSz = pageSz; +} + +/** + * @this {Query} + * @returns pageSize + */ +Query.prototype.pageSize = function() { + return this._pageSz; +} + +/** + * @this {Query} + * @returns "SqlFields" + */ +Query.prototype.type = function() { + return this._qryType; +} + +exports.Query = Query; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/nodejs/src/main/js/scan-query.js ---------------------------------------------------------------------- diff --git a/modules/nodejs/src/main/js/scan-query.js b/modules/nodejs/src/main/js/scan-query.js new file mode 100644 index 0000000..1e211c2 --- /dev/null +++ b/modules/nodejs/src/main/js/scan-query.js @@ -0,0 +1,52 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. See the NOTICE file distributed with + * * this work for additional information regarding copyright ownership. + * * The ASF licenses this file to You under the Apache License, Version 2.0 + * * (the "License"); you may not use this file except in compliance with + * * the License. You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +var Query = require("./query").Query + +/** + * @this {ScanQuery} + */ +function ScanQuery() { + Query.apply(this, arguments); + this._className = null; + this._qryType = "Scan"; +} + +ScanQuery.prototype = Query.prototype; + +ScanQuery.prototype.constructor = ScanQuery; + + +/** + * @this {ScanQuery} + * @param type Filter class name + */ +ScanQuery.prototype.setFilterClassName = function(className) { + this._className = className; +} + +/** + * @this {ScanQuery} + * @returns Filter class name + */ +ScanQuery.prototype.filterClassName = function() { + return this._className; +} + +exports.ScanQuery = ScanQuery; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/nodejs/src/main/js/server.js ---------------------------------------------------------------------- diff --git a/modules/nodejs/src/main/js/server.js b/modules/nodejs/src/main/js/server.js index 7fa22b1..b81073c 100644 --- a/modules/nodejs/src/main/js/server.js +++ b/modules/nodejs/src/main/js/server.js @@ -86,8 +86,6 @@ Server.prototype.runCommand = function(cmd, callback) { }); response.on('end', function () { - //console.log("Full response:" + fullResponseString); - if (response.statusCode !== 200) { if (response.statusCode === 401) { callback.call(null, "Authentication failed. Status code 401."); @@ -250,4 +248,4 @@ Command.prototype._isPost = function() { } exports.Server = Server; -exports.Command = Command; \ No newline at end of file +exports.Command = Command; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/nodejs/src/main/js/sql-fields-query.js ---------------------------------------------------------------------- diff --git a/modules/nodejs/src/main/js/sql-fields-query.js b/modules/nodejs/src/main/js/sql-fields-query.js index edc9f4c..36615a1 100644 --- a/modules/nodejs/src/main/js/sql-fields-query.js +++ b/modules/nodejs/src/main/js/sql-fields-query.js @@ -15,65 +15,23 @@ * limitations under the License. */ +var Query = require("./query").Query + /** * @this {SqlFieldsQuery} * @param {string} Sql query */ function SqlFieldsQuery(sql) { + Query.apply(this, arguments); this._qryType = "SqlFields"; this._sql = sql; this._arg = []; this._pageSz = 1; - this._type = null; - this._endFunc = function(err) {console.log("Empty end function is called [err=" + err + "]")}; - this._pageFunc = function(res) {console.log("Empty page function is called [res=" + res + "]")} -} - -/** - * Set the callbacks for query events. - * - * @this {SqlFieldsQuery} - * @param {string} code Function code could be "end", "page" - * @param function Functions "end" and "page" are one argument functions. - */ -SqlFieldsQuery.prototype.on = function(code, f) { - switch(code) { - case "end": - this._endFunc = f; - - break; - case "page": - this._pageFunc = f; - - break; - default : - throw "Sql do not have method " + code; - } -} - -/** - * @this {SqlFieldsQuery} - * @param res Query result - */ -SqlFieldsQuery.prototype.end = function(err) { - this._endFunc(err); } -/** - * @this {SqlFieldsQuery} - * @param res Query data - */ -SqlFieldsQuery.prototype.page = function(res) { - this._pageFunc(res); -} +SqlFieldsQuery.prototype = Query.prototype; -/** - * @this {SqlFieldsQuery} - * @param {int} pageSz Page size. - */ -SqlFieldsQuery.prototype.setPageSize = function(pageSz) { - this._pageSz = pageSz; -} +SqlFieldsQuery.prototype.constructor = SqlFieldsQuery; /** * @this {SqlFieldsQuery} @@ -99,20 +57,4 @@ SqlFieldsQuery.prototype.arguments = function() { return this._arg; } -/** - * @this {SqlFieldsQuery} - * @returns pageSize - */ -SqlFieldsQuery.prototype.pageSize = function() { - return this._pageSz; -} - -/** - * @this {SqlFieldsQuery} - * @returns "SqlFields" - */ -SqlFieldsQuery.prototype.type = function() { - return this._qryType; -} - -exports.SqlFieldsQuery = SqlFieldsQuery; \ No newline at end of file +exports.SqlFieldsQuery = SqlFieldsQuery; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/nodejs/src/test/js/test-query.js ---------------------------------------------------------------------- diff --git a/modules/nodejs/src/test/js/test-query.js b/modules/nodejs/src/test/js/test-query.js index 3d55886..293b2ea 100644 --- a/modules/nodejs/src/test/js/test-query.js +++ b/modules/nodejs/src/test/js/test-query.js @@ -22,6 +22,7 @@ var assert = require("assert"); var Ignite = require(TestUtils.scriptPath()); var SqlQuery = Ignite.SqlQuery; var SqlFieldsQuery = Ignite.SqlFieldsQuery; +var ScanQuery = Ignite.ScanQuery; testSqlQuery = function() { TestUtils.startIgniteNode().then(function(ignite) { @@ -59,10 +60,46 @@ testSqlQuery = function() { cursor.nextPage().then(onQuery); }).catch(function(err) { - assert(err === null, err); + TestUtils.testFails(err); }) }).catch(function(err) { - assert(err === null, err); + TestUtils.testFails(err); + }); +} + +testScanQuery = function() { + TestUtils.startIgniteNode().then(function(ignite) { + var qry = new ScanQuery(); + + var fullRes = []; + + function onQuery(cursor) { + var page = cursor.page(); + + fullRes = fullRes.concat(page); + + if (cursor.isFinished()) { + console.log("Full result=" + JSON.stringify(fullRes)); + + assert(fullRes.length === 4, "Result length is not correct" + + "[expected=1, val = " + fullRes.length + "]"); + + fullRes.sort(); + + assert(fullRes[0]["key"] >= 0, + "Result has incorrect index [res=" + fullRes[0]["key"] + "]"); + + return ignite.cache("person").get("key"); + } + + return cursor.nextPage().then(onQuery); + } + + ignite.cache("person").query(qry).nextPage().then(onQuery).then(function(){ + TestUtils.testDone(); + }) + }).catch(function(err) { + TestUtils.testFails(err); }); } @@ -98,7 +135,7 @@ testSqlFieldsQuery = function() { TestUtils.testDone(); }) }).catch(function(err) { - assert(err === null, err); + TestUtils.testFails(err); }); } @@ -148,7 +185,7 @@ testSqlFieldsGetAllQuery = function() { TestUtils.testDone(); }) }).catch(function(err) { - assert(err === null, err); + TestUtils.testFails(err); }); } @@ -193,7 +230,7 @@ testSqlFieldsMeta = function() { ignite.cache("person").query(qry).nextPage().then(onQuery); }).catch(function(err) { - assert(err === null, err); + TestUtils.testFails(err); }); } @@ -232,6 +269,6 @@ testSqlQueryWithParams = function() { ignite.cache("person").query(qry).nextPage().then(onQuery); }).catch(function(err) { - assert(err === null, err); + TestUtils.testFails(err); }); -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/nodejs/src/test/js/test-runner.js ---------------------------------------------------------------------- diff --git a/modules/nodejs/src/test/js/test-runner.js b/modules/nodejs/src/test/js/test-runner.js index 9ee1092..adbad85 100644 --- a/modules/nodejs/src/test/js/test-runner.js +++ b/modules/nodejs/src/test/js/test-runner.js @@ -31,7 +31,7 @@ TestRunner.runTest = function() { console.log("FileName " + fileName); - require("./" + fileName); + require(fileName); var functionName = process.argv[3].toString().trim(); @@ -43,4 +43,4 @@ TestRunner.runTest = function() { global[functionName](); } -TestRunner.runTest(); \ No newline at end of file +TestRunner.runTest(); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/nodejs/src/test/js/test-script-runner.js ---------------------------------------------------------------------- diff --git a/modules/nodejs/src/test/js/test-script-runner.js b/modules/nodejs/src/test/js/test-script-runner.js new file mode 100644 index 0000000..7223d51 --- /dev/null +++ b/modules/nodejs/src/test/js/test-script-runner.js @@ -0,0 +1,39 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. See the NOTICE file distributed with + * * this work for additional information regarding copyright ownership. + * * The ASF licenses this file to You under the Apache License, Version 2.0 + * * (the "License"); you may not use this file except in compliance with + * * the License. You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +/** + * Create instance of ScriptTestRunner + * + * @constructor + */ +function ScriptTestRunner() { +} + +/** + * Test routine + */ +ScriptTestRunner.runTest = function() { + var fileName = process.argv[2].toString().trim(); + + console.log("FileName " + fileName); + + require(fileName); +} + +ScriptTestRunner.runTest(); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17a681c7/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java ---------------------------------------------------------------------- diff --git a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java index edd1745..59b22d4 100644 --- a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java +++ b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java @@ -24,6 +24,7 @@ import org.apache.ignite.internal.*; import org.apache.ignite.internal.processors.rest.*; import org.apache.ignite.internal.processors.rest.client.message.*; import org.apache.ignite.internal.processors.rest.request.*; +import org.apache.ignite.internal.processors.rest.request.RestQueryRequest.*; import org.apache.ignite.internal.util.typedef.*; import org.apache.ignite.internal.util.typedef.internal.*; import org.apache.ignite.lang.*; @@ -640,7 +641,7 @@ public class GridJettyRestHandler extends AbstractHandler { case EXECUTE_SQL_QUERY: case EXECUTE_SQL_FIELDS_QUERY: { - RestSqlQueryRequest restReq0 = new RestSqlQueryRequest(); + RestQueryRequest restReq0 = new RestQueryRequest(); restReq0.sqlQuery((String) params.get("qry")); @@ -661,20 +662,46 @@ public class GridJettyRestHandler extends AbstractHandler { restReq0.cacheName((String)params.get("cacheName")); + if (cmd.equals(EXECUTE_SQL_QUERY)) + restReq0.queryType(QueryType.SQL); + else + restReq0.queryType(QueryType.SQL_FIELDS); + + restReq = restReq0; + + break; + } + + case EXECUTE_SCAN_QUERY: { + RestQueryRequest restReq0 = new RestQueryRequest(); + + restReq0.sqlQuery((String)params.get("qry")); + + String pageSize = (String)params.get("pageSize"); + + if (pageSize != null) + restReq0.pageSize(Integer.parseInt(pageSize)); + + restReq0.cacheName((String)params.get("cacheName")); + + restReq0.className((String)params.get("classname")); + + restReq0.queryType(QueryType.SCAN); + restReq = restReq0; break; } case FETCH_SQL_QUERY: { - RestSqlQueryRequest restReq0 = new RestSqlQueryRequest(); + RestQueryRequest restReq0 = new RestQueryRequest(); String qryId = (String) params.get("qryId"); if (qryId != null) restReq0.queryId(Long.parseLong(qryId)); - String pageSize = (String) params.get("pageSize"); + String pageSize = (String)params.get("pageSize"); if (pageSize != null) restReq0.pageSize(Integer.parseInt(pageSize)); @@ -687,7 +714,7 @@ public class GridJettyRestHandler extends AbstractHandler { } case CLOSE_SQL_QUERY: { - RestSqlQueryRequest restReq0 = new RestSqlQueryRequest(); + RestQueryRequest restReq0 = new RestQueryRequest(); String qryId = (String) params.get("qryId");