factorylabs-adapter_extensions 0.4.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,26 @@
1
+ 0.1.0 - March 5, 2007
2
+ * Initial release
3
+
4
+ 0.1.1 - March 5, 2007
5
+ * Bug fixes
6
+
7
+ 0.1.2 - March 5, 2007
8
+ * Bug fixes
9
+
10
+ 0.2.0 - March 6, 2007
11
+ * SQL Server adapter included (Seth Ladd)
12
+
13
+ 0.3.0 - March 8, 2007
14
+ * PostgreSQL adapter included
15
+ * Added tests for bulk loading
16
+ * bulk_load method now handles table missing and file missing as error cases
17
+
18
+ 0.3.1 - May 4, 2007
19
+ * Added support for modifying SELECT statements to add an INSERT INTO.
20
+
21
+ 0.4 - September 17, 2007
22
+ * Added copy_table method that can copy the structure and data from one table to another. Currently implemented in MySQL (tested), PostgreSQL (tested) and SQL Server adapters (untested).
23
+ * Added support for SELECT..INTO for PostgreSQL.
24
+
25
+ 0.5 -
26
+ * Updated dependencies for gem to current versions of ActiveRecord, ActiveSupport and Rake. May not be compatible with Rails versions less than 2.x.
data/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ Copyright (c) 2007 Anthony Eden
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
4
+ associated documentation files (the "Software"), to deal in the Software without restriction, including
5
+ without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6
+ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
7
+ following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or substantial
10
+ portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
13
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
14
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
15
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,7 @@
1
+ This library provides extensions to Rails' ActiveRecord adapters.
2
+
3
+ As of version 0.5, adapter_extensions has dependencies on ActiveSupport and ActiveRecord 2.1.x or higher.
4
+
5
+ To use the MySQL adapter extensions with Rails 2.x, you must patch the mysql_adapter with the mysql_adapter_opt_local_infile.patch.
6
+
7
+ To execute the unit tests you must first construct a adapter_extensions_unittest database.
data/Rakefile ADDED
@@ -0,0 +1,158 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/packagetask'
5
+ require 'rake/gempackagetask'
6
+ require 'rake/contrib/rubyforgepublisher'
7
+ require 'date'
8
+
9
+ require File.join(File.dirname(__FILE__), 'lib/adapter_extensions', 'version')
10
+
11
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
12
+ PKG_NAME = 'adapter_extensions'
13
+ PKG_VERSION = AdapterExtensions::VERSION::STRING + PKG_BUILD
14
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
15
+ PKG_DESTINATION = ENV["PKG_DESTINATION"] || "../#{PKG_NAME}"
16
+
17
+ RELEASE_NAME = "REL #{PKG_VERSION}"
18
+
19
+ RUBY_FORGE_PROJECT = "activewarehouse"
20
+ RUBY_FORGE_USER = "aeden"
21
+
22
+ desc 'Default: run unit tests.'
23
+ task :default => :test
24
+
25
+ desc 'Test the ETL application.'
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = true
30
+ # TODO: reset the database
31
+ end
32
+
33
+ namespace :rcov do
34
+ desc 'Measures test coverage'
35
+ task :test do
36
+ rm_f 'coverage.data'
37
+ mkdir 'coverage' unless File.exist?('coverage')
38
+ rcov = "rcov --aggregate coverage.data --text-summary -Ilib"
39
+ system("#{rcov} test/*_test.rb test/**/*_test.rb")
40
+ system("open coverage/index.html") if PLATFORM['darwin']
41
+ end
42
+ end
43
+
44
+ desc 'Generate documentation for the AdapterExtensions library.'
45
+ Rake::RDocTask.new(:rdoc) do |rdoc|
46
+ rdoc.rdoc_dir = 'rdoc'
47
+ rdoc.title = 'Extensions for Rails adapters'
48
+ rdoc.options << '--line-numbers' << '--inline-source'
49
+ rdoc.rdoc_files.include('README')
50
+ rdoc.rdoc_files.include('lib/**/*.rb')
51
+ end
52
+
53
+ PKG_FILES = FileList[
54
+ 'CHANGELOG',
55
+ 'README',
56
+ 'LICENSE',
57
+ 'Rakefile',
58
+ 'doc/**/*',
59
+ 'lib/**/*',
60
+ ] - [ 'test' ]
61
+
62
+ spec = Gem::Specification.new do |s|
63
+ s.name = 'adapter_extensions'
64
+ s.version = PKG_VERSION
65
+ s.summary = "Extensions to Rails ActiveRecord adapters."
66
+ s.description = <<-EOF
67
+ Provides various extensions to the Rails ActiveRecord adapters.
68
+ EOF
69
+
70
+ s.add_dependency('rake', '>= 0.8.3')
71
+ s.add_dependency('activesupport', '>= 2.1.0')
72
+ s.add_dependency('activerecord', '>= 2.1.0')
73
+ s.add_dependency('fastercsv', '>= 1.0.0')
74
+
75
+ s.rdoc_options << '--exclude' << '.'
76
+ s.has_rdoc = false
77
+
78
+ s.files = PKG_FILES.to_a.delete_if {|f| f.include?('.svn')}
79
+ s.require_path = 'lib'
80
+
81
+ s.author = "Anthony Eden"
82
+ s.email = "anthonyeden@gmail.com"
83
+ s.homepage = "http://activewarehouse.rubyforge.org/adapter_extensions"
84
+ s.rubyforge_project = "activewarehouse"
85
+ end
86
+
87
+ Rake::GemPackageTask.new(spec) do |pkg|
88
+ pkg.gem_spec = spec
89
+ pkg.need_tar = true
90
+ pkg.need_zip = true
91
+ end
92
+
93
+ namespace :github do
94
+ desc "Update Github Gemspec"
95
+ task :update_gemspec do
96
+ File.open(File.join(File.dirname(__FILE__), "#{spec.name}.gemspec"), "w"){|f| f << spec.to_ruby}
97
+ end
98
+ end
99
+
100
+
101
+
102
+ desc "Generate code statistics"
103
+ task :lines do
104
+ lines, codelines, total_lines, total_codelines = 0, 0, 0, 0
105
+
106
+ for file_name in FileList["lib/**/*.rb"]
107
+ next if file_name =~ /vendor/
108
+ f = File.open(file_name)
109
+
110
+ while line = f.gets
111
+ lines += 1
112
+ next if line =~ /^\s*$/
113
+ next if line =~ /^\s*#/
114
+ codelines += 1
115
+ end
116
+ puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}"
117
+
118
+ total_lines += lines
119
+ total_codelines += codelines
120
+
121
+ lines, codelines = 0, 0
122
+ end
123
+
124
+ puts "Total: Lines #{total_lines}, LOC #{total_codelines}"
125
+ end
126
+
127
+ desc "Publish the release files to RubyForge."
128
+ task :release => [ :package ] do
129
+ `rubyforge login`
130
+
131
+ for ext in %w( gem tgz zip )
132
+ release_command = "rubyforge add_release activewarehouse #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
133
+ puts release_command
134
+ system(release_command)
135
+ end
136
+ end
137
+
138
+ desc "Publish the API documentation"
139
+ task :pdoc => [:rdoc] do
140
+ Rake::SshDirPublisher.new("aeden@rubyforge.org", "/var/www/gforge-projects/activewarehouse/adapter_extensions/rdoc", "rdoc").upload
141
+ end
142
+
143
+ desc "Install the gem from a local generated package"
144
+ task :install => [:package] do
145
+ windows = RUBY_PLATFORM =~ /mswin/
146
+ sudo = windows ? '' : 'sudo'
147
+ gem = windows ? 'gem.bat' : 'gem'
148
+ `#{sudo} #{gem} install pkg/#{PKG_NAME}-#{PKG_VERSION}`
149
+ end
150
+
151
+ desc "Reinstall the gem from a local package copy"
152
+ task :reinstall => [:package] do
153
+ windows = RUBY_PLATFORM =~ /mswin/
154
+ sudo = windows ? '' : 'sudo'
155
+ gem = windows ? 'gem.bat' : 'gem'
156
+ `#{sudo} #{gem} uninstall #{PKG_NAME} -x`
157
+ `#{sudo} #{gem} install pkg/#{PKG_NAME}-#{PKG_VERSION}`
158
+ end
@@ -0,0 +1,12 @@
1
+ # Extensions to the Rails ActiveRecord adapters.
2
+ #
3
+ # Requiring this file will require all of the necessary files to function.
4
+
5
+ puts "Using AdapterExtensions"
6
+
7
+ require 'rubygems'
8
+ require 'active_support'
9
+ require 'active_record'
10
+
11
+ $:.unshift(File.dirname(__FILE__))
12
+ Dir[File.dirname(__FILE__) + "/adapter_extensions/**/*.rb"].each { |file| require(file) }
@@ -0,0 +1,44 @@
1
+ # This source file contains extensions to the abstract adapter.
2
+ module ActiveRecord #:nodoc:
3
+ module ConnectionAdapters #:nodoc:
4
+ # Extensions to the AbstractAdapter. In some cases a default implementation
5
+ # is provided, in others it is adapter-dependent and the method will
6
+ # raise a NotImplementedError if the adapter does not implement that method
7
+ class AbstractAdapter
8
+ # Truncate the specified table
9
+ def truncate(table_name)
10
+ execute("TRUNCATE TABLE #{table_name}")
11
+ end
12
+
13
+ # Bulk loading interface. Load the data from the specified file into the
14
+ # given table. Note that options will be adapter-dependent.
15
+ def bulk_load(file, table_name, options={})
16
+ raise ArgumentError, "#{file} does not exist" unless File.exist?(file)
17
+ raise ArgumentError, "#{table_name} does not exist" unless tables.include?(table_name)
18
+ do_bulk_load(file, table_name, options)
19
+ end
20
+
21
+ # SQL select into statement constructs a new table from the results
22
+ # of a select. It is used to select data from a table and create a new
23
+ # table with its result set at the same time. Note that this method
24
+ # name does not necessarily match the implementation. E.g. MySQL's
25
+ # version of this is 'CREATE TABLE ... AS SELECT ...'
26
+ def support_select_into_table?
27
+ false
28
+ end
29
+
30
+ # Add a chunk of SQL to the given query that will create a new table and
31
+ # execute the select into that table.
32
+ def add_select_into_table(new_table_name, sql_query)
33
+ raise NotImplementedError, "add_select_into_table is an abstract method"
34
+ end
35
+
36
+ protected
37
+
38
+ # for subclasses to implement
39
+ def do_bulk_load(file, table_name, options={})
40
+ raise NotImplementedError, "do_bulk_load is an abstract method"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,63 @@
1
+ # Source code for the MysqlAdapter extensions.
2
+ module ActiveRecord #:nodoc:
3
+ module ConnectionAdapters #:nodoc:
4
+ # Adds new functionality to ActiveRecord MysqlAdapter.
5
+ class MysqlAdapter < AbstractAdapter
6
+
7
+ def support_select_into_table?
8
+ true
9
+ end
10
+
11
+ # Inserts an INTO table_name clause to the sql_query.
12
+ def add_select_into_table(new_table_name, sql_query)
13
+ "CREATE TABLE #{new_table_name} " + sql_query
14
+ end
15
+
16
+ # Copy the specified table.
17
+ def copy_table(old_table_name, new_table_name)
18
+ transaction do
19
+ execute "CREATE TABLE #{new_table_name} LIKE #{old_table_name}"
20
+ execute "INSERT INTO #{new_table_name} SELECT * FROM #{old_table_name}"
21
+ end
22
+ end
23
+
24
+ protected
25
+ # Call +bulk_load+, as that method wraps this method.
26
+ #
27
+ # Bulk load the data in the specified file. This implementation always uses the LOCAL keyword
28
+ # so the file must be found locally, not on the remote server, to be loaded.
29
+ #
30
+ # Options:
31
+ # * <tt>:ignore</tt> -- Ignore the specified number of lines from the source file
32
+ # * <tt>:columns</tt> -- Array of column names defining the source file column order
33
+ # * <tt>:fields</tt> -- Hash of options for fields:
34
+ # * <tt>:delimited_by</tt> -- The field delimiter
35
+ # * <tt>:enclosed_by</tt> -- The field enclosure
36
+ def do_bulk_load(file, table_name, options={})
37
+ return if File.size(file) == 0
38
+
39
+ # an unfortunate hack - setting the bulk load option after the connection has been
40
+ # established does not seem to have any effect, and since the connection is made when
41
+ # active-record is loaded, there's no chance for us to sneak it in earlier. So we
42
+ # disconnect, set the option, then reconnect - fortunately, this only needs to happen once.
43
+ unless @bulk_load_enabled
44
+ disconnect!
45
+ @connection.options(Mysql::OPT_LOCAL_INFILE, true)
46
+ connect
47
+ @bulk_load_enabled = true
48
+ end
49
+
50
+ q = "LOAD DATA LOCAL INFILE '#{file}' INTO TABLE #{table_name}"
51
+ if options[:fields]
52
+ q << " FIELDS"
53
+ q << " TERMINATED BY '#{options[:fields][:delimited_by]}'" if options[:fields][:delimited_by]
54
+ q << " ENCLOSED BY '#{options[:fields][:enclosed_by]}'" if options[:fields][:enclosed_by]
55
+ end
56
+ q << " IGNORE #{options[:ignore]} LINES" if options[:ignore]
57
+ q << " (#{options[:columns].join(',')})" if options[:columns]
58
+ execute(q)
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,52 @@
1
+ # Source code for the PostgreSQLAdapter extensions.
2
+ module ActiveRecord #:nodoc:
3
+ module ConnectionAdapters #:nodoc:
4
+ # Adds new functionality to ActiveRecord PostgreSQLAdapter.
5
+ class PostgreSQLAdapter < AbstractAdapter
6
+ def support_select_into_table?
7
+ true
8
+ end
9
+
10
+ # Inserts an INTO table_name clause to the sql_query.
11
+ def add_select_into_table(new_table_name, sql_query)
12
+ sql_query.sub(/FROM/i, "INTO #{new_table_name} FROM")
13
+ end
14
+
15
+ # Copy the specified table.
16
+ def copy_table(old_table_name, new_table_name)
17
+ execute add_select_into_table(new_table_name, "SELECT * FROM #{old_table_name}")
18
+ end
19
+
20
+ protected
21
+ # Call +bulk_load+, as that method wraps this method.
22
+ #
23
+ # Bulk load the data in the specified file.
24
+ #
25
+ # Options:
26
+ # * <tt>:ignore</tt> -- Ignore the specified number of lines from the source file. In the case of PostgreSQL
27
+ # only the first line will be ignored from the source file regardless of the number of lines specified.
28
+ # * <tt>:columns</tt> -- Array of column names defining the source file column order
29
+ # * <tt>:fields</tt> -- Hash of options for fields:
30
+ # * <tt>:delimited_by</tt> -- The field delimiter
31
+ # * <tt>:null_string</tt> -- The string that should be interpreted as NULL (in addition to \N)
32
+ # * <tt>:enclosed_by</tt> -- The field enclosure
33
+ def do_bulk_load(file, table_name, options={})
34
+ q = "COPY #{table_name} "
35
+ q << "(#{options[:columns].join(',')}) " if options[:columns]
36
+ q << "FROM '#{File.expand_path(file)}' "
37
+ if options[:fields]
38
+ q << "WITH "
39
+ q << "DELIMITER '#{options[:fields][:delimited_by]}' " if options[:fields][:delimited_by]
40
+ q << "NULL '#{options[:fields][:null_string]}'" if options[:fields][:null_string]
41
+ if options[:fields][:enclosed_by] || options[:ignore] && options[:ignore] > 0
42
+ q << "CSV "
43
+ q << "HEADER " if options[:ignore] && options[:ignore] > 0
44
+ q << "QUOTE '#{options[:fields][:enclosed_by]}' " if options[:fields][:enclosed_by]
45
+ end
46
+ end
47
+
48
+ execute(q)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,44 @@
1
+ # Source code for the SQLServerAdapter extensions.
2
+ module ActiveRecord #:nodoc:
3
+ module ConnectionAdapters #:nodoc:
4
+ # Adds new functionality to ActiveRecord SQLServerAdapter.
5
+ class SQLServerAdapter < AbstractAdapter
6
+ def support_select_into_table?
7
+ true
8
+ end
9
+
10
+ # Inserts an INTO table_name clause to the sql_query.
11
+ def add_select_into_table(new_table_name, sql_query)
12
+ sql_query.sub(/FROM/i, "INTO #{new_table_name} FROM")
13
+ end
14
+
15
+ # Copy the specified table.
16
+ def copy_table(old_table_name, new_table_name)
17
+ execute add_select_into_table(new_table_name, "SELECT * FROM #{old_table_name}")
18
+ end
19
+
20
+ protected
21
+ # Call +bulk_load+, as that method wraps this method.
22
+ #
23
+ # Bulk load the data in the specified file. This implementation relies
24
+ # on bcp being in your PATH.
25
+ #
26
+ # Options:
27
+ # * <tt>:ignore</tt> -- Ignore the specified number of lines from the source file
28
+ # * <tt>:columns</tt> -- Array of column names defining the source file column order
29
+ # * <tt>:fields</tt> -- Hash of options for fields:
30
+ # * <tt>:delimited_by</tt> -- The field delimiter
31
+ # * <tt>:enclosed_by</tt> -- The field enclosure
32
+ def do_bulk_load(file, table_name, options={})
33
+ env_name = options[:env] || RAILS_ENV
34
+ config = ActiveRecord::Base.configurations[env_name]
35
+ puts "Loading table \"#{table_name}\" from file \"#{filename}\""
36
+ cmd = "bcp \"#{config['database']}.dbo.#{table_name}\" in " +
37
+ "\"#{filename}\" -S \"#{config['host']}\" -c " +
38
+ "-t \"#{options[:delimited_by]}\" -b10000 -a8192 -q -E -U \"#{config['username']}\" " +
39
+ "-P \"#{config['password']}\" -e \"#{filename}.in.errors\""
40
+ `#{cmd}`
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,10 @@
1
+ # Source file identifying the version of AdapterExtensions in this package
2
+ module AdapterExtensions#:nodoc:
3
+ module VERSION #:nodoc:
4
+ MAJOR = 0
5
+ MINOR = 5
6
+ TINY = 0
7
+
8
+ STRING = [MAJOR, MINOR, TINY].join('.')
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: factorylabs-adapter_extensions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Anthony Eden
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-05-22 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.7.1
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: activesupport
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 1.3.1
32
+ version:
33
+ - !ruby/object:Gem::Dependency
34
+ name: activerecord
35
+ version_requirement:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.14.4
41
+ version:
42
+ - !ruby/object:Gem::Dependency
43
+ name: fastercsv
44
+ version_requirement:
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.0.0
50
+ version:
51
+ description: Provides various extensions to the Rails ActiveRecord adapters. Forked again to force gem build.
52
+ email: anthonyeden@gmail.com
53
+ executables: []
54
+
55
+ extensions: []
56
+
57
+ extra_rdoc_files: []
58
+
59
+ files:
60
+ - CHANGELOG
61
+ - README
62
+ - LICENSE
63
+ - Rakefile
64
+ - lib/adapter_extensions
65
+ - lib/adapter_extensions.rb
66
+ - lib/adapter_extensions/connection_adapters
67
+ - lib/adapter_extensions/version.rb
68
+ - lib/adapter_extensions/connection_adapters/abstract_adapter.rb
69
+ - lib/adapter_extensions/connection_adapters/mysql_adapter.rb
70
+ - lib/adapter_extensions/connection_adapters/postgresql_adapter.rb
71
+ - lib/adapter_extensions/connection_adapters/sqlserver_adapter.rb
72
+ has_rdoc: false
73
+ homepage: http://activewarehouse.rubyforge.org/adapter_extensions
74
+ post_install_message:
75
+ rdoc_options:
76
+ - --exclude
77
+ - .
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ version:
92
+ requirements: []
93
+
94
+ rubyforge_project: activewarehouse
95
+ rubygems_version: 1.2.0
96
+ signing_key:
97
+ specification_version: 2
98
+ summary: Extensions to Rails ActiveRecord adapters.
99
+ test_files: []
100
+