data_objects 0.9.11 → 0.9.12
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +19 -1
- data/Rakefile +6 -80
- data/lib/data_objects.rb +1 -6
- data/lib/data_objects/command.rb +51 -1
- data/lib/data_objects/connection.rb +13 -2
- data/lib/data_objects/logger.rb +40 -32
- data/lib/data_objects/quoting.rb +28 -32
- data/lib/data_objects/reader.rb +6 -5
- data/lib/data_objects/result.rb +7 -1
- data/lib/data_objects/spec/command_spec.rb +191 -0
- data/lib/data_objects/spec/connection_spec.rb +106 -0
- data/lib/data_objects/spec/encoding_spec.rb +31 -0
- data/lib/data_objects/spec/quoting_spec.rb +0 -0
- data/lib/data_objects/spec/reader_spec.rb +156 -0
- data/lib/data_objects/spec/result_spec.rb +58 -0
- data/lib/data_objects/spec/typecast/array_spec.rb +36 -0
- data/lib/data_objects/spec/typecast/bigdecimal_spec.rb +107 -0
- data/lib/data_objects/spec/typecast/boolean_spec.rb +107 -0
- data/lib/data_objects/spec/typecast/byte_array_spec.rb +86 -0
- data/lib/data_objects/spec/typecast/class_spec.rb +63 -0
- data/lib/data_objects/spec/typecast/date_spec.rb +108 -0
- data/lib/data_objects/spec/typecast/datetime_spec.rb +110 -0
- data/lib/data_objects/spec/typecast/float_spec.rb +111 -0
- data/lib/data_objects/spec/typecast/integer_spec.rb +86 -0
- data/lib/data_objects/spec/typecast/ipaddr_spec.rb +0 -0
- data/lib/data_objects/spec/typecast/nil_spec.rb +116 -0
- data/lib/data_objects/spec/typecast/range_spec.rb +36 -0
- data/lib/data_objects/spec/typecast/string_spec.rb +86 -0
- data/lib/data_objects/spec/typecast/time_spec.rb +64 -0
- data/lib/data_objects/transaction.rb +20 -13
- data/lib/data_objects/uri.rb +24 -2
- data/lib/data_objects/version.rb +2 -1
- data/spec/command_spec.rb +1 -17
- data/spec/connection_spec.rb +1 -23
- data/spec/lib/pending_helpers.rb +11 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
- data/spec/result_spec.rb +0 -3
- data/tasks/gem.rake +49 -0
- data/tasks/install.rake +13 -0
- data/tasks/release.rake +74 -0
- data/tasks/spec.rake +18 -0
- metadata +51 -30
- data/.gitignore +0 -2
- data/spec/dataobjects_spec.rb +0 -1
- data/spec/spec.opts +0 -2
data/Manifest.txt
CHANGED
@@ -11,13 +11,31 @@ lib/data_objects/logger.rb
|
|
11
11
|
lib/data_objects/quoting.rb
|
12
12
|
lib/data_objects/reader.rb
|
13
13
|
lib/data_objects/result.rb
|
14
|
+
lib/data_objects/spec/command_spec.rb
|
15
|
+
lib/data_objects/spec/connection_spec.rb
|
16
|
+
lib/data_objects/spec/encoding_spec.rb
|
17
|
+
lib/data_objects/spec/quoting_spec.rb
|
18
|
+
lib/data_objects/spec/reader_spec.rb
|
19
|
+
lib/data_objects/spec/result_spec.rb
|
20
|
+
lib/data_objects/spec/typecast/bigdecimal_spec.rb
|
21
|
+
lib/data_objects/spec/typecast/boolean_spec.rb
|
22
|
+
lib/data_objects/spec/typecast/byte_array_spec.rb
|
23
|
+
lib/data_objects/spec/typecast/class_spec.rb
|
24
|
+
lib/data_objects/spec/typecast/date_spec.rb
|
25
|
+
lib/data_objects/spec/typecast/datetime_spec.rb
|
26
|
+
lib/data_objects/spec/typecast/float_spec.rb
|
27
|
+
lib/data_objects/spec/typecast/integer_spec.rb
|
28
|
+
lib/data_objects/spec/typecast/ipaddr_spec.rb
|
29
|
+
lib/data_objects/spec/typecast/nil_spec.rb
|
30
|
+
lib/data_objects/spec/typecast/string_spec.rb
|
31
|
+
lib/data_objects/spec/typecast/time_spec.rb
|
14
32
|
lib/data_objects/transaction.rb
|
15
33
|
lib/data_objects/uri.rb
|
16
34
|
lib/data_objects/version.rb
|
17
35
|
spec/command_spec.rb
|
18
36
|
spec/connection_spec.rb
|
19
|
-
spec/dataobjects_spec.rb
|
20
37
|
spec/do_mock.rb
|
38
|
+
spec/lib/pending_helpers.rb
|
21
39
|
spec/reader_spec.rb
|
22
40
|
spec/result_spec.rb
|
23
41
|
spec/spec.opts
|
data/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
require 'pathname'
|
2
1
|
require 'rubygems'
|
3
|
-
require '
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
|
5
|
+
require 'pathname'
|
4
6
|
require 'lib/data_objects/version'
|
5
7
|
|
6
8
|
ROOT = Pathname(__FILE__).dirname.expand_path
|
@@ -8,82 +10,6 @@ JRUBY = RUBY_PLATFORM =~ /java/
|
|
8
10
|
WINDOWS = Gem.win_platform?
|
9
11
|
SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
|
10
12
|
|
11
|
-
|
12
|
-
EMAIL = "d.bussink@gmail.com"
|
13
|
-
GEM_NAME = "data_objects"
|
14
|
-
GEM_VERSION = DataObjects::VERSION
|
15
|
-
GEM_DEPENDENCIES = ["addressable", "~>2.0"], ["extlib", "~>0.9.9"]
|
16
|
-
GEM_CLEAN = "{coverage,doc,log}/", "profile_results.*", "**/.*.sw?", "*.gem", ".config", "**/.DS_Store"
|
17
|
-
GEM_EXTRAS = {}
|
18
|
-
|
19
|
-
PROJECT_NAME = "dorb"
|
20
|
-
PROJECT_URL = "http://rubyforge.org/projects/dorb"
|
21
|
-
PROJECT_DESCRIPTION = PROJECT_SUMMARY = "The Core DataObjects class"
|
22
|
-
|
23
|
-
|
24
|
-
# RCov is run by default, except on the JRuby platform, or if NO_RCOV env is true
|
25
|
-
RUN_RCOV = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
|
26
|
-
|
27
|
-
if (tasks_dir = ROOT.parent + 'tasks').directory?
|
28
|
-
require tasks_dir + 'hoe'
|
29
|
-
end
|
30
|
-
|
31
|
-
def sudo_gem(cmd)
|
32
|
-
sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
|
33
|
-
end
|
34
|
-
|
35
|
-
# Installation
|
36
|
-
|
37
|
-
desc "Install #{GEM_NAME} #{GEM_VERSION}"
|
38
|
-
task :install => [ :package ] do
|
39
|
-
sudo_gem "install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
|
40
|
-
end
|
41
|
-
|
42
|
-
desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
|
43
|
-
task :uninstall => [ :clobber ] do
|
44
|
-
sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -I -x"
|
45
|
-
end
|
46
|
-
|
47
|
-
# Specs
|
48
|
-
|
49
|
-
Spec::Rake::SpecTask.new(:spec) do |t|
|
50
|
-
t.spec_opts << '--format' << 'specdoc' << '--colour'
|
51
|
-
t.spec_opts << '--loadby' << 'random'
|
52
|
-
t.spec_files = Pathname.glob(ENV['FILES'] || 'spec/**/*_spec.rb').map { |f| f.to_s }
|
53
|
-
|
54
|
-
begin
|
55
|
-
t.rcov = RUN_RCOV
|
56
|
-
t.rcov_opts << '--exclude' << 'spec'
|
57
|
-
t.rcov_opts << '--text-summary'
|
58
|
-
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
59
|
-
rescue Exception
|
60
|
-
# rcov not installed
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
namespace :ci do
|
65
|
-
|
66
|
-
task :prepare do
|
67
|
-
rm_rf ROOT + "ci"
|
68
|
-
mkdir_p ROOT + "ci"
|
69
|
-
mkdir_p ROOT + "ci/doc"
|
70
|
-
mkdir_p ROOT + "ci/cyclomatic"
|
71
|
-
mkdir_p ROOT + "ci/token"
|
72
|
-
end
|
73
|
-
|
74
|
-
task :publish do
|
75
|
-
out = ENV['CC_BUILD_ARTIFACTS'] || "out"
|
76
|
-
mkdir_p out unless File.directory? out
|
77
|
-
|
78
|
-
mv "ci/rspec_report.html", "#{out}/rspec_report.html"
|
79
|
-
mv "ci/coverage", "#{out}/coverage"
|
80
|
-
end
|
81
|
-
|
82
|
-
task :spec => :prepare do
|
83
|
-
Rake::Task[:spec].invoke
|
84
|
-
mv ROOT + "coverage", ROOT + "ci/coverage"
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|
13
|
+
Dir['tasks/*.rake'].each { |f| import f }
|
88
14
|
|
89
|
-
|
15
|
+
CLEAN.include(%w[ pkg/ **/*.rbc ])
|
data/lib/data_objects.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
-
gem 'extlib', '~>0.9.
|
3
|
+
gem 'extlib', '~>0.9.11'
|
4
4
|
require 'extlib'
|
5
5
|
|
6
6
|
require File.expand_path(File.join(File.dirname(__FILE__), 'data_objects', 'version'))
|
@@ -16,9 +16,4 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'data_objects', 'quot
|
|
16
16
|
|
17
17
|
module DataObjects
|
18
18
|
class LengthMismatchError < StandardError; end
|
19
|
-
|
20
|
-
def self.root
|
21
|
-
@root ||= Pathname(__FILE__).dirname.parent.expand_path
|
22
|
-
end
|
23
|
-
|
24
19
|
end
|
data/lib/data_objects/command.rb
CHANGED
@@ -1,30 +1,80 @@
|
|
1
1
|
module DataObjects
|
2
|
+
# Abstract base class for adapter-specific Command subclasses
|
2
3
|
class Command
|
3
4
|
|
5
|
+
# The Connection on which the command will be run
|
4
6
|
attr_reader :connection
|
5
7
|
|
6
|
-
#
|
8
|
+
# Create a new Command object on the specified connection
|
7
9
|
def initialize(connection, text)
|
8
10
|
raise ArgumentError.new("+connection+ must be a DataObjects::Connection") unless DataObjects::Connection === connection
|
9
11
|
@connection, @text = connection, text
|
10
12
|
end
|
11
13
|
|
14
|
+
# Execute this command and return no dataset
|
12
15
|
def execute_non_query(*args)
|
13
16
|
raise NotImplementedError.new
|
14
17
|
end
|
15
18
|
|
19
|
+
# Execute this command and return a DataObjects::Reader for a dataset
|
16
20
|
def execute_reader(*args)
|
17
21
|
raise NotImplementedError.new
|
18
22
|
end
|
19
23
|
|
24
|
+
# Assign an array of types for the columns to be returned by this command
|
20
25
|
def set_types(column_types)
|
21
26
|
raise NotImplementedError.new
|
22
27
|
end
|
23
28
|
|
29
|
+
# Display the command text
|
24
30
|
def to_s
|
25
31
|
@text
|
26
32
|
end
|
27
33
|
|
34
|
+
private
|
35
|
+
|
36
|
+
# Escape a string of SQL with a set of arguments.
|
37
|
+
# The first argument is assumed to be the SQL to escape,
|
38
|
+
# the remaining arguments (if any) are assumed to be
|
39
|
+
# values to escape and interpolate.
|
40
|
+
#
|
41
|
+
# ==== Examples
|
42
|
+
# escape_sql("SELECT * FROM zoos")
|
43
|
+
# # => "SELECT * FROM zoos"
|
44
|
+
#
|
45
|
+
# escape_sql("SELECT * FROM zoos WHERE name = ?", "Dallas")
|
46
|
+
# # => "SELECT * FROM zoos WHERE name = `Dallas`"
|
47
|
+
#
|
48
|
+
# escape_sql("SELECT * FROM zoos WHERE name = ? AND acreage > ?", "Dallas", 40)
|
49
|
+
# # => "SELECT * FROM zoos WHERE name = `Dallas` AND acreage > 40"
|
50
|
+
#
|
51
|
+
# ==== Warning
|
52
|
+
# This method is meant mostly for adapters that don't support
|
53
|
+
# bind-parameters.
|
54
|
+
def escape_sql(args)
|
55
|
+
sql = @text.dup
|
56
|
+
vars = args.dup
|
57
|
+
|
58
|
+
replacements = 0
|
59
|
+
mismatch = false
|
60
|
+
|
61
|
+
sql.gsub!(/\?/) do |x|
|
62
|
+
replacements += 1
|
63
|
+
if vars.empty?
|
64
|
+
mismatch = true
|
65
|
+
else
|
66
|
+
var = vars.shift
|
67
|
+
connection.quote_value(var)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if !vars.empty? || mismatch
|
72
|
+
raise ArgumentError, "Binding mismatch: #{args.size} for #{replacements}"
|
73
|
+
else
|
74
|
+
sql
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
28
78
|
end
|
29
79
|
|
30
80
|
end
|
@@ -6,8 +6,11 @@ rescue LoadError
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module DataObjects
|
9
|
+
# An abstract connection to a DataObjects resource. The physical connection may be broken and re-established from time to time.
|
9
10
|
class Connection
|
10
11
|
|
12
|
+
# Make a connection to the database using the DataObjects::URI given.
|
13
|
+
# Note that the physical connection may be delayed until the first command is issued, so success here doesn't necessarily mean you can connect.
|
11
14
|
def self.new(uri_s)
|
12
15
|
uri = DataObjects::URI::parse(uri_s)
|
13
16
|
|
@@ -40,9 +43,12 @@ module DataObjects
|
|
40
43
|
DataObjects.const_get(driver_name.capitalize)::Connection.new(conn_uri)
|
41
44
|
end
|
42
45
|
|
46
|
+
# Ensure that all Connection subclasses handle pooling and logging uniformly.
|
47
|
+
# See also Extlib::Pooling and DataObjects::Logger
|
43
48
|
def self.inherited(target)
|
44
49
|
target.class_eval do
|
45
50
|
|
51
|
+
# Allocate a Connection object from the pool, creating one if necessary. This method is active in Connection subclasses only.
|
46
52
|
def self.new(*args)
|
47
53
|
instance = allocate
|
48
54
|
instance.send(:initialize, *args)
|
@@ -50,6 +56,8 @@ module DataObjects
|
|
50
56
|
end
|
51
57
|
|
52
58
|
include Extlib::Pooling
|
59
|
+
include Quoting
|
60
|
+
|
53
61
|
alias close release
|
54
62
|
end
|
55
63
|
|
@@ -72,18 +80,21 @@ module DataObjects
|
|
72
80
|
#####################################################
|
73
81
|
# Standard API Definition
|
74
82
|
#####################################################
|
83
|
+
|
84
|
+
# Show the URI for this connection
|
75
85
|
def to_s
|
76
86
|
@uri.to_s
|
77
87
|
end
|
78
88
|
|
79
|
-
def initialize(uri)
|
89
|
+
def initialize(uri) #:nodoc:
|
80
90
|
raise NotImplementedError.new
|
81
91
|
end
|
82
92
|
|
83
|
-
def dispose
|
93
|
+
def dispose #:nodoc:
|
84
94
|
raise NotImplementedError.new
|
85
95
|
end
|
86
96
|
|
97
|
+
# Create a Command object of the right subclass using the given text
|
87
98
|
def create_command(text)
|
88
99
|
concrete_command.new(self, text)
|
89
100
|
end
|
data/lib/data_objects/logger.rb
CHANGED
@@ -1,47 +1,54 @@
|
|
1
1
|
require "time" # httpdate
|
2
|
-
|
3
|
-
#
|
4
|
-
# Logger taken from Merb :)
|
5
|
-
#
|
6
|
-
# To replace an existing logger with a new one:
|
7
|
-
# DataObjects::Logger.set_log(log{String, IO},level{Symbol, String})
|
8
|
-
#
|
9
|
-
# Available logging levels are
|
10
|
-
# DataObjects::Logger::{ Fatal, Error, Warn, Info, Debug }
|
11
|
-
#
|
12
|
-
# Logging via:
|
13
|
-
# DataObjects.logger.fatal(message<String>)
|
14
|
-
# DataObjects.logger.error(message<String>)
|
15
|
-
# DataObjects.logger.warn(message<String>)
|
16
|
-
# DataObjects.logger.info(message<String>)
|
17
|
-
# DataObjects.logger.debug(message<String>)
|
18
|
-
#
|
19
|
-
# Flush the buffer to
|
20
|
-
# DataObjects.logger.flush
|
21
|
-
#
|
22
|
-
# Remove the current log object
|
23
|
-
# DataObjects.logger.close
|
24
|
-
#
|
25
|
-
# ==== Private DataObjects Logger API
|
26
|
-
#
|
27
|
-
# To initialize the logger you create a new object, proxies to set_log.
|
28
|
-
# DataObjects::Logger.new(log{String, IO},level{Symbol, String})
|
29
|
-
#
|
30
|
-
# Logger will not create the file until something is actually logged
|
31
|
-
# This avoids file creation on DataObjects init when it creates the
|
32
|
-
# default logger.
|
2
|
+
|
33
3
|
module DataObjects
|
34
4
|
|
35
|
-
class << self
|
5
|
+
class << self
|
6
|
+
# The global logger for DataObjects
|
36
7
|
attr_accessor :logger
|
37
8
|
end
|
38
9
|
|
10
|
+
# ==== Public DataObjects Logger API
|
11
|
+
#
|
12
|
+
# Logger taken from Merb :)
|
13
|
+
#
|
14
|
+
# To replace an existing logger with a new one:
|
15
|
+
# DataObjects::Logger.set_log(log{String, IO},level{Symbol, String})
|
16
|
+
#
|
17
|
+
# Available logging levels are
|
18
|
+
# DataObjects::Logger::{ Fatal, Error, Warn, Info, Debug }
|
19
|
+
#
|
20
|
+
# Logging via:
|
21
|
+
# DataObjects.logger.fatal(message<String>)
|
22
|
+
# DataObjects.logger.error(message<String>)
|
23
|
+
# DataObjects.logger.warn(message<String>)
|
24
|
+
# DataObjects.logger.info(message<String>)
|
25
|
+
# DataObjects.logger.debug(message<String>)
|
26
|
+
#
|
27
|
+
# Flush the buffer to
|
28
|
+
# DataObjects.logger.flush
|
29
|
+
#
|
30
|
+
# Remove the current log object
|
31
|
+
# DataObjects.logger.close
|
32
|
+
#
|
33
|
+
# ==== Private DataObjects Logger API
|
34
|
+
#
|
35
|
+
# To initialize the logger you create a new object, proxies to set_log.
|
36
|
+
# DataObjects::Logger.new(log{String, IO},level{Symbol, String})
|
37
|
+
#
|
38
|
+
# Logger will not create the file until something is actually logged
|
39
|
+
# This avoids file creation on DataObjects init when it creates the
|
40
|
+
# default logger.
|
39
41
|
class Logger
|
40
42
|
|
43
|
+
# Use asynchronous I/O?
|
41
44
|
attr_accessor :aio
|
45
|
+
# delimiter to use between message sections
|
42
46
|
attr_accessor :delimiter
|
47
|
+
# a symbol representing the log level from {:off, :fatal, :error, :warn, :info, :debug}
|
43
48
|
attr_reader :level
|
49
|
+
# Direct access to the buffer
|
44
50
|
attr_reader :buffer
|
51
|
+
# The name of the log file
|
45
52
|
attr_reader :log
|
46
53
|
|
47
54
|
# @note
|
@@ -64,6 +71,7 @@ module DataObjects
|
|
64
71
|
:debug => 0
|
65
72
|
}
|
66
73
|
|
74
|
+
# Set the log level (use the level symbols as documented)
|
67
75
|
def level=(new_level)
|
68
76
|
@level = LEVELS[new_level.to_sym]
|
69
77
|
reset_methods(:close)
|
data/lib/data_objects/quoting.rb
CHANGED
@@ -1,43 +1,14 @@
|
|
1
1
|
module DataObjects
|
2
2
|
|
3
3
|
module Quoting
|
4
|
-
# Escape a string of SQL with a set of arguments.
|
5
|
-
# The first argument is assumed to be the SQL to escape,
|
6
|
-
# the remaining arguments (if any) are assumed to be
|
7
|
-
# values to escape and interpolate.
|
8
|
-
#
|
9
|
-
# ==== Examples
|
10
|
-
# escape_sql("SELECT * FROM zoos")
|
11
|
-
# # => "SELECT * FROM zoos"
|
12
|
-
#
|
13
|
-
# escape_sql("SELECT * FROM zoos WHERE name = ?", "Dallas")
|
14
|
-
# # => "SELECT * FROM zoos WHERE name = `Dallas`"
|
15
|
-
#
|
16
|
-
# escape_sql("SELECT * FROM zoos WHERE name = ? AND acreage > ?", "Dallas", 40)
|
17
|
-
# # => "SELECT * FROM zoos WHERE name = `Dallas` AND acreage > 40"
|
18
|
-
#
|
19
|
-
# ==== Warning
|
20
|
-
# This method is meant mostly for adapters that don't support
|
21
|
-
# bind-parameters.
|
22
|
-
def escape_sql(args)
|
23
|
-
sql = @text.dup
|
24
|
-
|
25
|
-
unless args.empty?
|
26
|
-
sql.gsub!(/\?/) do |x|
|
27
|
-
quote_value(args.shift)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
sql
|
32
|
-
end
|
33
4
|
|
5
|
+
# Quote a value of any of the recognised data types
|
34
6
|
def quote_value(value)
|
35
7
|
return 'NULL' if value.nil?
|
36
8
|
|
37
9
|
case value
|
38
10
|
when Numeric then quote_numeric(value)
|
39
11
|
when String then quote_string(value)
|
40
|
-
when Class then quote_class(value)
|
41
12
|
when Time then quote_time(value)
|
42
13
|
when DateTime then quote_datetime(value)
|
43
14
|
when Date then quote_date(value)
|
@@ -46,58 +17,83 @@ module DataObjects
|
|
46
17
|
when Range then quote_range(value)
|
47
18
|
when Symbol then quote_symbol(value)
|
48
19
|
when Regexp then quote_regexp(value)
|
20
|
+
when ::Extlib::ByteArray then quote_byte_array(value)
|
21
|
+
when Class then quote_class(value)
|
49
22
|
else
|
50
23
|
if value.respond_to?(:to_sql)
|
51
24
|
value.to_sql
|
52
25
|
else
|
53
|
-
raise "Don't know how to quote #{value.inspect}"
|
26
|
+
raise "Don't know how to quote #{value.class} objects (#{value.inspect})"
|
54
27
|
end
|
55
28
|
end
|
56
29
|
end
|
57
30
|
|
31
|
+
# Convert the Symbol to a String and quote that
|
58
32
|
def quote_symbol(value)
|
59
33
|
quote_string(value.to_s)
|
60
34
|
end
|
61
35
|
|
36
|
+
# Convert the Numeric to a String and quote that
|
62
37
|
def quote_numeric(value)
|
63
38
|
value.to_s
|
64
39
|
end
|
65
40
|
|
41
|
+
# Quote a String for SQL by doubling any embedded single-quote characters
|
66
42
|
def quote_string(value)
|
67
43
|
"'#{value.gsub("'", "''")}'"
|
68
44
|
end
|
69
45
|
|
46
|
+
# Quote a class by quoting its name
|
70
47
|
def quote_class(value)
|
71
48
|
quote_string(value.name)
|
72
49
|
end
|
73
50
|
|
51
|
+
# Convert a Time to standard YMDHMS format (with microseconds if necessary)
|
74
52
|
def quote_time(value)
|
75
|
-
|
53
|
+
offset = value.utc_offset
|
54
|
+
if offset >= 0
|
55
|
+
offset_string = "+#{sprintf("%02d", offset / 3600)}:#{sprintf("%02d", (offset % 3600) / 60)}"
|
56
|
+
elsif offset < 0
|
57
|
+
offset_string = "-#{sprintf("%02d", -offset / 3600)}:#{sprintf("%02d", (-offset % 3600) / 60)}"
|
58
|
+
end
|
59
|
+
"'#{value.strftime('%Y-%m-%dT%H:%M:%S')}" << (value.usec > 0 ? ".#{value.usec.to_s.rjust(6, '0')}" : "") << offset_string << "'"
|
76
60
|
end
|
77
61
|
|
62
|
+
# Quote a DateTime by relying on it's own to_s conversion
|
78
63
|
def quote_datetime(value)
|
79
64
|
"'#{value.dup}'"
|
80
65
|
end
|
81
66
|
|
67
|
+
# Convert a Date to standard YMD format
|
82
68
|
def quote_date(value)
|
83
69
|
"'#{value.strftime("%Y-%m-%d")}'"
|
84
70
|
end
|
85
71
|
|
72
|
+
# Quote true, false as the strings TRUE, FALSE
|
86
73
|
def quote_boolean(value)
|
87
74
|
value.to_s.upcase
|
88
75
|
end
|
89
76
|
|
77
|
+
# Quote an array as a list of quoted values
|
90
78
|
def quote_array(value)
|
91
79
|
"(#{value.map { |entry| quote_value(entry) }.join(', ')})"
|
92
80
|
end
|
93
81
|
|
82
|
+
# Quote a range by joining the quoted end-point values with AND.
|
83
|
+
# It's not clear whether or when this is a useful or correct thing to do.
|
94
84
|
def quote_range(value)
|
95
85
|
"#{quote_value(value.first)} AND #{quote_value(value.last)}"
|
96
86
|
end
|
97
87
|
|
88
|
+
# Quote a Regex using its string value. Note that there's no attempt to make a valid SQL "LIKE" string.
|
98
89
|
def quote_regexp(value)
|
99
90
|
quote_string(value.source)
|
100
91
|
end
|
92
|
+
|
93
|
+
def quote_byte_array(value)
|
94
|
+
quote_string(value.source)
|
95
|
+
end
|
96
|
+
|
101
97
|
end
|
102
98
|
|
103
99
|
end
|