sql_record 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ source "http://rubygems.org"
6
6
  # Add dependencies to develop your gem here.
7
7
  # Include everything needed to run rake, tests, features, etc.
8
8
  group :development do
9
+ gem "rdoc"
9
10
  gem "rspec", "~> 2.3.0"
10
11
  gem "yard", "~> 0.6.0"
11
12
  gem "bundler", "~> 1.0.0"
data/Gemfile.lock CHANGED
@@ -9,6 +9,7 @@ GEM
9
9
  rake
10
10
  rake (0.8.7)
11
11
  rcov (0.9.9)
12
+ rdoc (3.5.3)
12
13
  rspec (2.3.0)
13
14
  rspec-core (~> 2.3.0)
14
15
  rspec-expectations (~> 2.3.0)
@@ -26,5 +27,6 @@ DEPENDENCIES
26
27
  bundler (~> 1.0.0)
27
28
  jeweler (~> 1.5.2)
28
29
  rcov
30
+ rdoc
29
31
  rspec (~> 2.3.0)
30
32
  yard (~> 0.6.0)
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 vWorkApp
1
+ Copyright (c) 2011 Visfleet Ltd
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -8,17 +8,15 @@ Well that's what SQLRecord does.
8
8
 
9
9
  == Example
10
10
 
11
- class UserWithAccount
12
- include SQLRecord
11
+ class UserWithAccount << SQLRecord::Base
13
12
 
14
-
15
- with_class User do
13
+ with_opts :class => User do
16
14
  column :id
17
15
  column :user_email, :from => :email
18
16
  column :created_at
19
17
  end
20
18
 
21
- with_class Account do
19
+ with_opts :class => Account do
22
20
  column :account_name, :from => :name
23
21
  end
24
22
 
@@ -44,6 +42,10 @@ Well that's what SQLRecord does.
44
42
  => Time
45
43
 
46
44
 
