gloo-db 1.2 → 1.3

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: a5f869d21a951e0e316359c444255d44fdae07b64bf9991eb1739ba9df90431c
4
- data.tar.gz: 64f9bc0c6aeb28f99779a9addacbf3fbc4bcb3265c3b096d93c9db8d19b5c40e
3
+ metadata.gz: 3ad932a978b3c8ba5733dcd79d4188748ccbeae4077da55dfe096ced7bcc5fd0
4
+ data.tar.gz: 878fed77aa72d68a826043ac53026753b8cd50817efcf428d2df13b34998b729
5
5
  SHA512:
6
- metadata.gz: e7af37a53fdc0b250306bf723ae92181cca7958aa7dedbf78c61e1f9c660bcc3ee1f46ac52082df6647a3f55ea077ac05ebf659dd309f7c5900348521d71b035
7
- data.tar.gz: 25b3ec859468892ac5ed7572790b6400259e52241eca8ef18e0170f6db0cc0fa3a683bb6c27903efbd2513cd0ea4a18a2653ad0e011ccbb3a7e87c3e76641193
6
+ metadata.gz: 7fd86d6a95af8d73e481d8f6a589fb7bb7e4adf2708351e434fd2c28a677f3f804d01c2c75cd5f43d427829bccc8d1afcce455956cff2db692e2ddb97818f4c6
7
+ data.tar.gz: 6d166a12139e3e9cf9796c9e9cf49ff05df66ee13f17c80c3daebf25aebc7b48502d33346e65b069763de6bb617baa3b5dfc229db77a9396e37e72e403e80c45
@@ -0,0 +1,60 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2026 Eric Crane. All rights reserved.
3
+ #
4
+ # Shared behaviour for database connection objects (gloo-sqlite,
5
+ # gloo-mysql, gloo-pg). A connection class includes this module so
6
+ # every driver reports problems the same way:
7
+ #
8
+ # - Database errors (bad SQL, a missing table, a lost connection)
9
+ # come out of the driver's query as exceptions; Query reports them
10
+ # as one readable error. database_errors says which exception
11
+ # classes those are.
12
+ # - Setup problems the driver can see (eg. no database name) are
13
+ # reported with setup_err, and the query returns no result.
14
+ # - verify puts true in it, or reports a readable error and puts
15
+ # false (verify_connection).
16
+ #
17
+ module DbConnection
18
+
19
+ #
20
+ # The exception classes that are database errors for this driver.
21
+ # Query reports these as 'Query failed: …'; anything else is an
22
+ # unexpected error. Drivers override this with their library's
23
+ # error classes.
24
+ #
25
+ def database_errors
26
+ return [ StandardError ]
27
+ end
28
+
29
+ #
30
+ # Verify the connection: run the block, which connects (and raises
31
+ # if it can't). It is true when it connects, false otherwise, with
32
+ # a readable error and no backtrace.
33
+ #
34
+ def verify_connection
35
+ yield
36
+ @engine.heap.it.set_to true
37
+ return true
38
+ rescue *database_errors, SystemCallError => e
39
+ @engine.err "Could not connect to #{connection_label}: #{e.message}"
40
+ @engine.heap.it.set_to false
41
+ return false
42
+ end
43
+
44
+ #
45
+ # Report a setup problem (eg. no database name) and return nil,
46
+ # meaning no result.
47
+ #
48
+ def setup_err( msg )
49
+ @engine.err msg
50
+ return nil
51
+ end
52
+
53
+ #
54
+ # How the connection is named in messages, eg. sqlite 'db'.
55
+ #
56
+ def connection_label
57
+ return "#{self.class.typename} '#{name}'"
58
+ end
59
+
60
+ end
data/lib/gloo-db.rb CHANGED
@@ -1,8 +1,9 @@
1
- #
2
- # Shim to allow `require 'gloo-mysql'`
3
- #
1
+ #
2
+ # Shim to allow `require 'gloo-db'`
3
+ #
4
4
  # This file is loaded when someone does `require 'gloo-mysql'`
