sqlui 0.1.45 → 0.1.47

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0868cb367e107f12cd91368ae75b8fb7a3c07e560314cb4cef53f383098a8882'
4
- data.tar.gz: 5268a086e9a3436f0e3e421d41dd54fc1ebb11fff9942ff0a6e25c36863ffde1
3
+ metadata.gz: 01c105468ea4c5f463ada429231bd41a3a65752d8fa95f8befa2121a47765fbe
4
+ data.tar.gz: 6e0df11aa97b0e8d0d685e6b109a297c8ddba78959f109db26f7b159aa4cfa0c
5
5
  SHA512:
6
- metadata.gz: b9b7368e050c3aa4cce48c875347d2eeaa59c8fd33ee48f1e95addafc377f433a2fd6d16d26add6e0fe477c139ec2d300c26963ab34a2469e02b500123c34bcf
7
- data.tar.gz: 75c25197021f06d7d1cbc14516f254760c63f0830e55f86226a772d53ab7b23b10d62ab790c0bbca031d2a78795c9b4185a2467e5748eb00fdf84762b42fdf04
6
+ metadata.gz: 6c1fd32e0feb8817bac5e120a15e71adf48e9ccbe5183e0ba729dc29c1a2bb76ffa18bd7c63559dd49f66f0eb8a3669213988701da8c3f4d4566919985c80c13
7
+ data.tar.gz: 022b592a3ed56c7e06b8222566cfe7d096ed1b1789d687afe4bf945e625a390269dffd8a701fa4647377e85399b40e345147ea637113a2489e31fbd2630e409a
data/.version CHANGED
@@ -1 +1 @@
1
- 0.1.45
1
+ 0.1.47
@@ -8,7 +8,7 @@ require_relative 'args'
8
8
 
9
9
  # Config for a single database.
10
10
  class DatabaseConfig
11
- attr_reader :display_name, :description, :url_path, :joins, :saved_path, :table_aliases, :client_params
11
+ attr_reader :display_name, :description, :url_path, :joins, :saved_path, :tables, :client_params
12
12
 
13
13
  def initialize(hash)
14
14
  @display_name = Args.fetch_non_empty_string(hash, :display_name).strip
@@ -27,12 +27,25 @@ class DatabaseConfig
27
27
 
28
28
  raise ArgumentError, "invalid join #{join.to_json}"
29
29
  end
30
- @table_aliases = Args.fetch_optional_hash(hash, :table_aliases) || {}
31
- @table_aliases = @table_aliases.each do |table, a|
32
- raise ArgumentError, "invalid alias for table #{table} (#{a}), expected string" unless a.is_a?(String)
30
+ @tables = Args.fetch_optional_hash(hash, :tables) || {}
31
+ @tables = @tables.each do |table, table_config|
32
+ unless table_config.is_a?(Hash)
33
+ raise ArgumentError, "invalid table config for #{table} (#{table_config}), expected hash"
34
+ end
35
+
36
+ table_alias = table_config[:alias]
37
+ if table_alias && !table_alias.is_a?(String)
38
+ raise ArgumentError, "invalid table alias for #{table} (#{table_alias}), expected string"
39
+ end
40
+
41
+ table_boost = table_config[:boost]
42
+ if table_boost && !table_boost.is_a?(Integer)
43
+ raise ArgumentError, "invalid table boost for #{table} (#{table_boost}), expected int"
44
+ end
33
45
  end
34
- duplicate_aliases = @table_aliases.reject { |(_, v)| @table_aliases.values.count(v) == 1 }.to_h.values.to_set
35
- if @table_aliases.values.to_set.size < @table_aliases.values.size
46
+ aliases = @tables.map { |_table, table_config| table_config[:alias] }.compact
47
+ if aliases.to_set.size < aliases.size
48
+ duplicate_aliases = aliases.reject { |a| aliases.count(a) == 1 }.to_set
36
49
  raise ArgumentError, "duplicate table aliases: #{duplicate_aliases.join(', ')}"
37
50
  end
38
51
 
data/app/server.rb CHANGED
@@ -6,7 +6,6 @@ require 'erb'
6
6
  require 'json'
