db_mod 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +20 -0
- data/lib/db_mod/as.rb +38 -0
- data/lib/db_mod/as/csv.rb +37 -0
- data/lib/db_mod/statements.rb +38 -0
- data/lib/db_mod/statements/configurable_method.rb +41 -0
- data/lib/db_mod/statements/prepared.rb +4 -5
- data/lib/db_mod/statements/statement.rb +3 -5
- data/lib/db_mod/version.rb +1 -1
- data/spec/db_mod/as/csv_spec.rb +36 -0
- data/spec/db_mod/as_spec.rb +14 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fe4bb1c7e19c817bad5e788d2cd626ce909ba0d
|
4
|
+
data.tar.gz: 3bb72d90d2387e7f8e7373f41d390f779b0cc819
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9318f1de5b1fe4c8189c7bc1d03cb42533316175411bb33440824e0051dd33da5c4c64595658e95d001b8995fca4fa4e4c67d24570e229e48418d4cfd346f5e
|
7
|
+
data.tar.gz: fe369f08a3c480d4c5d3322c35b575ecccb5cbada2b7db33f5b05a3fd692ad5d17cbc9580fabf2356e936b7886d28d1cc7d322e605ad3f6f3f2b04ad5523fa1e
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
0.0.3 (2015-10-13)
|
2
|
+
==================
|
3
|
+
|
4
|
+
* Configurable method framework. Adds `def_prepared/statement.as(:csv)` - [@dslh](https://github.com/dslh)
|
5
|
+
|
6
|
+
0.0.2 (2015-10-12)
|
7
|
+
==================
|
8
|
+
|
9
|
+
* Adds `def_statement` to compliment `def_prepared` - [@dslh](https://github.com/dslh).
|
10
|
+
|
11
|
+
0.0.1 (2015-10-11)
|
12
|
+
==================
|
13
|
+
|
14
|
+
* Initial release - [@dslh](https://github.com/dslh).
|
data/README.md
CHANGED
@@ -183,3 +183,23 @@ Db::ComplicatedStuff.prepare_all_statements my_conn
|
|
183
183
|
the SQL queries are saved in memory rather than being sent to the database
|
184
184
|
at connection time. This is useful for queries that will only be run once
|
185
185
|
or twice during a program's execution.
|
186
|
+
|
187
|
+
#### Configuring defined statements
|
188
|
+
|
189
|
+
`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.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
module CsvReports
|
196
|
+
include DbMod
|
197
|
+
|
198
|
+
def_prepared(:foo, 'SELECT a, b FROM foo WHERE bar_id = $id').as(:csv)
|
199
|
+
end
|
200
|
+
|
201
|
+
include CsvReports
|
202
|
+
db_connect db: 'testdb'
|
203
|
+
|
204
|
+
foo(id: 1) # => "a,b\n1,2\n3,4\n..."
|
205
|
+
```
|
data/lib/db_mod/as.rb
ADDED
@@ -0,0 +1,38 @@
|
|
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
|
@@ -0,0 +1,37 @@
|
|
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/statements.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require_relative 'statements/configurable_method'
|
1
2
|
require_relative 'statements/statement'
|
2
3
|
require_relative 'statements/prepared'
|
3
4
|
|
@@ -15,5 +16,42 @@ module DbMod
|
|
15
16
|
DbMod::Statements::Prepared.setup(mod)
|
16
17
|
DbMod::Statements::Statement.setup(mod)
|
17
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
|
18
56
|
end
|
19
57
|
end
|
@@ -0,0 +1,41 @@
|
|
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
|
@@ -145,9 +145,8 @@ module DbMod
|
|
145
145
|
# @param name [Symbol] name of the method to be defined
|
146
146
|
# and the prepared query to be called.
|
147
147
|
def self.define_no_args_prepared_method(mod, name)
|
148
|
-
|
149
|
-
|
150
|
-
end
|
148
|
+
method = ->() { conn.exec_prepared(name.to_s) }
|
149
|
+
Statements.configurable_method mod, name, method
|
151
150
|
end
|
152
151
|
|
153
152
|
# Define a method with the given name that accepts the
|
@@ -165,7 +164,7 @@ module DbMod
|
|
165
164
|
conn.exec_prepared(name.to_s, args)
|
166
165
|
end
|
167
166
|
|
168
|
-
|
167
|
+
Statements.configurable_method mod, name, method
|
169
168
|
end
|
170
169
|
|
171
170
|
# Define a method with the given name that accepts a fixed
|
@@ -186,7 +185,7 @@ module DbMod
|
|
186
185
|
conn.exec_prepared(name.to_s, args)
|
187
186
|
end
|
188
187
|
|
189
|
-
mod
|
188
|
+
Statements.configurable_method(mod, name, method)
|
190
189
|
end
|
191
190
|
|
192
191
|
# Adds +prepared_statements+ to a module. This list of named
|
@@ -83,9 +83,7 @@ module DbMod
|
|
83
83
|
# @param name [Symbol] name of the method to be defined
|
84
84
|
# @param sql [String] parameterless SQL statement to execute
|
85
85
|
def self.define_no_args_statement_method(mod, name, sql)
|
86
|
-
|
87
|
-
define_method name, ->() { query(sql) }
|
88
|
-
end
|
86
|
+
Statements.configurable_method mod, name, ->() { query(sql) }
|
89
87
|
end
|
90
88
|
|
91
89
|
# Define a method with the given name, that accepts the
|
@@ -101,7 +99,7 @@ module DbMod
|
|
101
99
|
conn.exec_params(sql, args)
|
102
100
|
end
|
103
101
|
|
104
|
-
|
102
|
+
Statements.configurable_method mod, name, method
|
105
103
|
end
|
106
104
|
|
107
105
|
# Define a method with the given name that accepts a fixed number
|
@@ -119,7 +117,7 @@ module DbMod
|
|
119
117
|
conn.exec_params(sql, args)
|
120
118
|
end
|
121
119
|
|
122
|
-
|
120
|
+
Statements.configurable_method mod, name, method
|
123
121
|
end
|
124
122
|
end
|
125
123
|
end
|
data/lib/db_mod/version.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'csv'
|
3
|
+
|
4
|
+
describe DbMod::As::Csv do
|
5
|
+
subject do
|
6
|
+
Module.new do
|
7
|
+
include DbMod
|
8
|
+
|
9
|
+
def_statement(:statement, 'SELECT a, b FROM foo').as(:csv)
|
10
|
+
def_prepared(:prepared, 'SELECT c, d FROM bar').as(:csv)
|
11
|
+
end
|
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 csv' do
|
26
|
+
expect(@conn).to receive(exec_type).and_return([
|
27
|
+
{ 'a' => '1', 'b' => '2' },
|
28
|
+
{ 'a' => '3', 'b' => '4' }
|
29
|
+
])
|
30
|
+
|
31
|
+
csv = subject.create(db: 'testdb').send(method_type)
|
32
|
+
expect(csv).to eq("a,b\n1,2\n3,4\n")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,14 @@
|
|
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
|
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.
|
4
|
+
version: 0.0.3
|
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-
|
11
|
+
date: 2015-10-13 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
|
+
- CHANGELOG.md
|
108
109
|
- CODE_OF_CONDUCT.md
|
109
110
|
- Gemfile
|
110
111
|
- Guardfile
|
@@ -113,6 +114,8 @@ files:
|
|
113
114
|
- Rakefile
|
114
115
|
- db_mod.gemspec
|
115
116
|
- lib/db_mod.rb
|
117
|
+
- lib/db_mod/as.rb
|
118
|
+
- lib/db_mod/as/csv.rb
|
116
119
|
- lib/db_mod/create.rb
|
117
120
|
- lib/db_mod/exceptions.rb
|
118
121
|
- lib/db_mod/exceptions/already_in_transaction.rb
|
@@ -120,11 +123,14 @@ files:
|
|
120
123
|
- lib/db_mod/exceptions/connection_not_set.rb
|
121
124
|
- lib/db_mod/exceptions/duplicate_statement_name.rb
|
122
125
|
- lib/db_mod/statements.rb
|
126
|
+
- lib/db_mod/statements/configurable_method.rb
|
123
127
|
- lib/db_mod/statements/parameters.rb
|
124
128
|
- lib/db_mod/statements/prepared.rb
|
125
129
|
- lib/db_mod/statements/statement.rb
|
126
130
|
- lib/db_mod/transaction.rb
|
127
131
|
- lib/db_mod/version.rb
|
132
|
+
- spec/db_mod/as/csv_spec.rb
|
133
|
+
- spec/db_mod/as_spec.rb
|
128
134
|
- spec/db_mod/create_spec.rb
|
129
135
|
- spec/db_mod/statements/prepared_spec.rb
|
130
136
|
- spec/db_mod/statements/statement_spec.rb
|
@@ -156,6 +162,8 @@ signing_key:
|
|
156
162
|
specification_version: 4
|
157
163
|
summary: Declarative, modular database library framework.
|
158
164
|
test_files:
|
165
|
+
- spec/db_mod/as/csv_spec.rb
|
166
|
+
- spec/db_mod/as_spec.rb
|
159
167
|
- spec/db_mod/create_spec.rb
|
160
168
|
- spec/db_mod/statements/prepared_spec.rb
|
161
169
|
- spec/db_mod/statements/statement_spec.rb
|