5
5
  #
6
+ require 'db_connection'
6
7
  require 'query'
7
8
  require 'query_result'
8
9
  require 'table'
data/lib/query.rb CHANGED
@@ -17,6 +17,7 @@ class Query < Gloo::Core::Obj
17
17
  SIMPLE_LIST = 'simple_list'.freeze
18
18
 
19
19
  DB_MISSING_ERR = 'The database connection is missing!'.freeze
20
+ QUERY_FAILED = 'Query failed: '.freeze
20
21
 
21
22
  #
22
23
  # The name of the object type.
@@ -79,45 +80,43 @@ class Query < Gloo::Core::Obj
79
80
 
80
81
  #
81
82
  # Run the query and process the results.
83
+ # It is true when the query ran, false if it failed.
82
84
  #
83
85
  def msg_run
84
86
  db = db_obj
85
- return unless db
87
+ return @engine.heap.it.set_to( false ) unless db
86
88
 
87
- begin
88
- clear_results
89
+ sql = sql_value
90
+ return @engine.heap.it.set_to( false ) unless sql
89
91
 
90
- log_query sql_value, param_array
91
- result = db.query( sql_value, param_array )
92
- process_result( result, db )
93
- rescue => e
94
- @engine.log_exception e
95
- return
96
- end
92
+ # Clear first, so a failed query doesn't leave the last results.
93
+ clear_results
94
+ result = execute( db, sql )
95
+ return @engine.heap.it.set_to( false ) unless result
96
+
97
+ process_result( result, db )
98
+ @engine.heap.it.set_to true
97
99
  end
98
100
 
99
101
  #
100
- # Run the query and return the results.
102
+ # Run the query and return the results (used by table).
103
+ # Returns nil if the query failed; the failure is reported.
101
104
  #
102
105
  def run_query
103
106
  db = db_obj
104
- return unless db
105
-
106
- begin
107
- log_query sql_value, param_array
108
-
109
- db_start = ::Time.now
110
- result = db.query( sql_value, param_array )
111
- db_done = ::Time.now
112
- elapsed = ( ( db_done - db_start ) * 1000.0 ).round(2)
113
-
114
- app = @engine.running_app
115
- app.add_db_time elapsed if app
116
- return result
117
- rescue => e
118
- @engine.log_exception e
119
- return
120
- end
107
+ return nil unless db
108
+
109
+ sql = sql_value
110
+ return nil unless sql
111
+
112
+ db_start = ::Time.now
113
+ result = execute( db, sql )
114
+ db_done = ::Time.now
115
+ elapsed = ( ( db_done - db_start ) * 1000.0 ).round(2)
116
+
117
+ app = @engine.running_app
118
+ app.add_db_time elapsed if app
119
+ return result
121
120
  end
122
121
 
123
122
  #
@@ -151,29 +150,71 @@ class Query < Gloo::Core::Obj
151
150
  private
152
151
 
153
152
  #
154
- # Get the database connection.
153
+ # Run the SQL on the database connection. A database error (one of
154
+ # the driver's database_errors) is reported as one readable error,
155
+ # with no backtrace. Returns the result, or nil if the query failed
156
+ # or the driver reported a setup problem.
157
+ #
158
+ def execute( db, sql )
159
+ params = param_array
160
+ log_query sql, params
161
+ return db.query( sql, params )
162
+ rescue *database_errors_for( db ) => e
163
+ @engine.err "#{QUERY_FAILED}#{e.message}"
164
+ return nil
165
+ end
166
+
167
+ #
168
+ # The exception classes that are database errors for the driver.
169
+ # A driver that doesn't say (an older one) counts every
170
+ # StandardError.
171
+ #
172
+ def database_errors_for( db )
173
+ return db.database_errors if db.respond_to?( :database_errors )
174
+
175
+ return [ StandardError ]
176
+ end
177
+
178
+ #
179
+ # Get the database connection. Reports an error and returns nil if
180
+ # there's no database child, its alias points at nothing, or it
181
+ # isn't a database connection.
155
182
  #
