sqlui 0.1.45 → 0.1.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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