7
7
  require 'sinatra/base'
8
8
  require 'uri'
9
- require 'webrick/log'
10
9
  require_relative 'database_metadata'
11
10
  require_relative 'mysql_types'
12
11
  require_relative 'sql_parser'
@@ -14,6 +13,10 @@ require_relative 'sqlui'
14
13
 
15
14
  # SQLUI Sinatra server.
16
15
  class Server < Sinatra::Base
16
+ def self.logger
17
+ @logger ||= WEBrick::Log.new
18
+ end
19
+
17
20
  def self.init_and_run(config, resources_dir)
18
21
  Mysql2::Client.default_query_options[:as] = :array
19
22
  Mysql2::Client.default_query_options[:cast_booleans] = true
@@ -27,8 +30,6 @@ class Server < Sinatra::Base
27
30
  set :raise_errors, false
28
31
  set :show_exceptions, false
29
32
 
30
- logger = WEBrick::Log.new
31
-
32
33
  get '/-/health' do
33
34
  status 200
34
35
  body 'OK'
@@ -67,7 +68,7 @@ class Server < Sinatra::Base
67
68
  server: "#{config.name} - #{database.display_name}",
68
69
  list_url_path: config.list_url_path,
69
70
  schemas: DatabaseMetadata.lookup(client, database),
70
- table_aliases: database.table_aliases,
71
+ tables: database.tables,
71
72
  joins: database.joins,
72
73
  saved: Dir.glob("#{database.saved_path}/*.sql").to_h do |path|
73
74
  contents = File.read(path)
@@ -99,35 +100,45 @@ class Server < Sinatra::Base
99
100
  variables = params[:variables] || {}
100
101
  sql = find_selected_query(params[:sql], params[:selection])
101
102
 
102
- result = database.with_client do |client|
103
- query_result = execute_query(client, variables, sql)
104
- # NOTE: the call to result.field_types must go before other interaction with the result. Otherwise you will
105
- # get a seg fault. Seems to be a bug in Mysql2.
106
- # TODO: stream this and render results on the client as they are returned?
107
- {
108
- columns: query_result.fields,
109
- column_types: MysqlTypes.map_to_google_charts_types(query_result.field_types),
110
- total_rows: query_result.size,
111
- rows: (query_result.to_a || []).take(Sqlui::MAX_ROWS)
112
- }
113
- end
114
-
115
- result[:selection] = params[:selection]
116
- result[:query] = params[:sql]
117
-
118
103
  status 200
119
104
  headers 'Content-Type' => 'application/json; charset=utf-8'
120
- body result.to_json
105
+
106
+ database.with_client do |client|
107
+ query_result = execute_query(client, variables, sql)
108
+ stream do |out|
109
+ json = <<~RES.chomp
110
+ {
111
+ "columns": #{query_result.fields.to_json},
112
+ "column_types": #{MysqlTypes.map_to_google_charts_types(query_result.field_types).to_json},
113
+ "total_rows": #{query_result.size.to_json},
114
+ "selection": #{params[:selection].to_json},
115
+ "query": #{params[:sql].to_json},
116
+ "rows": [
117
+ RES
118
+ out << json
119
+ bytes = json.bytesize
120
+ query_result.each_with_index do |row, i|
121
+ json = "#{i.zero? ? '' : ','}\n #{row.to_json}"
122
+ bytes += json.bytesize
123
+ break if i == Sqlui::MAX_ROWS || bytes > Sqlui::MAX_BYTES
124
+
125
+ out << json
126
+ end
127
+ out << <<~RES
128
+
129
+ ]
130
+ }
131
+ RES
132
+ end
133
+ end
121
134
  end
122
135
 
123
136
  get "#{database.url_path}/download_csv" do
124
137
  break client_error('missing sql') unless params[:sql]
125
138
 
126
139
  sql = Base64.decode64(params[:sql]).force_encoding('UTF-8')
127
- logger.info "sql: #{sql}"
128
140
  variables = params.map { |k, v| k[0] == '_' ? [k, v] : nil }.compact.to_h
129
141
  sql = find_selected_query(sql, params[:selection])
130
- logger.info "sql: #{sql}"
131
142
 