156
183
  def db_obj
157
184
  o = find_child DB
158
185
 
159
- unless o
186
+ # No database child, or an alias that doesn't point anywhere yet.
187
+ if o.nil? || o.value.to_s.strip.empty?
160
188
  @engine.err DB_MISSING_ERR
161
189
  return nil
162
190
  end
163
191
 
164
- return Gloo::Objs::Alias.resolve_alias( @engine, o )
192
+ db = Gloo::Objs::Alias.resolve_alias( @engine, o )
193
+ unless db
194
+ @engine.err Gloo::Core::NotFound.object( o.value )
195
+ return nil
196
+ end
197
+
198
+ unless db.respond_to?( :query )
199
+ @engine.err "'#{o.value}' is not a database connection."
200
+ return nil
201
+ end
202
+
203
+ return db
165
204
  end
166
205
 
167
206
  #
168
207
  # Get the SQL from the child object.
169
- # Returns nil if there is none.
208
+ # Reports an error and returns nil if there is none.
170
209
  #
171
210
  def sql_value
172
211
  o = find_child SQL
173
- return nil unless o
174
-
175
212
  o = Gloo::Objs::Alias.resolve_alias( @engine, o )
176
- return o.value
213
+ sql = o&.value.to_s
214
+ return sql unless sql.strip.empty?
215
+
216
+ @engine.err "query '#{name}' has no SQL; put a SQL statement into #{name}.sql first."
217
+ return nil
177
218
  end
178
219
 
179
220
  #
@@ -282,8 +323,13 @@ class Query < Gloo::Core::Obj
282
323
  'params (container) — Optional list of parameters for the query.'
283
324
  ],
284
325
  :messages => [
285
- 'run — Run the query and get back the data.'
326
+ 'run — Run the query and get back the data. It is true when the query ran, false if it failed (with or without a result container).'
286
327
  ],
328
+ :notes => 'Errors (and it is false): no database, a database ' \
329
+ 'alias that points at nothing or at something that is not a ' \
330
+ 'database connection, no SQL, and a database error such as bad ' \
331
+ "SQL or a missing table, reported as 'Query failed: ' and the " \
332
+ "database's message. A failed query clears the result container.",
287
333
  :examples => <<~EXAMPLES.strip
288
334
  sqlite [can] :
289
335
  on_load [script] : run sqlite.sql
data/lib/table.rb CHANGED
@@ -73,17 +73,15 @@ class Table < Gloo::Core::Obj
73
73
 
74
74
  if o.is_a? Query
75
75
  @engine.log.debug "Table getting data from query."
76
- begin
77
- result = o.run_query
78
- return result
79
- rescue => e
80
- @engine.log_exception e
81
- return nil
82
- end
76
+ # Nil if the query failed (Query has reported it).
77
+ return o.run_query
83
78
  else
84
79
  cols = self.columns
85
80
 
86
- if o.children&.first.children.empty?
81
+ # No rows yet.
82
+ return [ cols, [] ] if o.children.empty?
83
+
84
+ if o.children.first.children.empty?
87
85
  # It is a simgle row table.
88
86
  rows = [ cols.map { |h| o.find_child( h )&.value } ]
89
87
  else
@@ -166,14 +164,24 @@ class Table < Gloo::Core::Obj
166
164
 
167
165
  #
168
166
  # Show the table in the CLI.
167
+ # Shows nothing if its query failed (the query reports the error).
169
168
  #
170
169
  def msg_show
170
+ result = data
171
+ return unless result
172
+
171
173
  title = self.value
172
- @engine.platform.table.show headers, data[1], title
174
+ @engine.platform.table.show headers, result[1], title
173
175
  end
174
176
 
