db 0.5.1 → 0.10.0

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: 1149f3daa25b0832441ed9c08eeba087be727167ff5ee12b33e2d96a2ae54138
4
- data.tar.gz: efc580a879bc9d91c46bc631a76b5761f276ce24e531daf20bc797e75ea06273
3
+ metadata.gz: f128a427ea4ac05f7182d550d9c9548fb87d1f50d81602a3a9c6e29832f7bb95
4
+ data.tar.gz: 30fa1ea2be7e82e9731f832cf3147b8b794832922cb2f26a9e9faba66a9a00d5
5
5
  SHA512:
6
- metadata.gz: 104d7bce64424a3666c1a699e8b06c655a37dc44f5b025530a422188d386c3b84ad00ccc314ba8d0a4f5b9c931375c21c0799e6d0868064d012220d5fc26e6cd
7
- data.tar.gz: 856321b31c8894f5fe914100b5892cc160c812f56b6bf0cc8ec4f7bc159d9535195bf5c8d406e0ca1116b6fc4d73ecc2527b03d630bf336c6d768060c11918c2
6
+ metadata.gz: 27648baebb40112a422a69d5c464bfd5d984ad86ae495368c5a59fb8900f390f2a97e8e7b969bdfbdae6ab790ae7186436fc48101fc1672b13511cf568cdbd04
7
+ data.tar.gz: 87c2e6137adb9fdfbf33cc42d97ec3d19a5543b72bad9022c8060851a99c6f0a00a0794075bdc7b9e08bd4d84f8e9beef65918f2ed7bbe78ad163d5ed3387a76
data/lib/db/client.rb CHANGED
@@ -24,7 +24,8 @@ require 'async/io'
24
24
  require 'async/io/stream'
25
25
  require 'async/pool/controller'
26
26
 
27
- require_relative 'context/query'
27
+ require_relative 'context/generic'
28
+ require_relative 'context/session'
28
29
  require_relative 'context/transaction'
29
30
 
30
31
  module DB
@@ -47,24 +48,33 @@ module DB
47
48
  @pool.close
48
49
  end
49
50
 
51
+ # Acquire a generic context which will acquire a connection on demand.
52
+ def context(**options)
53
+ context = Context::Generic.new(@pool, **options)
54
+
55
+ return context unless block_given?
56
+
57
+ begin
58
+ yield context
59
+ ensure
60
+ context.close
61
+ end
62
+ end
63
+
50
64
  # Acquires a connection and sends the specified statement if given.
51
65
  # @parameters statement [String | Nil] An optional statement to send.
52
66
  # @yields {|session| ...} A connected session if a block is given. Implicitly closed.
53
- # @parameter session [Context::Query]
54
- # @returns [Context::Query] A connected session if no block is given.
55
- def call(statement = nil, **options)
56
- query = Context::Query.new(@pool, **options)
57
-
58
- if statement
59
- query.send_query(statement)
60
- end
67
+ # @parameter session [Context::Session]
68
+ # @returns [Context::Session] A connected session if no block is given.
69
+ def session(**options)
70
+ session = Context::Session.new(@pool, **options)
61
71
 
62
- return query unless block_given?
72
+ return session unless block_given?
63
73
 
64
74
  begin
65
- yield query
75
+ yield session
66
76
  ensure
67
- query.close
77
+ session.close
68
78
  end
69
79
  end
70
80
 
@@ -73,12 +83,10 @@ module DB
73
83
  # @yields {|session| ...} A connected session if a block is given. Implicitly commits, or aborts the connnection if an exception is raised.
74
84
  # @parameter session [Context::Transaction]
75
85
  # @returns [Context::Transaction] A connected and started transaction if no block is given.
76
- def transaction(statement = "BEGIN", **options)
86
+ def transaction(**options)
77
87
  transaction = Context::Transaction.new(@pool, **options)
78
88
 
79
- if statement
80
- transaction.call("BEGIN")
81
- end
89
+ transaction.call("BEGIN")
82
90
 
83
91
  return transaction unless block_given?
84
92
 
@@ -86,8 +94,8 @@ module DB
86
94
  yield transaction
87
95
 
88
96
  transaction.commit
89
- ensure
90
- transaction.abort if $!
97
+ rescue
98
+ transaction.abort
91
99
  end