132
143
  content_type 'application/csv; charset=utf-8'
133
144
  attachment 'result.csv'
data/app/sqlui.rb CHANGED
@@ -6,6 +6,7 @@ require_relative 'server'
6
6
  # Main entry point.
7
7
  class Sqlui
8
8
  MAX_ROWS = 10_000
9
+ MAX_BYTES = 10 * 1_024 * 1_024
9
10
 
10
11
  def initialize(config_file)
11
12
  raise 'you must specify a configuration file' unless config_file
@@ -23995,19 +23995,20 @@
23995
23995
  const schemas = Object.entries(window.metadata.schemas);
23996
23996
  const editorSchema = {};
23997
23997
  const tables = [];
23998
- const hasTableAliases = Object.keys(window.metadata.table_aliases).length > 0;
23999
23998
  schemas.forEach(([schemaName, schema]) => {
24000
23999
  Object.entries(schema.tables).forEach(([tableName, table]) => {
24001
24000
  const qualifiedTableName = schemas.length === 1 ? tableName : `${schemaName}.${tableName}`;
24002
24001
  const quotedQualifiedTableName = schemas.length === 1 ? `\`${tableName}\`` : `\`${schemaName}\`.\`${tableName}\``;
24003
24002
  const columns = Object.keys(table.columns);
24004
24003
  editorSchema[qualifiedTableName] = columns;
24005
- const alias = window.metadata.table_aliases[qualifiedTableName];
24004
+ const alias = window.metadata.tables[qualifiedTableName]?.alias;
24005
+ const boost = window.metadata.tables[qualifiedTableName]?.boost;
24006
24006
  if (alias) {
24007
24007
  editorSchema[alias] = columns;
24008
24008
  tables.push({
24009
24009
  label: qualifiedTableName,
24010
24010
  detail: alias,
24011
+ boost,
24011
24012
  alias_type: 'with',
24012
24013
  quoted: `${quotedQualifiedTableName} \`${alias}\``,
24013
24014
  unquoted: `${qualifiedTableName} ${alias}`
@@ -24015,6 +24016,7 @@
24015
24016
  tables.push({
24016
24017
  label: qualifiedTableName,
24017
24018
  detail: alias,
24019
+ boost,
24018
24020
  alias_type: 'only',
24019
24021
  quoted: '`' + alias + '`',
24020
24022
  unquoted: alias
@@ -24090,7 +24092,7 @@
24090
24092
  MySQL.language.data.of({
24091
24093
  autocomplete: (context) => {
24092
24094
  const result = originalSchemaCompletionSource(context);
24093
- if (!hasTableAliases || !result?.options) return result
24095
+ if (!result?.options) return result
24094
24096
 
24095
24097
  const tree = syntaxTree(context.state);
24096
24098
  let node = tree.resolveInner(context.pos, -1);
@@ -24164,10 +24166,19 @@
24164
24166
  if (foundSchema) {
24165
24167
  const unquotedLabel = unquoteSqlId(option.label);
24166
24168
  const quoted = unquotedLabel !== option.label;
24167
- const alias = window.metadata.table_aliases[`${foundSchema}.${unquotedLabel}`];
24169
+ const tableConfig = window.metadata.tables[`${foundSchema}.${unquotedLabel}`];
24170
+ const alias = tableConfig?.alias;
24171
+ const boost = tableConfig?.boost || -1;
24172
+ const optionOverride = {
24173
+ label: option.label
24174
+ };
24168
24175
  if (alias) {
24169
- option = { label: quoted ? `\`${unquotedLabel}\` \`${alias}\`` : `${option.label} ${alias}` };
24176
+ optionOverride.label = quoted ? `\`${unquotedLabel}\` \`${alias}\`` : `${option.label} ${alias}`;
24170
24177
  }
24178
+ if (boost) {
24179
+ optionOverride.boost = boost;
24180
+ }
24181
+ if (alias || boost) return optionOverride
24171
24182
  }
24172
24183
  return option
24173
24184
  });
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqlui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.45
4
+ version: 0.1.47
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Dower
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-20 00:00:00.000000000 Z
11
+ date: 2022-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mysql2