177
+ #
178
+ # Render the table as HTML, inside a web app.
179
+ # It has the HTML, or false if the table couldn't be rendered.
180
+ #
175
181
  def msg_render
176
- return render
182
+ html = render
183
+ @engine.heap.it.set_to( html.nil? ? false : html )
184
+ return html
177
185
  end
178
186
 
179
187
 
@@ -185,9 +193,19 @@ class Table < Gloo::Core::Obj
185
193
  # Render the table.
186
194
  # The render_ƒ is 'render_html', 'render_text', 'render_json', etc.
187
195
  #
188
- def render render_ƒ
196
+ def render render_ƒ = :render_html
197
+ # Outside a web app (or without gloo-web) there's no renderer.
198
+ helper = table_renderer
199
+ unless helper
200
+ @engine.err "table '#{name}' can only render inside a web app (gloo-web); use show to see it in the console."
201
+ return nil
202
+ end
203
+
189
204
  begin
190
205
  result = self.data
206
+ # The query failed and has reported it.
207
+ return nil unless result
208
+
191
209
  head = self.headers
192
210
  head = result[0] if head.empty?
193
211
  rows = result[1]
@@ -207,20 +225,24 @@ class Table < Gloo::Core::Obj
207
225
  params[ :always_rows ] = true
208
226
  end
209
227
 
210
- # helper = Gloo::WebSvr::TableRenderer.new( @engine )
211
- helper = @engine.running_app&.create_table_renderer
212
- if helper
213
- return helper.data_to_table params
214
- else
215
- @engine.log.error "Table renderer not found."
216
- return nil
217
- end
228
+ return helper.data_to_table params
218
229
  rescue => e
219
230
  @engine.log_exception e
220
231
  return nil
221
232
  end
222
233
  end
223
234
 
235
+ #
236
+ # The web app's table renderer, or nil outside a web app or when
237
+ # gloo-web isn't loaded.
238
+ #
239
+ def table_renderer
240
+ return nil unless @engine.running_app
241
+ return nil unless defined?( WebSvr::TableRenderer )
242
+
243
+ return @engine.running_app.create_table_renderer
244
+ end
245
+
224
246
  #
225
247
  # Build the column list based on the result data and
226
248
  # the headers defined in the table object.
@@ -285,8 +307,12 @@ class Table < Gloo::Core::Obj
285
307
  'always_rows (boolean) — Optional. By default, if a table\'s data is only 1 row, it shows that row in a vertical table. Marking this true means a horizontal table is shown even if only one row is returned.'
286
308
  ],
287
309
  :messages => [
288
- 'show — Show the contents of the table in the CLI.'
310
+ 'show — Show the contents of the table in the CLI.',
311
+ 'render — Render the table as HTML, inside a web app (gloo-web). It has the HTML. Outside a web app this is an error, and it is false; use show instead.'
289
312
  ],
313
+ :notes => 'If data is a query and the query fails, the query ' \
314
+ 'reports the error and show and render stop without showing ' \
315
+ 'anything.',
290
316
  :examples => <<~EXAMPLES.strip
291
317
  t [tbl] :
292
318
  on_load [script] :
metadata CHANGED
@@ -1,14 +1,82 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gloo-db
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.2'
4
+ version: '1.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Crane
8
8
  bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
- dependencies: []
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: gloo
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: bundler
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: minitest
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.1'
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 5.14.2
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '5.1'
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 5.14.2
60
+ - !ruby/object:Gem::Dependency
61
+ name: rake
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '13.0'
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 13.0.1
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '13.0'
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 13.0.1
12
80
  description: Adds database support to Gloo.
13
81
  email:
14
82
  - eric.crane@mac.com
@@ -17,6 +85,7 @@ extensions: []
17
85
  extra_rdoc_files: []
18
86
  files:
19
87
  - README.md
88
+ - lib/db_connection.rb
20
89
  - lib/gloo-db.rb
21
90
  - lib/query.rb
22
91
  - lib/query_result.rb