45
+ == Contributers
46
+
47
+ Thanks to {Loren Segal}[http://gnuu.org] for the big code review, and making me aware that sound OO principles are not dead in ruby.
48
+
47
49
  == Contributing to sql-record
48
50
 
49
51
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
data/Rakefile CHANGED
@@ -16,12 +16,7 @@ Jeweler::Tasks.new do |gem|
16
16
  gem.homepage = "http://github.com/visfleet/sql_record"
17
17
  gem.license = "MIT"
18
18
  gem.summary = %Q{SQL direct mapping to ActiveRecord}
19
- gem.description = %Q{Do you use ActiveRecord::Connection.execute for speed sometimes?
20
-
21
- Does it bother you that the results are not mapped to your schema and type-cast as ActiveRecord would?
22
-
23
- Well that's what SQLRecord does.
24
- }
19
+ gem.description = %Q{Do you use ActiveRecord::Connection.execute for speed sometimes? Does it bother you that the results are not mapped to your schema and type-cast as ActiveRecord would? Well that's what SQLRecord does.}
25
20
  gem.email = "rasheed@visfleet.com"
26
21
  gem.authors = ["Rasheed Abdul-Aziz"]
27
22
  # Include your dependencies below. Runtime dependencies are required when using your gem,
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
@@ -0,0 +1,68 @@
1
+ # @author Rasheed Abdul-Aziz
2
+ module SQLRecord
3
+ module Attributes
4
+ module Mapper
5
+
6
+ attr_reader :sql_select_columns
7
+
8
+ # with_opts blocks specify default options for calls to {#column}
9
+ #
10
+ # @param opts [Hash] anything that {#column} supports. Currently this should only be :class
11
+ #
12
+ # @example Longhand (not using with_opts)
13
+ # column :name, :class => Account
14
+ # column :id, :class => Account
15
+ # ...snip...
16
+ # column :created_at, :class => Account
17
+ #
18
+ # @example Shorthand (using with_opts)
19
+ # with_opts :class => Account
20
+ # column :name
21
+ # column :id
22
+ # ...snip...
23
+ # column :created_at
24
+ # end
25
+ #
26
+ def with_opts opts, &block
27
+ @default_opts = opts
28
+ block.arity == 2 ? yield(self) : self.instance_eval(&block)
29
+ @default_opts = nil
30
+ end
31
+
32
+ # Specifies the mapping from an ActiveRecord#column_definition to an SQLRecord instance attribute.
33
+ # @param [Symbol] attribute_name the attribute you are defining for this model
34
+ # @option opts [Class] :class the active record this attribute will use to type_cast from
35
+ # @option opts [Symbol,String] :from if it differs from the attribute_name, the schema column of the active record
36
+ # to use for type_cast
37
+ #
38
+ # @example Simple mapping
39
+ # # Account#name column maps to the "name" attribute
40
+ # column :name, :class => Account
41
+ #
42
+ # @example Mapping a different column name
43
+ # # Account#name column maps to the "account name" attribute
44
+ # column :account_name, :class => Account, :from => :name
45
+ #
46
+ def column attribute_name, opts = {}
47
+ klass = opts[:class] || @default_opts[:class] || nil
48
+ raise ArgumentError, 'You must specify a :class option, either explicitly, or using with_opts' if klass.nil?
49
+
50
+ source_attribute = (opts[:from] || attribute_name).to_s
51
+
52
+ define_method attribute_name do
53
+ klass.columns_hash[source_attribute].type_cast(@raw_attributes[attribute_name.to_s])
54
+ end
55
+
56
+ # bit mucky, a lot here that feels like it should be a little method of its own
57
+ select_column = "#{klass.table_name}.#{source_attribute}"
58
+ select_column += " as #{attribute_name}" if opts[:from]
59
+ (@sql_select_columns ||= []) << select_column
60
+ end
61
+
62
+ def sql_select_helper
63
+ @sql_select_columns.join(', ')
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,19 @@
1
+ module SQLRecord
2
+ # Base provides a class that has a collection of raw_attributes.
3
+ # These can be set from a database abstraction (SQLRecord::SanitizedQuery), and are expected to be type_cast by a mixin
4
+ # (SQLRecord::Attributes::Mapper)
5
+ #
6
+ # @todo Does it sound like the database abstraction could be a whole other class?
7
+ class Base
8
+ extend SQLRecord::SanitizedQuery
9
+ extend SQLRecord::Attributes::Mapper
10
+
11
+ # the raw attributes returned from a db query
12
+ attr_accessor :raw_attributes
13
+
14
+ def initialize raw_attributes = {}
15
+ @raw_attributes = raw_attributes
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ module SQLRecord
2
+ module SanitizedQuery
3
+ # Executes the {#query} proc on your database, building SQLRecords with the results.
4
+ # @param params [Hash] a hash of parameters that are yielded to the {#query} proc
5
+ # @return [Array] {SQLRecord::Base}s with their raw_attributes set to the row results.
6
+ def find params={}
7
+ rows = execute_query params
8
+
9
+ rows.map do |row|
10
+ new row
11
+ end
12
+ end
13
+
14
+ def query &deferred
15
+ @query_proc = deferred
16
+ end
17
+
18
+ protected
19
+
20
+ # @todo check that this logs the sql
21
+ def execute_query params={}
22
+ sql = ActiveRecord::Base.send(:sanitize_sql_array, get_query_array(params))
23
+ ActiveRecord::Base.connection.execute(sql)
24
+ end
25
+
26
+ def get_query_array(params)
27
+ @query_proc.call(params)
28
+ end
29
+
30
+ end
31
+ end
data/lib/sql_record.rb CHANGED
@@ -1,65 +1,3 @@
1
- module SQLRecord
2
-
3
- def initialize(row)
4
- @row = row
5
- end
6
-
7
- def self.included(base)
8
- base.extend ClassMethods
9
- end
10
-
11
- module ClassMethods
12
-
13
- def with_class klass, &block
14
- @current_class = klass
15
- block.arity == 2 ? yield(self) : self.instance_eval(&block)
16
- @current_class = nil
17
- end
18
-
19
- def column attribute_name, opts = {}
20
- klass = opts[:class] || @current_class || nil
21
- raise ArgumentError, 'Either opts[:class] is not defined or you have not specified a with_class block' if klass.nil?
22
-
23
- source_attribute = (opts[:from] || attribute_name).to_s
24
-
25
- define_method attribute_name do
26
- klass.columns_hash[source_attribute].type_cast(@row[attribute_name.to_s])
27
- end
28
-
29
- # bit mucky, a lot here that feels like it should be a little method of its own
30
- select_column = "#{klass.table_name}.#{source_attribute}"
31
- select_column += " as #{attribute_name}" if opts[:from]
32
- (@sql_select_columns ||= []) << select_column
33
- end
34
-
35
- def query &deferred
36
- @query_proc = deferred
37
- end
38
-
39
- def find params={}
40
- rows = execute_query params
41
-
42
- rows.map do |row|
43
- new row
44
- end
45
- end
46
-
47
- protected
48
-
49
- def execute_query params={}
50
- # does this log?
51
- sql = ActiveRecord::Base.send(:sanitize_sql_array, get_query_array(params))
52
- ActiveRecord::Base.connection.execute(sql)
53
- end
54
-
55
- def get_query_array(params)
56
- if @query_proc.arity == 2
57
- @query_proc.call(params, @sql_select_columns.join(", "))
58
- else
59
- @query_proc.call(params)
60
- end
61
- end
62
-
63
- end
64
-
65
- end
1
+ require 'sql_record/sanitized_query'
2
+ require 'sql_record/attributes/mapper'
3
+ require 'sql_record/base'
data/spec/spec_helper.rb CHANGED
@@ -5,8 +5,8 @@ require 'sql-record'
5
5
 
6
6
  # Requires supporting files with custom matchers and macros, etc,
7
7
  # in ./support/ and its subdirectories.
8
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
9
9
 
10
10
  RSpec.configure do |config|
11
-
11
+
12
12
  end
data/sql_record.gemspec CHANGED
@@ -5,17 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{sql_record}
8
- s.version = "0.1.2"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Rasheed Abdul-Aziz"]
12
- s.date = %q{2011-04-07}
13
- s.description = %q{Do you use ActiveRecord::Connection.execute for speed sometimes?
14
-
15
- Does it bother you that the results are not mapped to your schema and type-cast as ActiveRecord would?
16
-
17
- Well that's what SQLRecord does.
18
- }
12
+ s.date = %q{2011-04-08}
13
+ s.description = %q{Do you use ActiveRecord::Connection.execute for speed sometimes? Does it bother you that the results are not mapped to your schema and type-cast as ActiveRecord would? Well that's what SQLRecord does.}
19
14
  s.email = %q{rasheed@visfleet.com}
20
15
  s.extra_rdoc_files = [
21
16
  "LICENSE.txt",
@@ -32,6 +27,9 @@ Well that's what SQLRecord does.
32
27
  "VERSION",
33
28
  "init.rb",
34
29
  "lib/sql_record.rb",
30
+ "lib/sql_record/attributes/mapper.rb",
31
+ "lib/sql_record/base.rb",
32
+ "lib/sql_record/sanitized_query.rb",
35
33
  "spec/spec_helper.rb",
36
34
  "spec/sql_record_spec.rb",
37
35
  "sql_record.gemspec"
@@ -50,12 +48,14 @@ Well that's what SQLRecord does.
50
48
  s.specification_version = 3
51
49
 
52
50
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
53
52
  s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
54
53
  s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
55
54
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
56
55
  s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
57
56
  s.add_development_dependency(%q<rcov>, [">= 0"])
58
57
  else
58
+ s.add_dependency(%q<rdoc>, [">= 0"])
59
59
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
60
60
  s.add_dependency(%q<yard>, ["~> 0.6.0"])
61
61
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -63,6 +63,7 @@ Well that's what SQLRecord does.
63
63
  s.add_dependency(%q<rcov>, [">= 0"])
64
64
  end
65
65
  else
66
+ s.add_dependency(%q<rdoc>, [">= 0"])
66
67
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
67
68
  s.add_dependency(%q<yard>, ["~> 0.6.0"])
68
69
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql_record
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
9
8
  - 2
10
- version: 0.1.2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Rasheed Abdul-Aziz
@@ -15,12 +15,26 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-04-07 00:00:00 +00:00
18
+ date: 2011-04-08 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: rspec
22
+ name: rdoc
23
23
  version_requirements: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ prerelease: false
33
+ type: :development
34
+ requirement: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ version_requirements: &id002 !ruby/object:Gem::Requirement
24
38
  none: false
25
39
  requirements:
26
40
  - - ~>
@@ -33,10 +47,10 @@ dependencies:
33
47
  version: 2.3.0
34
48
  prerelease: false
35
49
  type: :development
36
- requirement: *id001
50
+ requirement: *id002
37
51
  - !ruby/object:Gem::Dependency
38
52
  name: yard
39
- version_requirements: &id002 !ruby/object:Gem::Requirement
53
+ version_requirements: &id003 !ruby/object:Gem::Requirement
40
54
  none: false
41
55
  requirements:
42
56
  - - ~>
@@ -49,10 +63,10 @@ dependencies:
49
63
  version: 0.6.0
50
64
  prerelease: false
51
65
  type: :development
52
- requirement: *id002
66
+ requirement: *id003
53
67
  - !ruby/object:Gem::Dependency
54
68
  name: bundler
55
- version_requirements: &id003 !ruby/object:Gem::Requirement
69
+ version_requirements: &id004 !ruby/object:Gem::Requirement
56
70
  none: false
57
71
  requirements:
58
72
  - - ~>
@@ -65,10 +79,10 @@ dependencies:
65
79
  version: 1.0.0
66
80
  prerelease: false
67
81
  type: :development
68
- requirement: *id003
82
+ requirement: *id004
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: jeweler
71
- version_requirements: &id004 !ruby/object:Gem::Requirement
85
+ version_requirements: &id005 !ruby/object:Gem::Requirement
72
86
  none: false
73
87
  requirements:
74
88
  - - ~>
@@ -81,10 +95,10 @@ dependencies:
81
95
  version: 1.5.2
82
96
  prerelease: false
83
97
  type: :development
84
- requirement: *id004
98
+ requirement: *id005
85
99
  - !ruby/object:Gem::Dependency
86
100
  name: rcov
87
- version_requirements: &id005 !ruby/object:Gem::Requirement
101
+ version_requirements: &id006 !ruby/object:Gem::Requirement
88
102
  none: false
89
103
  requirements:
90
104
  - - ">="
@@ -95,14 +109,8 @@ dependencies:
95
109
  version: "0"
96
110
  prerelease: false
97
111
  type: :development
98
- requirement: *id005
99
- description: |
100
- Do you use ActiveRecord::Connection.execute for speed sometimes?
101
-
102
- Does it bother you that the results are not mapped to your schema and type-cast as ActiveRecord would?
103
-
104
- Well that's what SQLRecord does.
105
-
112
+ requirement: *id006
113
+ description: Do you use ActiveRecord::Connection.execute for speed sometimes? Does it bother you that the results are not mapped to your schema and type-cast as ActiveRecord would? Well that's what SQLRecord does.
106
114
  email: rasheed@visfleet.com
107
115
  executables: []
108
116
 
@@ -122,6 +130,9 @@ files:
122
130
  - VERSION
123
131
  - init.rb
124
132
  - lib/sql_record.rb
133
+ - lib/sql_record/attributes/mapper.rb
134
+ - lib/sql_record/base.rb
135
+ - lib/sql_record/sanitized_query.rb
125
136
  - spec/spec_helper.rb
126
137
  - spec/sql_record_spec.rb
127
138
  - sql_record.gemspec