predefined 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in predefined.gemspec
4
+ gemspec
@@ -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.
@@ -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/
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs = ["lib", "test"]
8
+ t.test_files = FileList["test/*_test.rb"]
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,5 @@
1
+ require "predefined/version"
2
+
3
+ module Predefined
4
+ # Your code goes here...
5
+ end
@@ -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,9 @@
1
+ require 'predefined/active_record'
2
+
3
+ module Predefined
4
+ class Railtie < Rails::Railtie
5
+ initializer "predefined.configure_template_paths" do
6
+ Predefined::Query.template_paths = Rails.root.join('app/queries')
7
+ end
8
+ end
9
+ 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
@@ -0,0 +1,3 @@
1
+ module Predefined
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -0,0 +1,6 @@
1
+ SELECT
2
+ username, first_name, last_name, email
3
+ FROM
4
+ users
5
+ WHERE
6
+ status = :status
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ class QueryTest < Minitest::Test
4
+ def test_template
5
+ query = Predefined::Query.new("users/find_by_status")
6
+ assert_equal "SELECT username, first_name, last_name, email FROM users WHERE status = :status",
7
+ query.template
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ require 'minitest/autorun'
2
+ require 'predefined/query'
3
+
4
+ Predefined::Query.template_paths << File.expand_path('queries', File.dirname(__FILE__))
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