92
100
  end
93
101
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
3
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the "Software"), to deal
@@ -20,65 +20,55 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
+ require_relative '../query'
24
+
23
25
  module DB
24
26
  module Context
25
27
  # A connected context for sending queries and reading results.
26
- class Query
28
+ class Generic
27
29
  # Iniitalize the query context attached to the given connection pool.
28
30
  def initialize(pool, **options)
29
31
  @pool = pool
30
- @connection = pool.acquire
32
+ @connection = nil
33
+ end
34
+
35
+ def connection?
36
+ @connection != nil
31
37
  end
32
38
 
33
- # The underlying connection.
34
- attr :connection
39
+ # Lazy initialize underlying connection.
40
+ def connection
41
+ @connection ||= @pool.acquire
42
+ end
35
43
 
36
44
  # Flush the connection and then return it to the connection pool.
37
45
  def close
38
46
  if @connection
39
- self.flush
40
-
41
47
  @pool.release(@connection)
42
-
43
48
  @connection = nil
44
49
  end
45
50
  end
46
51
 
47
- # Send a query to the server.
48
- # @parameter statement [String] The SQL query to send.
49
- def send_query(statement, **options)
50
- @connection.send_query(statement, **options)
52
+ def query(fragment = String.new, **parameters)
53
+ if parameters.empty?
54
+ Query.new(self, fragment)
55
+ else
56
+ Query.new(self).interpolate(fragment, **parameters)
57
+ end
51
58
  end
52
59
 
53
- # Read the next result. Sending a query usually generates 1 or more results.
54
- # @returns [Enumerable] The resulting records.
55
- def next_result
56
- @connection.next_result
60
+ def clause(fragment = String.new)
61
+ Query.new(self, fragment)
57
62
  end
58
63
 
59
- # Send a query to the server and read the next result.
60
- # @returns [Enumerable] The resulting records.
64
+ # Send a query to the server.
65
+ # @parameter statement [String] The SQL query to send.
61
66
  def call(statement, **options)
62
- @connection.send_query(statement, **options)
63
-
64
- return @connection.next_result
65
- end
66
-
67
- # Enumerate all results.
68
- # @yields {|result ...} The results if a block is given.
69
- # @parameter result [Enumerable]
70
- def results
71
- while result = self.next_result
72
- yield result
73
- end
67
+ connection.send_query(statement, **options)
74
68
 
75
- return nil
76
- end
77
-
78
- # Flush all outstanding results.
79
- def flush
80
- until @connection.next_result.nil?
81
- end
69
+ yield connection if block_given?
70
+ ensure
71
+ self.close
82
72
  end
83
73
  end
84
74
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require_relative '../query'
24
+
25
+ module DB
26
+ module Context
27
+ # A connected context for sending queries and reading results.
28
+ class Session < Generic
29
+ # Send a query to the server.
30
+ # @parameter statement [String] The SQL query to send.
31
+ def call(statement, **options)
32
+ connection = self.connection
33
+
34
+ connection.send_query(statement, **options)
35
+
36
+ yield connection if block_given?
37
+ end
38
+ end
39
+ end
40
+ end
@@ -20,11 +20,11 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require_relative 'query'
23
+ require_relative 'session'
24
24
 
25
25
  module DB
26
26
  module Context
27
- class Transaction < Query
27
+ class Transaction < Session
28
28
  # Commit the transaction and return the connection to the connection pool.
29
29
  def commit
30
30
  self.call("COMMIT")
