db_mod 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/CHANGELOG.md +7 -1
  4. data/README.md +53 -5
  5. data/lib/db_mod/exceptions/bad_method_configuration.rb +11 -0
  6. data/lib/db_mod/exceptions/no_results.rb +12 -0
  7. data/lib/db_mod/exceptions/too_many_results.rb +12 -0
  8. data/lib/db_mod/exceptions.rb +4 -1
  9. data/lib/db_mod/statements/configuration/as/csv.rb +39 -0
  10. data/lib/db_mod/statements/configuration/as/json.rb +33 -0
  11. data/lib/db_mod/statements/configuration/as.rb +47 -0
  12. data/lib/db_mod/statements/configuration/configurable_method.rb +78 -0
  13. data/lib/db_mod/statements/configuration/single/column.rb +29 -0
  14. data/lib/db_mod/statements/configuration/single/required_row.rb +35 -0
  15. data/lib/db_mod/statements/configuration/single/required_value.rb +35 -0
  16. data/lib/db_mod/statements/configuration/single/row.rb +33 -0
  17. data/lib/db_mod/statements/configuration/single/value.rb +32 -0
  18. data/lib/db_mod/statements/configuration/single.rb +63 -0
  19. data/lib/db_mod/statements/configuration.rb +48 -0
  20. data/lib/db_mod/statements/parameters.rb +1 -1
  21. data/lib/db_mod/statements/prepared.rb +6 -11
  22. data/lib/db_mod/statements/statement.rb +28 -10
  23. data/lib/db_mod/statements.rb +1 -38
  24. data/lib/db_mod/version.rb +1 -1
  25. data/lib/db_mod.rb +4 -2
  26. data/spec/db_mod/{as → statements/configuration/as}/csv_spec.rb +7 -6
  27. data/spec/db_mod/statements/configuration/as/json_spec.rb +38 -0
  28. data/spec/db_mod/statements/configuration/as_spec.rb +24 -0
  29. data/spec/db_mod/statements/configuration/single_spec.rb +106 -0
  30. metadata +25 -9
  31. data/lib/db_mod/as/csv.rb +0 -37
  32. data/lib/db_mod/as.rb +0 -38
  33. data/lib/db_mod/statements/configurable_method.rb +0 -41
  34. data/spec/db_mod/as_spec.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1fe4bb1c7e19c817bad5e788d2cd626ce909ba0d
4
- data.tar.gz: 3bb72d90d2387e7f8e7373f41d390f779b0cc819
3
+ metadata.gz: 9f9ed4ad3824fbe0a2b09444c5aa9b4dde35ee94
4
+ data.tar.gz: 4a70f5c7416895da2fb5cc58608d5aaabeb610ce
5
5
  SHA512:
