predefined 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +103 -0
- data/Rakefile +11 -0
- data/lib/predefined.rb +5 -0
- data/lib/predefined/active_record.rb +68 -0
- data/lib/predefined/adapter_interface.rb +35 -0
- data/lib/predefined/query.rb +91 -0
- data/lib/predefined/rails.rb +9 -0
- data/lib/predefined/sequel.rb +44 -0
- data/lib/predefined/version.rb +3 -0
- data/predefined.gemspec +22 -0
- data/test/queries/users/find_by_status.sql +6 -0
- data/test/query_test.rb +9 -0
- data/test/test_helper.rb +4 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6d326c7094088f2bd75bca4da0142c213c9a17ce
|
4
|
+
data.tar.gz: 6d85ccf0c4bc7a30e3db7c177761e0445fc307a8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 380223845dadba62611409069b8e155c262b713271dee3287e9c2d68561c55d456d8b621e8cd78a0e951b4bbd3aed13fa1aee7c24387da1e809cb9d23ba44ae3
|
7
|
+
data.tar.gz: 937d20bc196b89fabcd6066281b6fb4103bd2d83f1a75d6487fe62f7ef9d06ab70d99e928f02a53f7dc102b9af088d5cc6d131b2b6a95639aee4ef1802cc7887
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Paul Barry
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# Predefined
|
2
|
+
|
3
|
+
Predefined is a library for writing parameterized SQL queries, executing them and mapping the result to on to objects.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
To use in a [Rails][rails] app, add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'predefined', require: 'predefined/rails'
|
11
|
+
```
|
12
|
+
|
13
|
+
To use in a Ruby app with [Sequel][sequel], app this line your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'predefined', require: 'predefined/sequel'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install predefined
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
The basic concept of Predefined is that you will write SQL queries and save them into a file. For example, if you have a Rails app with a users table, you would create a file `app/queries/users/get.sql` that would look like this:
|
30
|
+
|
31
|
+
```sql
|
32
|
+
SELECT
|
33
|
+
*
|
34
|
+
FROM
|
35
|
+
users
|
36
|
+
WHERE
|
37
|
+
id = :id
|
38
|
+
```
|
39
|
+
|
40
|
+
Then to execute the query and return the results, you would write code like this:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
Predefined::ActiveRecordQuery.new('users/get').select_one(id: id)
|
44
|
+
```
|
45
|
+
|
46
|
+
This will replace `:id` in your SQL statement with the actual value you pass in, then run the query and return the results as a Hash.
|
47
|
+
|
48
|
+
To make the syntax a bit cleaner, include the module `Predefined::ActiveRecordHelpers` in your base classes like `ApplicationController`, then you can simply run this code:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
select_one 'users/get', id: id
|
52
|
+
```
|
53
|
+
|
54
|
+
There are several methods you can use to execute a query:
|
55
|
+
|
56
|
+
### `select_one(template_file, params)`
|
57
|
+
|
58
|
+
This method take the name of the query and the parameters for the query and returns a Hash with the keys as Symbols and the values are type casted, meaning if the database column is an Integer, you will get a Integer instead of a String.
|
59
|
+
|
60
|
+
### `select_all(template_file, params)`
|
61
|
+
|
62
|
+
This method takes the name of the query and the parameters for the query and returns an Array of Hashes, one Hash for each row in the result of the query. The keys of the Hashes are Symbols and the values are type casted.
|
63
|
+
|
64
|
+
### `select_rows(template_file, params)`
|
65
|
+
|
66
|
+
This method will return an Array of Arrays of type casted values, one Array for each row in the result of the query.
|
67
|
+
|
68
|
+
### `select_values(template_file, params)`
|
69
|
+
|
70
|
+
This method will return an Array of type casted values, using the first column from the result of the query.
|
71
|
+
|
72
|
+
### `select_values(template_file, params)`
|
73
|
+
|
74
|
+
This method will return a type casted value, the first column in the first row of the result
|
75
|
+
|
76
|
+
### `select_object(template_file, klass, params)`
|
77
|
+
|
78
|
+
This method is like `select_one`, but it will also pass the Hash an an argument to the class's new method and return the object instance. This:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
select_object 'thing', Thing, id: 1
|
82
|
+
```
|
83
|
+
|
84
|
+
is equivalent to
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
Thing.new(select_one('thing', id: 1))
|
88
|
+
```
|
89
|
+
|
90
|
+
### `select_objects(template_file, klass, params)`
|
91
|
+
|
92
|
+
This is like `select_object` except that it creates an object for every row in the result of the query and returns the Array of objects
|
93
|
+
|
94
|
+
## Contributing
|
95
|
+
|
96
|
+
1. Fork it ( https://github.com/[my-github-username]/predefined/fork )
|
97
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
98
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
99
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
100
|
+
5. Create a new Pull Request
|
101
|
+
|
102
|
+
[rails]: http://rubyonrails.org/
|
103
|
+
[sequel]: http://sequel.jeremyevans.net/
|
data/Rakefile
ADDED
data/lib/predefined.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'predefined/query'
|
2
|
+
|
3
|
+
module Predefined
|
4
|
+
class ActiveRecordQuery < Query
|
5
|
+
class Database < ActiveRecord::Base
|
6
|
+
self.abstract_class = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def connection
|
10
|
+
Database.connection
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_sql(params=nil)
|
14
|
+
Database.send(:sanitize_sql, [template, params])
|
15
|
+
end
|
16
|
+
|
17
|
+
def select_all(params=nil)
|
18
|
+
result_to_rows(connection.select_all(to_sql(params), name))
|
19
|
+
end
|
20
|
+
|
21
|
+
def select_one(params=nil)
|
22
|
+
select_all(params).first
|
23
|
+
end
|
24
|
+
|
25
|
+
def select_rows(params=nil)
|
26
|
+
connection.select_rows(to_sql(params), name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def select_values(params=nil)
|
30
|
+
connection.select_values(to_sql(params), name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def select_value(params=nil)
|
34
|
+
connection.select_value(to_sql(params), name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def select_object(klass, params=nil)
|
38
|
+
record = connection.select_one(to_sql(params), name)
|
39
|
+
if record
|
40
|
+
klass.new(record)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def select_objects(klass, params=nil)
|
45
|
+
connection.select_all(to_sql(params), name).map do |row|
|
46
|
+
klass.new(row)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# TODO: Is there a way to do this built-in to ActiveRecord?
|
51
|
+
def result_to_rows(result)
|
52
|
+
result.rows.map do |row|
|
53
|
+
typed_row = result.columns.zip(row).map do |column_name, value|
|
54
|
+
typed_value = result.column_types[column_name].send(:type_cast, value)
|
55
|
+
[column_name.to_sym, typed_value]
|
56
|
+
end
|
57
|
+
Hash[typed_row]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module ActiveRecordHelpers
|
63
|
+
include Helpers
|
64
|
+
def predefined_helper_query_class
|
65
|
+
ActiveRecordQuery
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Predefined
|
2
|
+
module AdapterInterface
|
3
|
+
def to_sql(params=nil)
|
4
|
+
raise "Not Implemented"
|
5
|
+
end
|
6
|
+
|
7
|
+
def select_all(params=nil)
|
8
|
+
raise "Not Implemented"
|
9
|
+
end
|
10
|
+
|
11
|
+
def select_one(params=nil)
|
12
|
+
raise "Not Implemented"
|
13
|
+
end
|
14
|
+
|
15
|
+
def select_rows(params=nil)
|
16
|
+
raise "Not Implemented"
|
17
|
+
end
|
18
|
+
|
19
|
+
def select_values(params=nil)
|
20
|
+
raise "Not Implemented"
|
21
|
+
end
|
22
|
+
|
23
|
+
def select_value(params=nil)
|
24
|
+
raise "Not Implemented"
|
25
|
+
end
|
26
|
+
|
27
|
+
def select_object(klass, params=nil)
|
28
|
+
raise "Not Implemented"
|
29
|
+
end
|
30
|
+
|
31
|
+
def select_objects(klass, parmas=nil)
|
32
|
+
raise "Not Implemented"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'predefined/adapter_interface'
|
2
|
+
|
3
|
+
module Predefined
|
4
|
+
class Query
|
5
|
+
include Predefined::AdapterInterface
|
6
|
+
class Error < RuntimeError; end
|
7
|
+
class MissingTemplateError < Error; end
|
8
|
+
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
def self.template_paths
|
12
|
+
if defined? @template_paths
|
13
|
+
@template_paths
|
14
|
+
elsif superclass.respond_to?(:template_paths)
|
15
|
+
superclass.template_paths
|
16
|
+
else
|
17
|
+
@template_paths ||= []
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.template_paths=(paths)
|
22
|
+
@template_paths = Array(paths)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.template(name)
|
26
|
+
@template ||= begin
|
27
|
+
template_paths.each do |path|
|
28
|
+
file = template_file(path, name)
|
29
|
+
if File.exists?(file)
|
30
|
+
return format_query(File.read(file))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
template_missing(name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.template_file(path, name)
|
38
|
+
File.join(path, "#{name}.sql")
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.template_missing(name)
|
42
|
+
raise MissingTemplateError.new("Could not find template for query #{name.inspect} in #{template_paths.inspect}")
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.format_query(sql)
|
46
|
+
sql.to_s.split(/\n/).map(&:strip).join(' ')
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(name)
|
50
|
+
@name = name
|
51
|
+
end
|
52
|
+
|
53
|
+
def template
|
54
|
+
self.class.template(name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module Helpers
|
59
|
+
def predefined_helper_query_class
|
60
|
+
raise "Not Implemented"
|
61
|
+
end
|
62
|
+
|
63
|
+
def select_all(template_name, params=nil)
|
64
|
+
predefined_helper_query_class.new(template_name).select_all(params)
|
65
|
+
end
|
66
|
+
|
67
|
+
def select_one(template_name, params=nil)
|
68
|
+
predefined_helper_query_class.new(template_name).select_one(params)
|
69
|
+
end
|
70
|
+
|
71
|
+
def select_rows(template_name, params=nil)
|
72
|
+
predefined_helper_query_class.new(template_name).select_rows(params)
|
73
|
+
end
|
74
|
+
|
75
|
+
def select_values(template_name, params=nil)
|
76
|
+
predefined_helper_query_class.new(template_name).select_values(params)
|
77
|
+
end
|
78
|
+
|
79
|
+
def select_value(template_name, params=nil)
|
80
|
+
predefined_helper_query_class.new(template_name).select_value(params)
|
81
|
+
end
|
82
|
+
|
83
|
+
def select_object(template_name, klass, params=nil)
|
84
|
+
predefined_helper_query_class.new(template_name).select_object(klass, params)
|
85
|
+
end
|
86
|
+
|
87
|
+
def select_objects(template_name, klass, params=nil)
|
88
|
+
predefined_helper_query_class.new(template_name).select_objects(klass, params)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'predefined/query'
|
2
|
+
|
3
|
+
module Predefined
|
4
|
+
class SequelQuery < Query
|
5
|
+
def to_sql(params=nil)
|
6
|
+
raise "TODO: Implement Me"
|
7
|
+
end
|
8
|
+
|
9
|
+
def select_all(params=nil)
|
10
|
+
raise "TODO: Implement Me"
|
11
|
+
end
|
12
|
+
|
13
|
+
def select_one(params=nil)
|
14
|
+
raise "TODO: Implement Me"
|
15
|
+
end
|
16
|
+
|
17
|
+
def select_rows(params=nil)
|
18
|
+
raise "TODO: Implement Me"
|
19
|
+
end
|
20
|
+
|
21
|
+
def select_values(params=nil)
|
22
|
+
raise "TODO: Implement Me"
|
23
|
+
end
|
24
|
+
|
25
|
+
def select_value(params=nil)
|
26
|
+
raise "TODO: Implement Me"
|
27
|
+
end
|
28
|
+
|
29
|
+
def select_object(klass, params=nil)
|
30
|
+
raise "TODO: Implement Me"
|
31
|
+
end
|
32
|
+
|
33
|
+
def select_objects(klass, parmas=nil)
|
34
|
+
raise "TODO: Implement Me"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module SequelHelpers
|
39
|
+
include Helpers
|
40
|
+
def predefined_helper_query_class
|
41
|
+
SequelQuery
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/predefined.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'predefined/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "predefined"
|
8
|
+
spec.version = Predefined::VERSION
|
9
|
+
spec.authors = ["Paul Barry"]
|
10
|
+
spec.email = ["mail@paulbarry.com"]
|
11
|
+
spec.summary = %q{a library for writing parameterized SQL queries, executing them and mapping the result to on to objects.}
|
12
|
+
spec.homepage = "http://github.com/pjb3/predefined"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
end
|
data/test/query_test.rb
ADDED
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: predefined
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Barry
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- mail@paulbarry.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- Gemfile
|
50
|
+
- LICENSE.txt
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- lib/predefined.rb
|
54
|
+
- lib/predefined/active_record.rb
|
55
|
+
- lib/predefined/adapter_interface.rb
|
56
|
+
- lib/predefined/query.rb
|
57
|
+
- lib/predefined/rails.rb
|
58
|
+
- lib/predefined/sequel.rb
|
59
|
+
- lib/predefined/version.rb
|
60
|
+
- predefined.gemspec
|
61
|
+
- test/queries/users/find_by_status.sql
|
62
|
+
- test/query_test.rb
|
63
|
+
- test/test_helper.rb
|
64
|
+
homepage: http://github.com/pjb3/predefined
|
65
|
+
licenses:
|
66
|
+
- MIT
|
67
|
+
metadata: {}
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 2.4.5
|
85
|
+
signing_key:
|
86
|
+
specification_version: 4
|
87
|
+
summary: a library for writing parameterized SQL queries, executing them and mapping
|
88
|
+
the result to on to objects.
|
89
|
+
test_files:
|
90
|
+
- test/queries/users/find_by_status.sql
|
91
|
+
- test/query_test.rb
|
92
|
+
- test/test_helper.rb
|