Kouhei Sutou
null+****@clear*****
Sun Dec 21 16:28:18 JST 2014
Kouhei Sutou 2014-12-21 16:28:18 +0900 (Sun, 21 Dec 2014) New Revision: 9181451d3e50ca5c82cdd3e987afd51a98071503 https://github.com/groonga/groonga-admin/commit/9181451d3e50ca5c82cdd3e987afd51a98071503 Message: Make schema loader service Added files: app/scripts/services/schema-loader.js Modified files: app/index.html app/scripts/controllers/table-search-controller.js app/scripts/controllers/top-controller.js app/scripts/groonga-client.js app/views/tables/search.html Modified: app/index.html (+1 -0) =================================================================== --- app/index.html 2014-12-16 22:10:02 +0900 (d974221) +++ app/index.html 2014-12-21 16:28:18 +0900 (ac16093) @@ -81,6 +81,7 @@ <script src="scripts/groonga-client/response/table-list.js"></script> <script src="scripts/groonga-client/response/column-list.js"></script> <script src="scripts/app.js"></script> + <script src="scripts/services/schema-loader.js"></script> <script src="scripts/controllers/top-controller.js"></script> <script src="scripts/controllers/table-search-controller.js"></script> <!-- endbuild --> Modified: app/scripts/controllers/table-search-controller.js (+66 -148) =================================================================== --- app/scripts/controllers/table-search-controller.js 2014-12-16 22:10:02 +0900 (17f6f30) +++ app/scripts/controllers/table-search-controller.js 2014-12-21 16:28:18 +0900 (633abb1) @@ -9,8 +9,9 @@ */ angular.module('groongaAdminApp') .controller('TableSearchController', [ - '$scope', '$routeParams', '$location', '$q', '$http', '$filter', - function ($scope, $routeParams, $location, $q, $http, $filter) { + '$scope', '$routeParams', '$location', '$http', '$filter', 'schemaLoader', + function ($scope, $routeParams, $location, $http, $filter, schemaLoader) { + var schema; var client = new GroongaClient($http); function findElement(array, finder) { @@ -30,7 +31,12 @@ angular.module('groongaAdminApp') } function initialize() { - $scope.table = $routeParams.table; + $scope.table = { + name: $routeParams.table, + allColumns: [], + timeColumns: [], + indexedColumns: [] + }; $scope.style = 'table'; $scope.response = { rawData: [], @@ -40,10 +46,6 @@ angular.module('groongaAdminApp') elapsedTimeInMilliseconds: 0, nTotalRecords: 0 }; - $scope.allTables = []; - $scope.allColumns = []; - $scope.timeColumns = []; - $scope.indexedColumns = []; $scope.commandLine = ''; $scope.message = ''; $scope.parameters = angular.copy($location.search()); @@ -69,6 +71,13 @@ angular.module('groongaAdminApp') return names.join(','); } + function packMatchColumns(columns) { + var names = columns.map(function(column) { + return column.indexName; + }); + return names.join(','); + } + function packSortColumns(columns) { var keys = columns.map(function(column) { if (column.sort === 'ascending') { @@ -105,7 +114,7 @@ angular.module('groongaAdminApp') } function buildFilter() { - var timeQueries = $scope.timeColumns.filter(function(column) { + var timeQueries = $scope.table.timeColumns.filter(function(column) { return column.start || column.end; }).map(function(column) { var operator; @@ -141,12 +150,12 @@ angular.module('groongaAdminApp') function buildParameters() { var parameters = angular.copy($scope.parameters); - var matchColumns = $scope.indexedColumns.filter(function(column) { + var matchColumns = $scope.table.indexedColumns.filter(function(column) { return column.inUse; }); - parameters.match_columns = packColumns(matchColumns); + parameters.match_columns = packMatchColumns(matchColumns); - var outputColumns = $scope.allColumns.filter(function(column) { + var outputColumns = $scope.table.allColumns.filter(function(column) { return column.output; }); parameters.output_columns = packColumns(outputColumns); @@ -154,12 +163,12 @@ angular.module('groongaAdminApp') parameters.offset = ($scope.currentPage - 1) * $scope.nRecordsInPage; parameters.limit = $scope.nRecordsInPage; - var sortColumns = $scope.allColumns.filter(function(column) { + var sortColumns = $scope.table.allColumns.filter(function(column) { return column.sort; }); parameters.sortby = packSortColumns(sortColumns); - var drilldowns = $scope.allColumns.filter(function(column) { + var drilldowns = $scope.table.allColumns.filter(function(column) { return column.drilldown; }); parameters.drilldown = packColumns(drilldowns); @@ -198,7 +207,7 @@ angular.module('groongaAdminApp') } function toggleSort(column) { - var columnInfo = findElement($scope.allColumns, function(columnInfo) { + var columnInfo = findElement($scope.table.allColumns, function(columnInfo) { return columnInfo.name === column.name; }); if (!columnInfo) { @@ -222,30 +231,13 @@ angular.module('groongaAdminApp') incrementalSearch(); } - function isTableType(type) { - return $scope.allTables.some(function(table) { - return table.name === type; - }); - } - - function isTextType(type) { - switch (type) { - case 'ShortText': - case 'Text': - case 'LongText': - return true; - default: - return false; - } - } - function selectDrilldown(key, value) { var queryKey = key; - var column = findElement($scope.allColumns, function(column) { + var column = findElement($scope.table.allColumns, function(column) { return column.name === key; }); if (column) { - if (isTableType(column.type)) { + if (column.isTableType) { queryKey += '._key'; } } @@ -302,12 +294,16 @@ angular.module('groongaAdminApp') type: column.range, output: output, drilldown: drilldown, - sort: sort + sort: sort, + indexes: column.indexes || [], + isTextType: column.isTextType, + isTableType: column.isTableType }; } function addColumn(columnInfo) { - $scope.allColumns.push(columnInfo); + $scope.table.allColumns.push(columnInfo); + if (columnInfo.type === 'Time') { var timeColumnInfo = { name: columnInfo.name, @@ -316,8 +312,23 @@ angular.module('groongaAdminApp') end: null, endIncluded: true }; - $scope.timeColumns.push(timeColumnInfo); + $scope.table.timeColumns.push(timeColumnInfo); } + + var matchColumns = $scope.parameters.match_columns; + columnInfo.indexes.forEach(function(/* index */) { + var indexName = columnInfo.name; + var inUse = true; + if (matchColumns) { + inUse = (matchColumns.indexOf(indexName) !== -1); + } + var indexedColumnInfo = { + name: columnInfo.name, + indexName: indexName, + inUse: inUse + }; + $scope.table.indexedColumns.push(indexedColumnInfo); + }); } function applyTimeQueries() { @@ -350,7 +361,7 @@ angular.module('groongaAdminApp') var startBorder = parts[3]; var end = parts[4]; var endBorder = parts[5]; - timeColumn = findElement($scope.timeColumns, function(column) { + timeColumn = findElement($scope.table.timeColumns, function(column) { return column.name === columnName; }); if (!timeColumn) { @@ -365,7 +376,7 @@ angular.module('groongaAdminApp') columnName = parts[0]; operator = parts[1]; time = parts[2]; - timeColumn = findElement($scope.timeColumns, function(column) { + timeColumn = findElement($scope.table.timeColumns, function(column) { return column.name === columnName; }); if (!timeColumn) { @@ -393,116 +404,9 @@ angular.module('groongaAdminApp') }); } - function extractColumnsInfo(table, columns) { - columns.forEach(function(column) { - if (!column.isIndex) { - return; - } - if (column.range !== $scope.table) { - return; - } - var matchColumns = $scope.parameters.match_columns; - column.sources.forEach(function(source) { - var localName; - if (source.indexOf('.') === -1) { - localName = '_key'; - } else { - localName = source.split('.')[1]; - } - - var indexName = localName; - var sourceColumn = findElement($scope.allColumns, function(column) { - return column.name === localName; - }); - if (sourceColumn) { - var targetType = sourceColumn.type; - var isTableTypeSource = isTableType(targetType); - if (isTableTypeSource) { - var table = findElement($scope.allTables, function(table) { - return table.name === targetType; - }); - targetType = table.domain; - } - if (!isTextType(targetType)) { - return; - } - - if (isTableTypeSource) { - indexName += '._key'; - } - } - - var inUse = true; - if (matchColumns) { - inUse = matchColumns.indexOf(indexName) !== -1; - } - - $scope.indexedColumns.push({ - name: indexName, - label: localName, - inUse: inUse - }); - }); - }); - } - - function extractTableInfo(table) { - return client.execute('column_list', {table: table.name}) - .success(function(response) { - extractColumnsInfo(table, response.columns()); - }); - } - - function fillOptions() { - client.execute('table_list') - .success(function(response) { - $scope.allTables = response.tables(); - - var idColumn = { - name: '_id', - range: 'UInt32' - }; - addColumn(createColumnInfo(idColumn)); - - client.execute('column_list', {table: $scope.table}) - .success(function(response) { - var columns = response.columns(); - - columns.forEach(function(column) { - if (column.isIndex) { - return; - } - addColumn(createColumnInfo(column)); - }); - applyTimeQueries(); - - var currentTable = findElement($scope.allTables, function(table) { - return table.name === $scope.table; - }); - extractColumnsInfo(currentTable, columns); - - var tasks = []; - $scope.allTables.forEach(function(table) { - if (table.name === $scope.table) { - return; - } - tasks.push(extractTableInfo(table)); - }); - $q.all(tasks) - .then(function() { - var parameters = buildParameters(); - if ($scope.parameters.offset) { - parameters.offset = $scope.parameters.offset; - } - select(parameters); - }); - }); - }); - } - function select(userParameters) { var parameters = { - table: $scope.table + table: $scope.table.name }; angular.forEach(userParameters, function(value, key) { if (key in parameters) { @@ -527,7 +431,7 @@ angular.module('groongaAdminApp') $scope.response.nTotalRecords = response.nTotalRecords(); $scope.response.columns = response.columns(); $scope.response.columns.forEach(function(column) { - var columnInfo = findElement($scope.allColumns, function(columnInfo) { + var columnInfo = findElement($scope.table.allColumns, function(columnInfo) { return columnInfo.name === column.name; }); if (columnInfo) { @@ -564,5 +468,19 @@ angular.module('groongaAdminApp') } initialize(); - fillOptions(); + schemaLoader() + .then(function(_schema) { + schema = _schema; + var table = schema.tables[$scope.table.name]; + angular.forEach(table.columns, function(column) { + addColumn(createColumnInfo(column)); + }); + applyTimeQueries(); + + var parameters = buildParameters(); + if ($scope.parameters.offset) { + parameters.offset = $scope.parameters.offset; + } + select(parameters); + }); }]); Modified: app/scripts/controllers/top-controller.js (+11 -8) =================================================================== --- app/scripts/controllers/top-controller.js 2014-12-16 22:10:02 +0900 (46fd18a) +++ app/scripts/controllers/top-controller.js 2014-12-21 16:28:18 +0900 (ca81f47) @@ -8,11 +8,14 @@ * Controller of the groongaAdminApp */ angular.module('groongaAdminApp') - .controller('TopController', function ($scope, $http) { - $scope.tables = []; - var client = new GroongaClient($http); - var request = client.execute('table_list', {}); - request.success(function(response) { - $scope.tables = response.tables(); - }); - }); + .controller('TopController', [ + '$scope', 'schemaLoader', + function ($scope, schemaLoader) { + $scope.tables = []; + schemaLoader() + .then(function(schema) { + angular.forEach(schema.tables, function(table) { + $scope.tables.push(table); + }); + }); + }]); Modified: app/scripts/groonga-client.js (+8 -4) =================================================================== --- app/scripts/groonga-client.js 2014-12-16 22:10:02 +0900 (ef6ec0e) +++ app/scripts/groonga-client.js 2014-12-21 16:28:18 +0900 (78e2c57) @@ -32,15 +32,19 @@ GroongaClient.Request.prototype.success = function(callback) { var name = this._name; - return this._rawRequest.success(function(data, status, headers, config) { + return this._rawRequest.then(function(rawResponse) { var ResponseConstructor = GroongaClient.Response.find(name); - var response = new ResponseConstructor(data); - callback(response, status, headers, config); + var response = new ResponseConstructor(rawResponse.data); + return callback(response, rawResponse); }); }; GroongaClient.Request.prototype.error = function(callback) { - return this._rawRequest.error(callback); + return this._rawRequest.then(null, function(rawResponse) { + var ResponseConstructor = GroongaClient.Response.find(name); + var response = new ResponseConstructor(rawResponse.data); + return callback(response, rawResponse); + }); }; GroongaClient.Request.prototype.commandLine = function() { Added: app/scripts/services/schema-loader.js (+141 -0) 100644 =================================================================== --- /dev/null +++ app/scripts/services/schema-loader.js 2014-12-21 16:28:18 +0900 (3581d06) @@ -0,0 +1,141 @@ +'use strict'; + +/** + * @ngdoc function + * @name groongaAdminApp.service:schemaLoader + * @description + * # schemaLoader + * Groonga database schema loader. + */ +angular.module('groongaAdminApp') + .factory('schemaLoader', [ + '$q', '$http', '$timeout', + function ($q, $http, $timeout) { + var fetching = false; + var waitingDeferes = []; + var fetched = false; + var schema = { + tables: {} + }; + var client = new GroongaClient($http); + + function isTextType(typeName) { + switch (typeName) { + case 'ShortText': + case 'Text': + case 'LongText': + return true; + default: + return false; + } + } + + function isReferenceType(typeName) { + return typeName in schema.tables; + } + + function resolveColumn(column) { + column.isTextType = isTextType(column.range); + column.isReferenceType = isReferenceType(column.range); + } + + function resolveColumns() { + angular.forEach(schema.tables, function(table) { + angular.forEach(table.columns, function(column) { + resolveColumn(column); + }); + }); + } + + function resolveIndex(column) { + var table = schema.tables[column.range]; + column.sources.forEach(function(source) { + var columnName; + if (source.indexOf('.') === -1) { + columnName = '_key'; + } else { + columnName = source.split('.')[1]; + } + var targetColumn = table.columns[columnName]; + targetColumn.indexes.push(column); + }); + } + + function resolveIndexes() { + angular.forEach(schema.tables, function(table) { + angular.forEach(table.columns, function(column) { + if (column.isIndex) { + resolveIndex(column); + } + }); + }); + } + + function addColumn(table, column) { + column.table = table; + column.indexes = []; + table.columns[column.name] = column; + } + + function fetchColumns(table) { + table.columns = {}; + + addColumn(table, { + name: '_id', + range: 'UInt32' + }); + + return client.execute('column_list', {table: table.name}) + .success(function(response) { + var columns = response.columns(); + + columns.forEach(function(column) { + addColumn(table, column); + }); + }); + } + + function fetchTables() { + return client.execute('table_list') + .success(function(response) { + response.tables().forEach(function(table) { + schema.tables[table.name] = table; + }); + + var fetchColumnsTasks = []; + angular.forEach(schema.tables, function(table) { + fetchColumnsTasks.push(fetchColumns(table)); + }); + + return $q.all(fetchColumnsTasks) + .then(function() { + resolveColumns(); + resolveIndexes(); + fetched = true; + fetching = false; + waitingDeferes.forEach(function(defer) { + defer.resolve(schema); + }); + waitingDeferes = []; + return schema; + }); + }); + } + + return function() { + if (fetching) { + var defer = $q.defer(); + waitingDeferes.push(defer); + return defer.promise; + } else if (fetched) { + var defer = $q.defer(); + $timeout(function() { + defer.resolve(schema); + }); + return defer.promise; + } else { + fetching = true + return fetchTables(); + } + }; + }]); Modified: app/views/tables/search.html (+5 -5) =================================================================== --- app/views/tables/search.html 2014-12-16 22:10:02 +0900 (bba6ee5) +++ app/views/tables/search.html 2014-12-21 16:28:18 +0900 (0c7cdc7) @@ -2,7 +2,7 @@ <ol class="breadcrumb"> <li><a href="#">Top</a></li> <li><a href="#/tables/">Tables</a></li> - <li><a href="#/tables/{{table}}">{{table}}</a></li> + <li><a href="#/tables/{{table.name}}">{{table.name}}</a></li> <li class="active">Search</li> </ol> @@ -44,7 +44,7 @@ </tr> </thead> <tbody> - <tr ng-repeat="column in allColumns track by $index"> + <tr ng-repeat="column in table.allColumns track by $index"> <td>{{column.name}}</td> <td><input type="checkbox" ng-model="column.output" @@ -87,12 +87,12 @@ <form class="search-form" role="search"> <div class="form-group"> <div class="input-group"> - <span ng-repeat="indexedColumn in indexedColumns track by $index"> + <span ng-repeat="indexedColumn in table.indexedColumns track by $index"> <label> <input type="checkbox" ng-model="indexedColumn.inUse" ng-change="incrementalSearch()"> - {{indexedColumn.label}} + {{indexedColumn.name}} </label> </span> </div> @@ -107,7 +107,7 @@ </div> </div> <div class="form-group time-query" - ng-repeat="timeColumn in timeColumns track by $index"> + ng-repeat="timeColumn in table.timeColumns track by $index"> {{timeColumn.name}}: <div class="dropdown"> <div class="input-group"> -------------- next part -------------- HTML����������������������������...Download