6
- metadata.gz: b9318f1de5b1fe4c8189c7bc1d03cb42533316175411bb33440824e0051dd33da5c4c64595658e95d001b8995fca4fa4e4c67d24570e229e48418d4cfd346f5e
7
- data.tar.gz: fe369f08a3c480d4c5d3322c35b575ecccb5cbada2b7db33f5b05a3fd692ad5d17cbc9580fabf2356e936b7886d28d1cc7d322e605ad3f6f3f2b04ad5523fa1e
6
+ metadata.gz: 22b0da036c7e04ee7f70d21c79a5dcb70db35895485ee8b1a9bae150a258be8a5c529023c0b71c1f6e74c80ddb911d8f0915d4ef341db88286c48bfaab8bf182
7
+ data.tar.gz: 23a8967663138b1b10d83d994b7b397dd00b8c536663d1a58b1227f6434a47334d7f1d77fcb58a86048d5bfcdbf30e8ab6800eb818d9f37116083cce35b2c0e1
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --private --protected lib/**/*.rb - *.md LICENSE
data/CHANGELOG.md CHANGED
@@ -1,7 +1,13 @@
1
+ 0.0.4 (2015-10-15)
2
+ ==================
3
+
4
+ * Adds `def_prepared/statement.single(:value/:row/:column)` - [@dslh](https://github.com/dslh).
5
+ * Adds `.as(:json)` to go with `.as(:csv)` - [@dslh](https://github.com/dslh).
6
+
1
7
  0.0.3 (2015-10-13)
2
8
  ==================
3
9
 
4
- * Configurable method framework. Adds `def_prepared/statement.as(:csv)` - [@dslh](https://github.com/dslh)
10
+ * Configurable method framework. Adds `def_prepared/statement.as(:csv)` - [@dslh](https://github.com/dslh).
5
11
 
6
12
  0.0.2 (2015-10-12)
7
13
  ==================
data/README.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  Database enabled modules for ruby.
4
4
 
5
+ [![GitHub version](https://badge.fury.io/gh/dslh%2Fdb_mod.svg)](https://github.com/dslh/db_mod)
6
+ [![Gem Version](https://badge.fury.io/rb/db_mod.svg)](https://rubygems.org/gems/db_mod)
7
+ [![Travis CI](https://img.shields.io/travis/dslh/db_mod/master.svg)](https://travis-ci.org/dslh/db_mod)
8
+ ![Gem downloads](https://img.shields.io/gem/dt/db_mod.svg)
9
+
10
+ [Rubydoc.info documentation](http://www.rubydoc.info/gems/db_mod)
11
+
5
12
  ## Description
6
13
 
7
14
  The `db_mod` gem is a simple framework that helps you organise your
@@ -187,19 +194,60 @@ or twice during a program's execution.
187
194
  #### Configuring defined statements
188
195
 
189
196
  `db_mod` contains a simple framework for extending these statement methods
190
- and prepared methods with additional argument and result processing. For
191
- now only `.as(:csv)` is supported, which will cause the method to format
192
- the SQL result set as a CSV string.
197
+ and prepared methods with additional result processing. A simple
198
+ chained-method syntax is used
199
+
200
+ ##### JSON and CSV formatting
201
+
202
+ Statement and prepared methods can be configured on declaration by using
203
+ `.as(:csv)` and `.as(:json)`, which will convert the result set to a string
204
+ formatted as either a CSV document or an array of JSON objects, respectively.
193
205
 
194
206
  ```ruby
195
- module CsvReports
207
+ module Reports
196
208
  include DbMod
197
209
 
198
210
  def_prepared(:foo, 'SELECT a, b FROM foo WHERE bar_id = $id').as(:csv)
211
+ def_statement(:bar, 'SElECT c, d FROM bar WHERE foo_id = $1').as(:json)
199
212
  end
200
213
 
201
- include CsvReports
214
+ include Reports
202
215
  db_connect db: 'testdb'
203
216
 
204
217
  foo(id: 1) # => "a,b\n1,2\n3,4\n..."
218
+ bar(2) # => '[{"c":"5","d":"6"},...]'
219
+ ```
220
+
221
+ ##### Queries returning one row, column or value
222
+
223
+ To save a lot of repetetive unboxing of query results, methods that return
224
+ only one row, or rows with only one column, or only one row with a single
225
+ value, can be marked as such using the `.single` extension.
226
+
227
+ ```ruby
228
+ module Getters
229
+ include DbMod
230
+
231
+ def_prepared(:user, 'SELECT * FROM user WHERE id = $1').single(:row)
232
+ def_prepared(:name, 'SELECT name FROM user WHERE id = $1').single(:value)
233
+ def_statement(:ids, 'SELECT id FROM user').single(:column)
234
+ end
235
+
236
+ # ...
237
+
238
+ user(1) # => { "id" => "1", "name" => "username" }
239
+ name(1) # => "username"
240
+ ids # => ['1', '2', '3', ...]
241
+ ```
242
+
243
+ When no results are returned, `:column` returns `[]` while `:row` and
244
+ `:value` will return `nil`. To raise an exception instead of returning
245
+ `nil`, use `:row!` and `:value!` instead.
246
+
247
+ ```ruby
248
+ def_statement(:a, 'SELECT 1 WHERE true = false').single(:value)
249
+ def_statement(:b, 'SELECT 1 WHERE true = false').single(:value!)
250
+
251
+ a # => nil
252
+ b # => fail
205
253
  ```
@@ -0,0 +1,11 @@
1
+ require_relative 'base'
2
+
3
+ module DbMod
4
+ module Exceptions
5
+ # Raised when an attempt is made to configure
6
+ # a dynamically defined statement or prepared method
7
+ # in an invalid way.
8
+ class BadMethodConfiguration < Base
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'base'
2
+
3
+ module DbMod
4
+ module Exceptions
5
+ # Raised by a statement or prepared method that
6
+ # has been configured using {ConfigurableMethod#single},
7
+ # when a result set expected to contain at least one
8
+ # result does not.
9
+ class NoResults < Base
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'base'
2
+
3
+ module DbMod
4
+ module Exceptions
5
+ # Raised by a statement or prepared method that
6
+ # has been configured using {ConfigurableMethod#single},
7
+ # when a result set expected to contain not more than
8
+ # one result, in fact, does.
9
+ class TooManyResults < Base
10
+ end
11
+ end
12
+ end
@@ -1,6 +1,9 @@
1
- require_relative 'exceptions/connection_not_set'
2
1
  require_relative 'exceptions/already_in_transaction'
2
+ require_relative 'exceptions/bad_method_configuration'
3
+ require_relative 'exceptions/connection_not_set'
3
4
  require_relative 'exceptions/duplicate_statement_name'
5
+ require_relative 'exceptions/no_results'
6
+ require_relative 'exceptions/too_many_results'
4
7
 
5
8
  module DbMod
6
9
  # Non-standard errors raised by db_mod
@@ -0,0 +1,39 @@
1
+ module DbMod
2
+ module Statements
3
+ module Configuration
4
+ module As
5
+ # Coercer which converts an SQL result set
6
+ # into a string formatted as a CSV document.
7
+ # May be enabled for a prepared method or
8
+ # statement method using +.as(:csv)+:
9
+ #
10
+ # def_statement(:a, 'SELECT a, b FROM foo').as(:csv)
11
+ # def_prepared(:b, 'SELECT b, c FROM bar').as(:csv)
12
+ #
13
+ # def do_stuff
14
+ # a # => "a,b\r\n1,2\r\n3,4\r\n..."
15
+ # end
16
+ module Csv
17
+ # Enables this module to be passed to
18
+ # {DbMod::Statements::Configuration.process_method_results} as the
19
+ # +wrapper+ function, in which case it will retrieve the results
20
+ # and format them as a CSV document using the column names
21
+ # from the result set.
22
+ #
23
+ # @param results [Object] SQL result set
24
+ # @return [String] a CSV formatted document
25
+ def self.call(results)
26
+ headers = nil
27
+ CSV.generate do |csv|
28
+ results.each do |row|
29
+ csv << (headers = row.keys) unless headers
30
+
31
+ csv << headers.map { |col| row[col] }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ module DbMod
2
+ module Statements
3
+ module Configuration
4
+ module As
5
+ # Coercer which converts an SQL result set
6
+ # into a string formatted as a JSON array.
7
+ # May be enabled for a prepared method or
8
+ # statement method using +.as(:json)+:
9
+ #
10
+ # def_statement(:a, 'SELECT a, b FROM foo').as(:json)
11
+ # def_prepared(:b, 'SELECT b, c FROM bar').as(:json)
12
+ #
13
+ # def do_stuff
14
+ # a # => '[{"a":"x","b":"y"},...]'
15
+ # end
16
+ module Json
17
+ # Enables this module to be passed to
18
+ # {DbMod::Statements::Configuration.process_method_results} as the
19
+ # +wrapper+ function, in which case it will retrieve the results
20
+ # and format them as a JSON string using the column names
21
+ # from the result set for the keys of each object.
22
+ #
23
+ # @param results [Object] SQL result set
24
+ # @return [String] a JSON formatted string
25
+ def self.call(results)
26
+ # .map turns the result object into an array
27
+ results.map { |x| x }.to_json
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'as/csv'
2
+ require_relative 'as/json'
3
+
4
+ module DbMod
5
+ module Statements
6
+ module Configuration
7
+ # Contains coercers and other functions that allow
8
+ # module instance methods returning an SQL result set
9
+ # to be extended with additional result coercion and
10
+ # formatting. The normal way to access this functionality
11
+ # is via {ConfigurableMethod#as},
12
+ # which is available when defining a statement method
13
+ # or prepared method:
14
+ #
15
+ # def_statement(:a, 'SELECT a, b, c FROM foo').as(:csv)
16
+ # def_prepared(:b, 'SELECT d, e, f FROM bar').as(:csv)
17
+ module As
18
+ # For extend_method
19
+ Configuration = DbMod::Statements::Configuration
20
+
21
+ # List of available result coercion methods.
22
+ # Only keys defined here are allowed as arguments
23
+ # to {DbMod::Statements::Configuration::ConfigurableMethod#as}.
24
+ COERCERS = {
25
+ csv: As::Csv,
26
+ json: As::Json
27
+ }
28
+
29
+ # Extend a method so that the SQL result set it
30
+ # returns will be coerced to the given type.
31
+ # See {COERCERS} for a list of defined coercion
32
+ # methods.
33
+ #
34
+ # @param mod [Module] module where the method has been defined
35
+ # @param name [Symbol] method name
36
+ # @param type [Symbol] type to which result set should be coerced
37
+ def self.extend_method(mod, name, type)
38
+ unless COERCERS.key? type
39
+ fail ArgumentError, "#{type} not in #{COERCERS.keys.join ', '}"
40
+ end
41
+
42
+ Configuration.process_method_results(mod, name, COERCERS[type])
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,78 @@
1
+ require_relative 'as'
2
+ require_relative 'single'
3
+
4
+ module DbMod
5
+ module Statements
6
+ module Configuration
7
+ # Encapsulates a method that has just been defined
8
+ # via the dsl exposed in {DbMod::Statements} so that
9
+ # it can be extended with additional processing such
10
+ # as result coercion.
11
+ #
12
+ # The pattern here is something similar to rack's middleware.
13
+ # Calling any of the extension methods below will replace
14
+ # the original method defined by +def_prepared+ or +def_statement+
15
+ # with a wrapper function that may perform processing on given
16
+ # arguments, pass them to the original function, then perform
17
+ # additional processing on the result.
18
+ class ConfigurableMethod
19
+ # Encapsulate a method that has been newly defined
20
+ # by a {DbMod} dsl function, for additional configuration.
21
+ #
22
+ # @param mod [Module] the {DbMod} enabled module
23
+ # where the method was defined
24
+ # @param name [Symbol] the method name
25
+ def initialize(mod, name)
26
+ @mod = mod
27
+ @name = name
28
+ @already_called = {}
29
+ end
30
+
31
+ # Extend the method by converting results into a given
32
+ # format, using one of the coercion methods defined
33
+ # under {DbMod::Statements::Configuration::As}.
34
+ #
35
+ # @param type [:csv,:json] output format for the method
36
+ # @return [self]
37
+ def as(type)
38
+ called! :as
39
+
40
+ Configuration::As.extend_method(@mod, @name, type)
41
+
42
+ self
43
+ end
44
+
45
+ # Extend the method by extracting a singular part of
46
+ # the result set, for queries expected to only return
47
+ # one row, one column, or one row with a single value.
48
+ # See {DbMod::Statements::Configuration::Single} for
49
+ # more details.
50
+ #
51
+ # @param type [Symbol] see {SINGLE_TYPES}
52
+ # @return [self]
53
+ def single(type)
54
+ called! :single
55
+
56
+ Configuration::Single.extend_method(@mod, @name, type)
57
+
58
+ self
59
+ end
60
+
61
+ private
62
+
63
+ # Guard method which asserts that a configuration method
64
+ # may not be called more than once, or else raises
65
+ # {DbMod::Exceptions::BadMethodConfiguration}.
66
+ #
67
+ # @param method [Symbol] method being called
68
+ def called!(method)
69
+ if @already_called[method]
70
+ fail Exceptions::BadMethodConfiguration, "#{method} already called"
71
+ end
72
+
73
+ @already_called[method] = true
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,29 @@
1
+ module DbMod
2
+ module Statements
3
+ module Configuration
4
+ module Single
5
+ # Wrapper for a statement or prepared method that returns
6
+ # an array of the values from the first value of every row
7
+ # returned by the SQL statement.
8
+ #
9
+ # def_statement(:a, 'SELECT a FROM b').single(:column)
10
+ #
11
+ # def do_stuff
12
+ # a # => ['a', 'b', 'c']
13
+ # end
14
+ module Column
15
+ # Enables this module to be passed to
16
+ # {DbMod::Statements::Configuration.process_method_results} as the
17
+ # +wrapper+ function, where it will return an array of the first
18
+ # value from every row in the result set.
19
+ #
20
+ # @param results [Object] SQL result set
21
+ # @return [Array<String>] an array of values from the first column
22
+ def self.call(results)
23
+ results.map { |row| row[row.keys.first] }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ module DbMod
2
+ module Statements
3
+ module Configuration
4
+ module Single
5
+ # Wrapper for a statement or prepared method that returns
6
+ # only the first row of the result set as a hash, to save
7
+ # manual unboxing. Raises an error unless exactly one row
8
+ # is returned.
9
+ #
10
+ # def_statement(:a, 'SELECT a, b FROM foo').single(:row)
11
+ #
12
+ # def do_stuff
13
+ # a # => { 'a' => '1', 'b' => '2'
14
+ # end
15
+ module RequiredRow
16
+ # Enables this module to be passed to
17
+ # {DbMod::Statements::Configuration.process_method_results} as the
18
+ # +wrapper+ function, where it will return the first row of the
19
+ # result set, or raise an exception if exactly one row is not
20
+ # returned.
21
+ #
22
+ # @param results [Object] SQL result set
23
+ # @return [Hash<String,String>]
24
+ # the first row of the SQL result set returned by the query
25
+ def self.call(results)
26
+ fail DbMod::Exceptions::NoResults unless results.any?
27
+ fail DbMod::Exceptions::TooManyResults if results.count > 1
28
+
29
+ results[0]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ module DbMod
2
+ module Statements
3
+ module Configuration
4
+ module Single
5
+ # Wrapper for a statement or prepared method that returns
6
+ # the first column of the first returned row. Strictly enforces
7
+ # that exactly one row should be returned by the SQL result, and
8
+ # will fail if zero or more than one row is returned.
9
+ #
10
+ # def_statement(:a, 'SELECT 1').single(:value!)
11
+ #
12
+ # def do_stuff
13
+ # a # => '1'
14
+ # end
15
+ module RequiredValue
16
+ # Enables this module to be passed to
17
+ # {DbMod::Statements::Configuration.process_method_results} as the
18
+ # +wrapper+ function, where it will return the first column of the
19
+ # first row of the result set, or fail if anything other than
20
+ # exactly one row is returned.
21
+ #
22
+ # @param results [Object] SQL result set
23
+ # @return [String] the first column of the first returned row
24
+ def self.call(results)
25
+ fail DbMod::Exceptions::NoResults unless results.any?
26
+ fail DbMod::Exceptions::TooManyResults if results.count > 1
27
+
28
+ row = results[0]
29
+ row[row.keys.first]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,33 @@
1
+ module DbMod
2
+ module Statements
3
+ module Configuration
4
+ module Single
5
+ # Wrapper for a statement or prepared method that returns
6
+ # only the first row of the result set as a hash, to save
7
+ # manual unboxing. Returns +nil+ if the query returns no
8
+ # results.
9
+ #
10
+ # def_statement(:a, 'SELECT a, b FROM foo').single(:row)
11
+ #
12
+ # def do_stuff
13
+ # a # => { 'a' => '1', 'b' => '2'
14
+ # end
15
+ module Row
16
+ # Enables this module to be passed to
17
+ # {DbMod::Statements::Configuration.process_method_results} as the
18
+ # +wrapper+ function, where it will return the first row of the
19
+ # result set, or +nil+ if the result set is empty.
20
+ #
21
+ # @param results [Object] SQL result set
22
+ # @return [Hash<String,String>,nil]
23
+ # the first row of the SQL result set returned by the query
24
+ def self.call(results)
25
+ return nil unless results.any?
26
+
27
+ results[0]
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ module DbMod
2
+ module Statements
3
+ module Configuration
4
+ module Single
5
+ # Wrapper for a statement or prepared method that
6
+ # returns the first column of the first returned row,
7
+ # or +nil+ if no rows are returned by the query.
8
+ #
9
+ # def_statement(:a, 'SELECT 1').single(:value)
10
+ #
11
+ # def do_stuff
12
+ # a # => '1'
13
+ # end
14
+ module Value
15
+ # Enables this module to be passed to
16
+ # {DbMod::Statements::Configuration.process_method_results} as the
17
+ # +wrapper+ function, where it will return the first column of the
18
+ # first row of the result set, or +nil+ if no results are returned.
19
+ #
20
+ # @param results [Object] SQL result set
21
+ # @return [String,nil] the first column of the first returned row
22
+ def self.call(results)
23
+ return nil unless results.any?
24
+
25
+ row = results[0]
26
+ row[row.keys.first]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,63 @@
1
+ require_relative 'single/value'
2
+ require_relative 'single/required_value'
3
+ require_relative 'single/row'
4
+ require_relative 'single/required_row'
5
+ require_relative 'single/column'
6
+
7
+ module DbMod
8
+ module Statements
9
+ module Configuration
10
+ # Provides convenience extensions for statement and
11
+ # prepared methods that return only a single result,
12
+ # row, or column. The normal way to access this functionality
13
+ # is via {ConfigurableMethod#single}, which is available
14
+ # when defining a statement method or prepared method:
15
+ #
16
+ # def_statement(:a, 'SELECT name FROM a WHERE id=$1').single(:value)
17
+ # def_prepared(:b, 'SELECT id FROM b WHERE value > $min').single(:column)
18
+ # def_prepared(:c, 'SELECT * FROM c WHERE id = $id').single(:row)
19
+ #
20
+ # def do_stuff
21
+ # a # => "foo"
22
+ # b # => ['1','2','3',...]
23
+ # c # => Hash
24
+ # end
25
+ #
26
+ # +.single(:row)+ and +.single(:value)+ will return the first
27
+ # row or the first value of the first row respectively, or +nil+
28
+ # if no results are found. To generate a
29
+ # {DbMod::Exceptions::NoResults} failure
30
+ # instead of returning +nil+, use +.single(:row!)+ or
31
+ # +.single(:value!)+.
32
+ module Single
33
+ # For process_method_results
34
+ Configuration = DbMod::Statements::Configuration
35
+
36
+ # List of allowed parameters for {#single},
37
+ # and the methods used to process them.
38
+ COERCERS = {
39
+ value: Single::Value,
40
+ value!: Single::RequiredValue,
41
+ row: Single::Row,
42
+ row!: Single::RequiredRow,
43
+ column: Single::Column
44
+ }
45
+
46
+ # Extend a method so that only some singular part of
47
+ # the SQL result set is returned.
48
+ # See above for more details.
49
+ #
50
+ # @param mod [Module] module where the method has been defined
51
+ # @param name [Symbol] method name
52
+ # @param type [Symbol] one of {SINGLE_TYPES}
53
+ def self.extend_method(mod, name, type)
54
+ unless COERCERS.key? type
55
+ fail ArgumentError, "#{type} not in #{COERCERS.keys.join ', '}"
56
+ end
57
+
58
+ Configuration.process_method_results(mod, name, COERCERS[type])
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,48 @@
1
+ module DbMod
2
+ module Statements
3
+ # Provides additional functionality to statement and
4
+ # prepared methods, allowing additional processing of
5
+ # arguments and results using the dsl extensions
6
+ # exposed via {ConfigurableMethod}.
7
+ module Configuration
8
+ # Used by submodules to when defining a method as declared by
9
+ # +def_statement+ or +def_prepared+. Wraps the defined method
10
+ # so that it may be extended with additional argument and
11
+ # result processing.
12
+ #
13
+ # @param mod [Module] the module where the method has been declared
14
+ # @param name [Symbol] the name of the module that has been defined
15
+ # @param definition [Proc] method definition
16
+ # @return [DbMod::Statements::ConfigurableMethod] dsl object for
17
+ # further extending the method
18
+ def self.def_configurable(mod, name, definition)
19
+ mod.instance_eval { define_method(name, definition) }
20
+
21
+ ConfigurableMethod.new(mod, name)
22
+ end
23
+
24
+ # Used by {ConfigurableMethod} (and associated code) to wrap a defined
25
+ # statement method or prepared method with additional result processing.
26
+ # A method should be provided, which accepts an SQL result set and
27
+ # returns some transformation of the results. The original method
28
+ # declaration will be replaced, so that the original method definition
29
+ # is called and the results are passed through this given method.
30
+ #
31
+ # @param mod [Module] the module where the method has been defined
32
+ # @param name [Symbol] the method name
33
+ # @param wrapper [#call]
34
+ # a function that processes the SQL results in some way
35
+ def self.process_method_results(mod, name, wrapper)
36
+ mod.instance_eval do
37
+ wrapped = instance_method(name)
38
+
39
+ define_method(name, lambda do |*args|
40
+ wrapper.call wrapped.bind(self).call(*args)
41
+ end)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ require_relative 'configuration/configurable_method'
@@ -78,7 +78,7 @@ module DbMod
78
78
  # Assert that the given parameter list is an array
79
79
  # containing a single hash of named parameter values.
80
80
  #
81
- # Raises {ArgumentError} otherwise.
81
+ # Raises +ArgumentError+ otherwise.
82
82
  #
83
83
  # @param args [Array<Hash<Symbol>>] method arguments being validated
84
84
  def self.wrapped_hash!(args)
@@ -10,23 +10,18 @@ module DbMod
10
10
  # For statements that are not prepared ahead of execution,
11
11
  # see +def_statement+ in {DbMod::Statements::Statement}.
12
12
  #
13
- # def_prepared
14
- # ------------
15
- #
16
13
  # +def_prepared+ accepts two parameters:
17
- # * `name` [Symbol]: The name that will be given to
14
+ # * *name* [Symbol]: The name that will be given to
18
15
  # the prepared statement. A method will also be defined
19
16
  # on the module with the same name which will call the
20
17
  # statement and return the result.
21
- # * `sql` [String]: The SQL statement to be prepared.
18
+ # * *sql* [String]: The SQL statement to be prepared.
22
19
  # Parameters may be declared using the $ symbol followed
23
- # by a number ($1, $2, $3) or a name ($one, $two, $under_scores).
20
+ # by a number +($1, $2, $3)+ or a name +($one, $two, $a_b)+.
24
21
  # The two styles may not be mixed in the same statement.
25
22
  # The defined function can then be passed parameters
26
23
  # that will be used when the statement is executed.
27
24
  #
28
- # ### example
29
- #
30
25
  # module MyModule
31
26
  # include DbMod
32
27
  #
@@ -146,7 +141,7 @@ module DbMod
146
141
  # and the prepared query to be called.
147
142
  def self.define_no_args_prepared_method(mod, name)
148
143
  method = ->() { conn.exec_prepared(name.to_s) }
149
- Statements.configurable_method mod, name, method
144
+ Configuration.def_configurable mod, name, method
150
145
  end
151
146
 
152
147
  # Define a method with the given name that accepts the
@@ -164,7 +159,7 @@ module DbMod
164
159
  conn.exec_prepared(name.to_s, args)
165
160
  end
166
161
 
167
- Statements.configurable_method mod, name, method
162
+ Configuration.def_configurable mod, name, method
168
163
  end
169
164
 
170
165
  # Define a method with the given name that accepts a fixed
@@ -185,7 +180,7 @@ module DbMod
185
180
  conn.exec_prepared(name.to_s, args)
186
181
  end
187
182
 
188
- Statements.configurable_method(mod, name, method)
183
+ Configuration.def_configurable(mod, name, method)
189
184
  end
190
185
 
191
186
  # Adds +prepared_statements+ to a module. This list of named
@@ -10,20 +10,38 @@ module DbMod
10
10
  # To declare prepared statements, see +def_prepared+
11
11
  # in {DbMod::Statements::Prepared}.
12
12
  #
13
- # def_statement
14
- # -------------
15
- #
16
13
  # +def_statement+ accepts two parameters:
17
- # * `name` [Symbol]: The name that will be given to the
14
+ # * *name* [Symbol]: The name that will be given to the
18
15
  # method that can be used to execute the SQL statement
19
16
  # and return the result.
20
- # * `sql` [String]: The SQL statement that shoul be executed
17
+ # * *sql* [String]: The SQL statement that shoul be executed
21
18
  # when the method is called. Parameters may be declared
22
- # using the $ symbol followed by a number ($1, $2, $3) or
23
- # a name ($one, $two, $under_scores). The two styles may
19
+ # using the $ symbol followed by a number +($1, $2, $3)+ or
20
+ # a name +($one, $two, $under_scores)+. The two styles may
24
21
  # not be mixed in the same statement. The defined function
25
22
  # can then be passed parameters that will be used to fill
26
23
  # in the statement before execution.
24
+ #
25
+ # module MyModule
26
+ # include DbMod
27
+ #
28
+ # def_prepared :my_prepared, <<-SQL
29
+ # SELECT *
30
+ # FROM stuff
31
+ # WHERE a = $1 AND b = $2
32
+ # SQL
33
+ #
34
+ # def_prepared :my_named_prepared, <<-SQL
35
+ # SELECT *
36
+ # FROM stuff
37
+ # WHERE a = $a AND b = $b
38
+ # SQL
39
+ # end
40
+ #
41
+ # include MyModule
42
+ # db_connect db: 'mydb'
43
+ # my_prepared(1,2)
44
+ # my_named_prepared(a: 1, b: 2)
27
45
  module Statement
28
46
  # Defines a module-specific +def_statement+ function
29
47
  # for a module that has just had {DbMod} included.
@@ -83,7 +101,7 @@ module DbMod
83
101
  # @param name [Symbol] name of the method to be defined
84
102
  # @param sql [String] parameterless SQL statement to execute
85
103
  def self.define_no_args_statement_method(mod, name, sql)
86
- Statements.configurable_method mod, name, ->() { query(sql) }
104
+ Configuration.def_configurable mod, name, ->() { query(sql) }
87
105
  end
88
106
 
89
107
  # Define a method with the given name, that accepts the
@@ -99,7 +117,7 @@ module DbMod
99
117
  conn.exec_params(sql, args)
100
118
  end
101
119
 
102
- Statements.configurable_method mod, name, method
120
+ Configuration.def_configurable mod, name, method
103
121
  end
104
122
 
105
123
  # Define a method with the given name that accepts a fixed number
@@ -117,7 +135,7 @@ module DbMod
117
135
  conn.exec_params(sql, args)
118
136
  end
119
137
 
120
- Statements.configurable_method mod, name, method
138
+ Configuration.def_configurable mod, name, method
121
139
  end
122
140
  end
123
141
  end
@@ -1,4 +1,4 @@
1
- require_relative 'statements/configurable_method'
1
+ require_relative 'statements/configuration'
2
2
  require_relative 'statements/statement'
3
3
  require_relative 'statements/prepared'
4
4
 
@@ -16,42 +16,5 @@ module DbMod
16
16
  DbMod::Statements::Prepared.setup(mod)
17
17
  DbMod::Statements::Statement.setup(mod)
18
18
  end
19
-
20
- # Used by submodules to when defining a method as declared by
21
- # +def_statement+ or +def_prepared+. Wraps the defined method
22
- # so that it may be extended with additional argument and
23
- # result processing.
24
- #
25
- # @param mod [Module] the module where the method has been declared
26
- # @param name [Symbol] the name of the module that has been defined
27
- # @param definition [Proc] method definition
28
- # @return [DbMod::Statements::ConfigurableMethod] dsl object for
29
- # further extending the method
30
- def self.configurable_method(mod, name, definition)
31
- mod.instance_eval { define_method(name, definition) }
32
-
33
- ConfigurableMethod.new(mod, name)
34
- end
35
-
36
- # Used by {ConfigurableMethod} (and associated code) to wrap a defined
37
- # statement method or prepared method with additional parameter or result
38
- # processing. A wrapper method definition should be provided, which will
39
- # be called in place of the original method. It will be called with the
40
- # original method proc as a first argument followed by the original
41
- # method arguments (before +DbMod+ has made any attempt to validate them!).
42
- # It is expected to yield to the original proc at some point, although it
43
- # is allowed to do whatever it wants with the results before returning them.
44
- #
45
- # @param mod [Module] the module where the method has been defined
46
- # @param name [Symbol] the method name
47
- # @param wrapper [Proc] a function which will be used to wrap the
48
- # original method definition
49
- def self.extend_method(mod, name, wrapper)
50
- mod.instance_eval do
51
- wrapped = instance_method(name)
52
-
53
- define_method name, ->(*args) { wrapper.call wrapped.bind(self), *args }
54
- end
55
- end
56
19
  end
57
20
  end
@@ -1,5 +1,5 @@
1
1
  # Version information
2
2
  module DbMod
3
3
  # The current version of db_mod.
4
- VERSION = '0.0.3'
4
+ VERSION = '0.0.4'
5
5
  end
data/lib/db_mod.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  require 'pg'
2
- require_relative 'db_mod/exceptions'
3
- require_relative 'db_mod/transaction'
2
+
4
3
  require_relative 'db_mod/create'
4
+ require_relative 'db_mod/exceptions'
5
5
  require_relative 'db_mod/statements'
6
+ require_relative 'db_mod/transaction'
7
+ require_relative 'db_mod/version'
6
8
 
7
9
  # This is the foundation module for enabling db_mod
8
10
  # support in an application. Including this module
@@ -1,14 +1,14 @@
1
1
  require 'spec_helper'
2
2
  require 'csv'
3
3
 
4
- describe DbMod::As::Csv do
4
+ describe DbMod::Statements::Configuration::As::Csv do
5
5
  subject do
6
6
  Module.new do
7
7
  include DbMod
8
8
 
9
9
  def_statement(:statement, 'SELECT a, b FROM foo').as(:csv)
10
- def_prepared(:prepared, 'SELECT c, d FROM bar').as(:csv)
11
- end
10
+ def_prepared(:prepared, 'SELECT a, b FROM bar').as(:csv)
11
+ end.create(db: 'testdb')
12
12
  end
13
13
 
14
14
  before do
@@ -25,11 +25,12 @@ describe DbMod::As::Csv do
25
25
  it 'coerces results to csv' do
26
26
  expect(@conn).to receive(exec_type).and_return([
27
27
  { 'a' => '1', 'b' => '2' },
28
- { 'a' => '3', 'b' => '4' }
28
+ { 'a' => '3', 'b' => '4' },
29
+ { 'a' => nil, 'b' => '5' }
29
30
  ])
30
31
 
31
- csv = subject.create(db: 'testdb').send(method_type)
32
- expect(csv).to eq("a,b\n1,2\n3,4\n")
32
+ csv = subject.send(method_type)
33
+ expect(csv).to eq("a,b\n1,2\n3,4\n,5\n")
33
34
  end
34
35
  end
35
36
  end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+
4
+ describe DbMod::Statements::Configuration::As::Json do
5
+ subject do
6
+ Module.new do
7
+ include DbMod
8
+
9
+ def_statement(:statement, 'SELECT a, b FROM foo').as(:json)
10
+ def_prepared(:prepared, 'SELECT a, b FROM bar').as(:json)
11
+ end.create(db: 'testdb')
12
+ end
13
+
14
+ before do
15
+ @conn = instance_double 'PGconn'
16
+ allow(@conn).to receive(:prepare)
17
+ allow(PGconn).to receive(:connect).and_return @conn
18
+ end
19
+
20
+ {
21
+ statement: :query,
22
+ prepared: :exec_prepared
23
+ }.each do |method_type, exec_type|
24
+ context "#{method_type} methods" do
25
+ it 'coerces results to json' do
26
+ expect(@conn).to receive(exec_type).and_return([
27
+ { 'a' => '1', 'b' => 'foo' },
28
+ { 'a' => '2', 'b' => nil }
29
+ ])
30
+
31
+ json = subject.send(method_type)
32
+ expect(json).to eq(
33
+ '[{"a":"1","b":"foo"},{"a":"2","b":null}]'
34
+ )
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ # See submodules for more
4
+ describe DbMod::Statements::Configuration::As do
5
+ it 'disallows unknown coercions' do
6
+ expect do
7
+ Module.new do
8
+ include DbMod
9
+
10
+ def_statement(:foo, 'SELECT 1').as(:lolwut)
11
+ end
12
+ end.to raise_exception ArgumentError
13
+ end
14
+
15
+ it 'disallows multiple coercions' do
16
+ expect do
17
+ Module.new do
18
+ include DbMod
19
+
20
+ def_statement(:foo, 'SELECT 1').as(:json).as(:csv)
21
+ end
22
+ end.to raise_exception DbMod::Exceptions::BadMethodConfiguration
23
+ end
24
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ describe DbMod::Statements::Configuration::Single do
4
+ subject do
5
+ Module.new do
6
+ include DbMod
7
+
8
+ def_statement(:v, 'SELECT a FROM foo').single(:value)
9
+ def_prepared(:v!, 'SELECT c FROM d WHERE e = $f').single(:value!)
10
+
11
+ def_prepared(:r, 'SELECT a, b FROM foo WHERE c = $1').single(:row)
12
+ def_statement(:r!, 'SELECT a, b FROM foo').single(:row!)
13
+
14
+ def_statement(:c, 'SELECT a FROM foo WHERE c > $min').single(:column)
15
+ end.create(db: 'testdb')
16
+ end
17
+
18
+ before do
19
+ @conn = instance_double 'PGconn'
20
+ allow(@conn).to receive(:prepare)
21
+ allow(PGconn).to receive(:connect).and_return(@conn)
22
+ end
23
+
24
+ context ':value, :value!' do
25
+ it 'extracts single values' do
26
+ expect(@conn).to receive(:query).and_return([{ 'a' => '1' }])
27
+ expect(subject.v).to eq('1')
28
+
29
+ expect(@conn).to receive(:exec_prepared).and_return([{ 'c' => '2' }])
30
+ expect(subject.v! f: 1).to eq('2')
31
+ end
32
+
33
+ it 'can assert a single result was returned' do
34
+ expect(@conn).to receive(:exec_prepared).and_return([])
35
+ expect { subject.v! f: 2 }.to raise_exception DbMod::Exceptions::NoResults
36
+
37
+ expect(@conn).to receive(:exec_prepared).and_return([
38
+ { 'c' => '3' },
39
+ { 'c' => '4' }
40
+ ])
41
+ expect { subject.v! f: 3 }.to raise_exception(
42
+ DbMod::Exceptions::TooManyResults
43
+ )
44
+ end
45
+ end
46
+
47
+ context ':row, :row!' do
48
+ it 'extracts single rows' do
49
+ result = [{ 'a' => '1', 'b' => '2' }]
50
+ expected = { 'a' => '1', 'b' => '2' }
51
+
52
+ expect(@conn).to receive(:exec_prepared).and_return(result)
53
+ expect(subject.r(1)).to eq(expected)
54
+
55
+ expect(@conn).to receive(:query).and_return(result)
56
+ expect(subject.r!).to eq(expected)
57
+ end
58
+
59
+ it 'can assert that a single result was returned' do
60
+ expect(@conn).to receive(:query).and_return([])
61
+ expect { subject.r! }.to raise_exception DbMod::Exceptions::NoResults
62
+
63
+ expect(@conn).to receive(:query).and_return([
64
+ { 'a' => '3', 'b' => '4' },
65
+ { 'a' => '5', 'b' => '6' }
66
+ ])
67
+ expect { subject.r! }.to raise_exception(
68
+ DbMod::Exceptions::TooManyResults
69
+ )
70
+ end
71
+ end
72
+
73
+ context ':column' do
74
+ it 'returns the column as an array' do
75
+ expect(@conn).to receive(:exec_params).and_return([
76
+ { 'a' => '1' },
77
+ { 'a' => '2' },
78
+ { 'a' => '3' }
79
+ ])
80
+ expect(subject.c min: 1).to eq(%w(1 2 3))
81
+
82
+ expect(@conn).to receive(:exec_params).and_return([])
83
+ expect(subject.c min: 2).to eq([])
84
+ end
85
+ end
86
+
87
+ it 'rejects unknown types' do
88
+ expect do
89
+ Module.new do
90
+ include DbMod
91
+
92
+ def_statement(:a, 'SELECT 1').single(:lolwut)
93
+ end
94
+ end.to raise_exception ArgumentError
95
+ end
96
+
97
+ it 'cannot be called twice' do
98
+ expect do
99
+ Module.new do
100
+ include DbMod
101
+
102
+ def_statement(:a, 'SELECT 1').single(:row).single(:value)
103
+ end
104
+ end.to raise_exception DbMod::Exceptions::BadMethodConfiguration
105
+ end
106
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: db_mod
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Doug Hammond
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-13 00:00:00.000000000 Z
11
+ date: 2015-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -105,6 +105,7 @@ files:
105
105
  - ".rspec"
106
106
  - ".rubocop.yml"
107
107
  - ".travis.yml"
108
+ - ".yardopts"
108
109
  - CHANGELOG.md
109
110
  - CODE_OF_CONDUCT.md
110
111
  - Gemfile
@@ -114,24 +115,37 @@ files:
114
115
  - Rakefile
115
116
  - db_mod.gemspec
116
117
  - lib/db_mod.rb
117
- - lib/db_mod/as.rb
118
- - lib/db_mod/as/csv.rb
119
118
  - lib/db_mod/create.rb
120
119
  - lib/db_mod/exceptions.rb
121
120
  - lib/db_mod/exceptions/already_in_transaction.rb
121
+ - lib/db_mod/exceptions/bad_method_configuration.rb
122
122
  - lib/db_mod/exceptions/base.rb
123
123
  - lib/db_mod/exceptions/connection_not_set.rb
124
124
  - lib/db_mod/exceptions/duplicate_statement_name.rb
125
+ - lib/db_mod/exceptions/no_results.rb
126
+ - lib/db_mod/exceptions/too_many_results.rb
125
127
  - lib/db_mod/statements.rb
126
- - lib/db_mod/statements/configurable_method.rb
128
+ - lib/db_mod/statements/configuration.rb
129
+ - lib/db_mod/statements/configuration/as.rb
130
+ - lib/db_mod/statements/configuration/as/csv.rb
131
+ - lib/db_mod/statements/configuration/as/json.rb
132
+ - lib/db_mod/statements/configuration/configurable_method.rb
133
+ - lib/db_mod/statements/configuration/single.rb
134
+ - lib/db_mod/statements/configuration/single/column.rb
135
+ - lib/db_mod/statements/configuration/single/required_row.rb
136
+ - lib/db_mod/statements/configuration/single/required_value.rb
137
+ - lib/db_mod/statements/configuration/single/row.rb
138
+ - lib/db_mod/statements/configuration/single/value.rb
127
139
  - lib/db_mod/statements/parameters.rb
128
140
  - lib/db_mod/statements/prepared.rb
129
141
  - lib/db_mod/statements/statement.rb
130
142
  - lib/db_mod/transaction.rb
131
143
  - lib/db_mod/version.rb
132
- - spec/db_mod/as/csv_spec.rb
133
- - spec/db_mod/as_spec.rb
134
144
  - spec/db_mod/create_spec.rb
145
+ - spec/db_mod/statements/configuration/as/csv_spec.rb
146
+ - spec/db_mod/statements/configuration/as/json_spec.rb
147
+ - spec/db_mod/statements/configuration/as_spec.rb
148
+ - spec/db_mod/statements/configuration/single_spec.rb
135
149
  - spec/db_mod/statements/prepared_spec.rb
136
150
  - spec/db_mod/statements/statement_spec.rb
137
151
  - spec/db_mod/transaction_spec.rb
@@ -162,9 +176,11 @@ signing_key:
162
176
  specification_version: 4
163
177
  summary: Declarative, modular database library framework.
164
178
  test_files:
165
- - spec/db_mod/as/csv_spec.rb
166
- - spec/db_mod/as_spec.rb
167
179
  - spec/db_mod/create_spec.rb
180
+ - spec/db_mod/statements/configuration/as/csv_spec.rb
181
+ - spec/db_mod/statements/configuration/as/json_spec.rb
182
+ - spec/db_mod/statements/configuration/as_spec.rb
183
+ - spec/db_mod/statements/configuration/single_spec.rb
168
184
  - spec/db_mod/statements/prepared_spec.rb
169
185
  - spec/db_mod/statements/statement_spec.rb
170
186
  - spec/db_mod/transaction_spec.rb
data/lib/db_mod/as/csv.rb DELETED
@@ -1,37 +0,0 @@
1
- module DbMod
2
- module As
3
- # Coercer which converts an SQL result set
4
- # into a string formatted as a CSV document.
5
- # May be enabled for a prepared method or
6
- # statement method using +.as(:csv)+:
7
- #
8
- # def_statement(:a, 'SELECT a, b FROM foo').as(:csv)
9
- # def_prepared(:b, 'SELECT b, c FROM bar').as(:csv)
10
- #
11
- # def do_stuff
12
- # a # => "a,b\r\n1,2\r\n3,4\r\n..."
13
- # end
14
- module Csv
15
- # Enables this module to be passed to {DbMod::Statements.extend_method}
16
- # as the +wrapper+ function, in which case it will retrieve the results
17
- # and format them as a CSV document using the column names from the
18
- # result set.
19
- #
20
- # @param wrapped_method [Method] the method that has been wrapped
21
- # @param args [*] arguments expected to be passed to the wrapped method
22
- # @return [String] a CSV formatted document
23
- def self.call(wrapped_method, *args)
24
- results = wrapped_method.call(*args)
25
-
26
- headers = nil
27
- CSV.generate do |csv|
28
- results.each do |row|
29
- csv << (headers = row.keys) unless headers
30
-
31
- csv << headers.map { |col| row[col] }
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
data/lib/db_mod/as.rb DELETED
@@ -1,38 +0,0 @@
1
- require_relative 'as/csv'
2
-
3
- module DbMod
4
- # Contains coercers and other functions that allow
5
- # module instance methods returning an SQL result set
6
- # to be extended with additional result coercion and
7
- # formatting. The normal way to access this functionality
8
- # is via {DbMod::Statements::ConfigurableMethod#as},
9
- # which is available when defining a statement method
10
- # or prepared method:
11
- #
12
- # def_statement(:a, 'SELECT a, b, c FROM foo').as(:csv)
13
- # def_prepared(:b, 'SELECT d, e, f FROM bar').as(:csv)
14
- module As
15
- # List of available result coercion methods.
16
- # Only keys defined here are allowed as arguments
17
- # to {DbMod::Statements::ConfigurableMethod#as}.
18
- COERCERS = {
19
- csv: DbMod::As::Csv
20
- }
21
-
22
- # Extend a method so that the SQL result set it
23
- # returns will be coerced to the given type.
24
- # See {COERCERS} for a list of defined coercion
25
- # methods.
26
- #
27
- # @param mod [Module] module where the method has been defined
28
- # @param name [Symbol] method name
29
- # @param type [Symbol] type to which result set should be coerced
30
- def self.extend_method(mod, name, type)
31
- unless COERCERS.key? type
32
- fail ArgumentError, "#{type} not in #{COERCERS.keys.join ', '}"
33
- end
34
-
35
- Statements.extend_method(mod, name, COERCERS[type])
36
- end
37
- end
38
- end
@@ -1,41 +0,0 @@
1
- require 'db_mod/as'
2
-
3
- module DbMod
4
- module Statements
5
- # Encapsulates a method that has just been defined
6
- # via the dsl exposed in {DbMod::Statements} so that
7
- # it can be extended with additional processing such
8
- # as result coercion.
9
- #
10
- # The pattern here is something similar to rack's middleware.
11
- # Calling any of the extension methods below will replace
12
- # the original method defined by +def_prepared+ or +def_statement+
13
- # with a wrapper function that may perform processing on given
14
- # arguments, pass them to the original function, then perform
15
- # additional processing on the result.
16
- class ConfigurableMethod
17
- # Encapsulate a method that has been newly defined
18
- # by a {DbMod} dsl function, for additional configuration.
19
- #
20
- # @param mod [Module] the {DbMod} enabled module
21
- # where the method was defined
22
- # @param name [Symbol] the method name
23
- def initialize(mod, name)
24
- @mod = mod
25
- @name = name
26
- end
27
-
28
- # Extend the method by converting results into a given
29
- # format, using one of the coercion methods defined
30
- # under {DbMod::As}.
31
- #
32
- # @param type [Symbol] for now, only :csv is accepted
33
- # @return [self]
34
- def as(type)
35
- DbMod::As.extend_method(@mod, @name, type)
36
-
37
- self
38
- end
39
- end
40
- end
41
- end
@@ -1,14 +0,0 @@
1
- require 'spec_helper'
2
-
3
- # See submodules for more
4
- describe DbMod::As do
5
- it 'disallows unknown coercions' do
6
- expect do
7
- Module.new do
8
- include DbMod
9
-
10
- def_statement(:foo, 'SELECT 1').as(:lolwut)
11
- end
12
- end.to raise_exception ArgumentError
13
- end
14
- end