data/lib/db/query.rb ADDED
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ module DB
24
+ # Represents one or more identifiers for databases, tables or columns.
25
+ class Identifier < Array
26
+ def self.coerce(name_or_identifier)
27
+ case name_or_identifier
28
+ when Identifier
29
+ name_or_identifier
30
+ when Array
31
+ self.new(name_or_identifier)
32
+ when Symbol
33
+ self[name_or_identifier]
34
+ else
35
+ self[name_or_identifier.to_sym]
36
+ end
37
+ end
38
+
39
+ def append_to(query)
40
+ query.identifier(self)
41
+ end
42
+ end
43
+
44
+ # A mutable query builder.
45
+ class Query
46
+ # Create a new query builder attached to the specified context.
47
+ # @parameter context [Context::Generic] the context which is used for escaping arguments.
48
+ def initialize(context, buffer = String.new)
49
+ @context = context
50
+ @connection = context.connection
51
+ @buffer = +buffer
52
+ end
53
+
54
+ # Append a raw textual clause to the query buffer.
55
+ # @parameter value [String] A raw SQL string, e.g. `WHERE x > 10`.
56
+ # @returns [Query] The mutable query itself.
57
+ def clause(value)
58
+ @buffer << ' ' unless @buffer.end_with?(' ') || @buffer.empty?
59
+
60
+ @buffer << value
61
+
62
+ return self
63
+ end
64
+
65
+ # Append a literal value to the query buffer.
66
+ # Escapes the field according to the requirements of the underlying connection.
67
+ # @parameter value [Object] Any kind of object, passed to the underlying database connection for conversion to a string representation.
68
+ # @returns [Query] The mutable query itself.
69
+ def literal(value)
70
+ @buffer << ' ' unless @buffer.end_with?(' ')
71
+
72
+ @connection.append_literal(value, @buffer)
73
+
74
+ return self
75
+ end
76
+
77
+ # Append an identifier value to the query buffer.
78
+ # Escapes the field according to the requirements of the underlying connection.
79
+ # @parameter value [String | Symbol | DB::Identifier] Passed to the underlying database connection for conversion to a string representation.
80
+ # @returns [Query] The mutable query itself.
81
+ def identifier(value)
82
+ @buffer << ' ' unless @buffer.end_with?(' ')
83
+
84
+ @connection.append_identifier(value, @buffer)
85
+
86
+ return self
87
+ end
88
+
89
+ # Interpolate a query fragment with the specified parameters.
90
+ # The parameters are escaped before being appended.
91
+ #
92
+ # @parameter fragment [String] A fragment of SQL including placeholders, e.g. `WHERE x > %{column}`.
93
+ # @parameter parameters [Hash] The substitution parameters.
94
+ # @returns [Query] The mutable query itself.
95
+ def interpolate(fragment, **parameters)
96
+ parameters.transform_values! do |value|
97
+ case value
98
+ when Symbol, Identifier
99
+ @connection.append_identifier(value)
100
+ else
101
+ @connection.append_literal(value)
102
+ end
103
+ end
104
+
105
+ @buffer << sprintf(fragment, parameters)
106
+
107
+ return self
108
+ end
109
+
110
+ def key_column(*arguments, **options)
111
+ @buffer << @connection.key_column(*arguments, **options)
112
+
113
+ return self
114
+ end
115
+
116
+ # Send the query to the remote server to be executed. See {Context::Session#call} for more details.
117
+ # @returns [Enumerable] The resulting records.
118
+ def call(&block)
119
+ @context.call(@buffer, &block)
120
+ end
121
+
122
+ def to_s
123
+ @buffer
124
+ end
125
+
126
+ def inspect
127
+ "\#<#{self.class} #{@buffer.inspect}>"
128
+ end
129
+ end
130
+ end
data/lib/db/version.rb CHANGED
@@ -21,5 +21,5 @@
21
21
  # THE SOFTWARE.
22
22
 
23
23
  module DB
24
- VERSION = "0.5.1"
24
+ VERSION = "0.10.0"
25
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: db
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-07 00:00:00.000000000 Z
11
+ date: 2021-04-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-io
@@ -89,8 +89,10 @@ files:
89
89
  - lib/db.rb
90
90
  - lib/db/adapters.rb
91
91
  - lib/db/client.rb
92
- - lib/db/context/query.rb
92
+ - lib/db/context/generic.rb
93
+ - lib/db/context/session.rb
93
94
  - lib/db/context/transaction.rb
95
+ - lib/db/query.rb
94
96
  - lib/db/version.rb
95
97
  homepage: https://github.com/socketry/db
96
98
  licenses:
@@ -111,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
113
  - !ruby/object:Gem::Version
112
114
  version: '0'
113
115
  requirements: []
114
- rubygems_version: 3.1.2
116
+ rubygems_version: 3.2.3
115
117
  signing_key:
116
118
  specification_version: 4
117
119
  summary: A low level database access gem.