data_objects 0.9.11 → 0.9.12
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/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
|