sequel 2.11.0 → 2.12.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/CHANGELOG +168 -0
- data/README.rdoc +77 -95
- data/Rakefile +100 -80
- data/bin/sequel +2 -1
- data/doc/advanced_associations.rdoc +23 -32
- data/doc/cheat_sheet.rdoc +23 -40
- data/doc/dataset_filtering.rdoc +6 -6
- data/doc/prepared_statements.rdoc +22 -22
- data/doc/release_notes/2.12.0.txt +534 -0
- data/doc/schema.rdoc +3 -1
- data/doc/sharding.rdoc +8 -8
- data/doc/virtual_rows.rdoc +65 -0
- data/lib/sequel.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/ado.rb +3 -3
- data/lib/{sequel_core → sequel}/adapters/db2.rb +0 -0
- data/lib/{sequel_core → sequel}/adapters/dbi.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/do.rb +9 -5
- data/lib/{sequel_core → sequel}/adapters/do/mysql.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/do/postgres.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/do/sqlite.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/firebird.rb +84 -80
- data/lib/{sequel_core → sequel}/adapters/informix.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/jdbc.rb +21 -14
- data/lib/{sequel_core → sequel}/adapters/jdbc/h2.rb +14 -13
- data/lib/{sequel_core → sequel}/adapters/jdbc/mysql.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/jdbc/oracle.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/jdbc/postgresql.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/jdbc/sqlite.rb +1 -1
- data/lib/{sequel_core → sequel}/adapters/mysql.rb +60 -39
- data/lib/{sequel_core → sequel}/adapters/odbc.rb +8 -4
- data/lib/{sequel_core → sequel}/adapters/openbase.rb +0 -0
- data/lib/{sequel_core → sequel}/adapters/oracle.rb +38 -7
- data/lib/{sequel_core → sequel}/adapters/postgres.rb +24 -24
- data/lib/{sequel_core → sequel}/adapters/shared/mssql.rb +5 -5
- data/lib/{sequel_core → sequel}/adapters/shared/mysql.rb +126 -71
- data/lib/{sequel_core → sequel}/adapters/shared/oracle.rb +7 -10
- data/lib/{sequel_core → sequel}/adapters/shared/postgres.rb +159 -125
- data/lib/{sequel_core → sequel}/adapters/shared/progress.rb +1 -2
- data/lib/{sequel_core → sequel}/adapters/shared/sqlite.rb +72 -67
- data/lib/{sequel_core → sequel}/adapters/sqlite.rb +11 -7
- data/lib/{sequel_core → sequel}/adapters/utils/date_format.rb +0 -0
- data/lib/{sequel_core → sequel}/adapters/utils/stored_procedures.rb +0 -0
- data/lib/{sequel_core → sequel}/adapters/utils/unsupported.rb +19 -0
- data/lib/{sequel_core → sequel}/connection_pool.rb +7 -5
- data/lib/sequel/core.rb +221 -0
- data/lib/{sequel_core → sequel}/core_sql.rb +91 -49
- data/lib/{sequel_core → sequel}/database.rb +264 -149
- data/lib/{sequel_core/schema/generator.rb → sequel/database/schema_generator.rb} +6 -2
- data/lib/{sequel_core/database/schema.rb → sequel/database/schema_methods.rb} +12 -12
- data/lib/sequel/database/schema_sql.rb +224 -0
- data/lib/{sequel_core → sequel}/dataset.rb +78 -236
- data/lib/{sequel_core → sequel}/dataset/convenience.rb +99 -61
- data/lib/{sequel_core/object_graph.rb → sequel/dataset/graph.rb} +16 -14
- data/lib/{sequel_core → sequel}/dataset/prepared_statements.rb +1 -1
- data/lib/{sequel_core → sequel}/dataset/sql.rb +150 -99
- data/lib/sequel/deprecated.rb +593 -0
- data/lib/sequel/deprecated_migration.rb +91 -0
- data/lib/sequel/exceptions.rb +48 -0
- data/lib/sequel/extensions/blank.rb +42 -0
- data/lib/{sequel_model → sequel/extensions}/inflector.rb +8 -1
- data/lib/{sequel_core → sequel/extensions}/migration.rb +1 -1
- data/lib/{sequel_core/dataset → sequel/extensions}/pagination.rb +0 -0
- data/lib/{sequel_core → sequel/extensions}/pretty_table.rb +7 -0
- data/lib/{sequel_core/dataset → sequel/extensions}/query.rb +7 -0
- data/lib/sequel/extensions/string_date_time.rb +47 -0
- data/lib/sequel/metaprogramming.rb +43 -0
- data/lib/sequel/model.rb +110 -0
- data/lib/sequel/model/associations.rb +1300 -0
- data/lib/sequel/model/base.rb +937 -0
- data/lib/sequel/model/deprecated.rb +204 -0
- data/lib/sequel/model/deprecated_hooks.rb +103 -0
- data/lib/sequel/model/deprecated_inflector.rb +335 -0
- data/lib/sequel/model/deprecated_validations.rb +388 -0
- data/lib/sequel/model/errors.rb +39 -0
- data/lib/{sequel_model → sequel/model}/exceptions.rb +4 -4
- data/lib/sequel/model/inflections.rb +208 -0
- data/lib/sequel/model/plugins.rb +76 -0
- data/lib/sequel/plugins/caching.rb +122 -0
- data/lib/sequel/plugins/hook_class_methods.rb +122 -0
- data/lib/sequel/plugins/schema.rb +53 -0
- data/lib/sequel/plugins/serialization.rb +117 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
- data/lib/sequel/plugins/validation_class_methods.rb +384 -0
- data/lib/sequel/plugins/validation_helpers.rb +150 -0
- data/lib/{sequel_core → sequel}/sql.rb +125 -190
- data/lib/{sequel_core → sequel}/version.rb +2 -1
- data/lib/sequel_core.rb +1 -172
- data/lib/sequel_model.rb +1 -91
- data/spec/adapters/firebird_spec.rb +5 -5
- data/spec/adapters/informix_spec.rb +1 -1
- data/spec/adapters/mysql_spec.rb +128 -42
- data/spec/adapters/oracle_spec.rb +47 -19
- data/spec/adapters/postgres_spec.rb +64 -52
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +12 -17
- data/spec/{sequel_core → core}/connection_pool_spec.rb +10 -10
- data/spec/{sequel_core → core}/core_ext_spec.rb +19 -19
- data/spec/{sequel_core → core}/core_sql_spec.rb +68 -71
- data/spec/{sequel_core → core}/database_spec.rb +135 -99
- data/spec/{sequel_core → core}/dataset_spec.rb +398 -242
- data/spec/{sequel_core → core}/expression_filters_spec.rb +13 -13
- data/spec/core/migration_spec.rb +263 -0
- data/spec/{sequel_core → core}/object_graph_spec.rb +10 -10
- data/spec/{sequel_core → core}/pretty_table_spec.rb +2 -2
- data/spec/{sequel_core → core}/schema_generator_spec.rb +0 -0
- data/spec/{sequel_core → core}/schema_spec.rb +8 -10
- data/spec/{sequel_core → core}/spec_helper.rb +29 -2
- data/spec/{sequel_core → core}/version_spec.rb +0 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/caching_spec.rb +201 -0
- data/spec/{sequel_model/hooks_spec.rb → extensions/hook_class_methods_spec.rb} +8 -23
- data/spec/{sequel_model → extensions}/inflector_spec.rb +3 -0
- data/spec/{sequel_core → extensions}/migration_spec.rb +4 -4
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/{sequel_model → extensions}/schema_spec.rb +22 -1
- data/spec/extensions/serialization_spec.rb +109 -0
- data/spec/extensions/single_table_inheritance_spec.rb +53 -0
- data/spec/{sequel_model → extensions}/spec_helper.rb +13 -4
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/{sequel_model/validations_spec.rb → extensions/validation_class_methods_spec.rb} +15 -103
- data/spec/extensions/validation_helpers_spec.rb +291 -0
- data/spec/integration/dataset_test.rb +31 -0
- data/spec/integration/eager_loader_test.rb +17 -30
- data/spec/integration/schema_test.rb +8 -5
- data/spec/integration/spec_helper.rb +17 -0
- data/spec/integration/transaction_test.rb +68 -0
- data/spec/{sequel_model → model}/association_reflection_spec.rb +0 -0
- data/spec/{sequel_model → model}/associations_spec.rb +23 -10
- data/spec/{sequel_model → model}/base_spec.rb +29 -20
- data/spec/{sequel_model → model}/caching_spec.rb +16 -14
- data/spec/{sequel_model → model}/dataset_methods_spec.rb +0 -0
- data/spec/{sequel_model → model}/eager_loading_spec.rb +8 -8
- data/spec/model/hooks_spec.rb +472 -0
- data/spec/model/inflector_spec.rb +126 -0
- data/spec/{sequel_model → model}/model_spec.rb +25 -20
- data/spec/model/plugins_spec.rb +142 -0
- data/spec/{sequel_model → model}/record_spec.rb +121 -62
- data/spec/model/schema_spec.rb +92 -0
- data/spec/model/spec_helper.rb +124 -0
- data/spec/model/validations_spec.rb +1080 -0
- metadata +136 -107
- data/lib/sequel_core/core_ext.rb +0 -217
- data/lib/sequel_core/dataset/callback.rb +0 -13
- data/lib/sequel_core/dataset/schema.rb +0 -15
- data/lib/sequel_core/deprecated.rb +0 -26
- data/lib/sequel_core/exceptions.rb +0 -44
- data/lib/sequel_core/schema.rb +0 -2
- data/lib/sequel_core/schema/sql.rb +0 -325
- data/lib/sequel_model/association_reflection.rb +0 -267
- data/lib/sequel_model/associations.rb +0 -499
- data/lib/sequel_model/base.rb +0 -539
- data/lib/sequel_model/caching.rb +0 -82
- data/lib/sequel_model/dataset_methods.rb +0 -26
- data/lib/sequel_model/eager_loading.rb +0 -370
- data/lib/sequel_model/hooks.rb +0 -101
- data/lib/sequel_model/plugins.rb +0 -62
- data/lib/sequel_model/record.rb +0 -568
- data/lib/sequel_model/schema.rb +0 -49
- data/lib/sequel_model/validations.rb +0 -429
- data/spec/sequel_model/plugins_spec.rb +0 -80
data/Rakefile
CHANGED
|
@@ -1,46 +1,45 @@
|
|
|
1
1
|
require "rake"
|
|
2
2
|
require "rake/clean"
|
|
3
3
|
require "rake/gempackagetask"
|
|
4
|
-
require "spec/rake/spectask"
|
|
5
4
|
begin
|
|
6
5
|
require "hanna/rdoctask"
|
|
7
6
|
rescue LoadError
|
|
8
7
|
require "rake/rdoctask"
|
|
9
8
|
end
|
|
10
|
-
require "fileutils"
|
|
11
|
-
require "lib/sequel_core/version"
|
|
12
|
-
|
|
13
|
-
include FileUtils
|
|
14
9
|
|
|
15
10
|
NAME = 'sequel'
|
|
16
|
-
VERS =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
VERS = lambda do
|
|
12
|
+
require "lib/sequel/version"
|
|
13
|
+
Sequel.version
|
|
14
|
+
end
|
|
15
|
+
CLEAN.include ["**/.*.sw?", "pkg", ".config", "rdoc", "coverage", "www/public/*.html", "www/public/rdoc*"]
|
|
16
|
+
RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Sequel: The Database Toolkit for Ruby']
|
|
17
|
+
RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
|
|
20
18
|
|
|
21
19
|
# Gem Packaging and Release
|
|
22
20
|
|
|
23
|
-
desc "Packages sequel"
|
|
24
|
-
task :package=>[:clean]
|
|
25
21
|
spec = Gem::Specification.new do |s|
|
|
26
22
|
s.name = NAME
|
|
27
23
|
s.rubyforge_project = 'sequel'
|
|
28
|
-
s.version = VERS
|
|
24
|
+
s.version = VERS.call
|
|
29
25
|
s.platform = Gem::Platform::RUBY
|
|
30
26
|
s.has_rdoc = true
|
|
31
27
|
s.extra_rdoc_files = ["README.rdoc", "CHANGELOG", "COPYING"] + Dir["doc/*.rdoc"] + Dir['doc/release_notes/*.txt']
|
|
32
|
-
s.rdoc_options += RDOC_OPTS
|
|
28
|
+
s.rdoc_options += RDOC_OPTS
|
|
33
29
|
s.summary = "The Database Toolkit for Ruby"
|
|
34
30
|
s.description = s.summary
|
|
35
31
|
s.author = "Jeremy Evans"
|
|
36
32
|
s.email = "code@jeremyevans.net"
|
|
37
33
|
s.homepage = "http://sequel.rubyforge.org"
|
|
38
34
|
s.required_ruby_version = ">= 1.8.4"
|
|
39
|
-
s.files = %w(COPYING CHANGELOG README.rdoc Rakefile) + Dir
|
|
35
|
+
s.files = %w(COPYING CHANGELOG README.rdoc Rakefile) + Dir["{bin,doc,spec,lib}/**/*"]
|
|
40
36
|
s.require_path = "lib"
|
|
41
37
|
s.bindir = 'bin'
|
|
42
38
|
s.executables << 'sequel'
|
|
43
39
|
end
|
|
40
|
+
|
|
41
|
+
desc "Packages sequel"
|
|
42
|
+
task :package=>[:clean]
|
|
44
43
|
Rake::GemPackageTask.new(spec) do |p|
|
|
45
44
|
p.need_tar = true
|
|
46
45
|
p.gem_spec = spec
|
|
@@ -48,12 +47,7 @@ end
|
|
|
48
47
|
|
|
49
48
|
desc "Install sequel gem"
|
|
50
49
|
task :install=>[:package] do
|
|
51
|
-
sh %{sudo gem install pkg/#{NAME}-#{VERS} --local}
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
desc "Install sequel gem without RDoc"
|
|
55
|
-
task :install_no_docs=>[:package] do
|
|
56
|
-
sh %{sudo gem install pkg/#{NAME}-#{VERS} --no-rdoc --no-ri --local}
|
|
50
|
+
sh %{sudo gem install pkg/#{NAME}-#{VERS.call} --local}
|
|
57
51
|
end
|
|
58
52
|
|
|
59
53
|
desc "Uninstall sequel gem"
|
|
@@ -61,11 +55,11 @@ task :uninstall=>[:clean] do
|
|
|
61
55
|
sh %{sudo gem uninstall #{NAME}}
|
|
62
56
|
end
|
|
63
57
|
|
|
64
|
-
desc "Upload sequel
|
|
58
|
+
desc "Upload sequel gem to rubyforge"
|
|
65
59
|
task :release=>[:package] do
|
|
66
60
|
sh %{rubyforge login}
|
|
67
|
-
sh %{rubyforge add_release sequel #{NAME} #{VERS} pkg/#{NAME}-#{VERS}.tgz}
|
|
68
|
-
sh %{rubyforge add_file sequel #{NAME} #{VERS} pkg/#{NAME}-#{VERS}.gem}
|
|
61
|
+
sh %{rubyforge add_release sequel #{NAME} #{VERS.call} pkg/#{NAME}-#{VERS.call}.tgz}
|
|
62
|
+
sh %{rubyforge add_file sequel #{NAME} #{VERS.call} pkg/#{NAME}-#{VERS.call}.gem}
|
|
69
63
|
end
|
|
70
64
|
|
|
71
65
|
### RDoc
|
|
@@ -78,73 +72,103 @@ end
|
|
|
78
72
|
|
|
79
73
|
### Website
|
|
80
74
|
|
|
81
|
-
desc "
|
|
82
|
-
task :
|
|
75
|
+
desc "Make local version of website"
|
|
76
|
+
task :website do
|
|
83
77
|
sh %{www/make_www.rb}
|
|
84
|
-
sh %{scp -r www/public/* rubyforge.org:/var/www/gforge-projects/sequel/}
|
|
85
78
|
end
|
|
86
79
|
|
|
87
|
-
desc "
|
|
88
|
-
task :website_rdoc=>[:
|
|
89
|
-
sh %{scp -r rdoc/* rubyforge.org:/var/www/gforge-projects/sequel/rdoc/}
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
desc "Update sequel.rubyforge.org"
|
|
93
|
-
task :website=>[:website_base, :website_rdoc]
|
|
94
|
-
|
|
95
|
-
### Specs
|
|
80
|
+
desc "Make rdoc for website"
|
|
81
|
+
task :website_rdoc=>[:website_rdoc_main, :website_rdoc_adapters, :website_rdoc_plugins]
|
|
96
82
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
spec_opts = proc{File.read("spec/spec.opts").split("\n")}
|
|
102
|
-
rcov_opts = proc{File.read("spec/rcov.opts").split("\n")}
|
|
103
|
-
|
|
104
|
-
desc "Run core and model specs with coverage"
|
|
105
|
-
Spec::Rake::SpecTask.new("spec_coverage") do |t|
|
|
106
|
-
fixRUBYLIB.call
|
|
107
|
-
t.spec_files = FileList[sequel_core_specs, sequel_model_specs]
|
|
108
|
-
t.spec_opts = spec_opts.call
|
|
109
|
-
t.rcov_opts = rcov_opts.call
|
|
110
|
-
t.rcov = true
|
|
83
|
+
Rake::RDocTask.new(:website_rdoc_main) do |rdoc|
|
|
84
|
+
rdoc.rdoc_dir = "www/public/rdoc"
|
|
85
|
+
rdoc.options += RDOC_OPTS
|
|
86
|
+
rdoc.rdoc_files.add %w"README.rdoc CHANGELOG COPYING lib/*.rb lib/sequel/*.rb lib/sequel/{dataset,database,model}/*.rb doc/*.rdoc doc/release_notes/*.txt"
|
|
111
87
|
end
|
|
112
88
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
t.spec_files = FileList[sequel_core_specs, sequel_model_specs]
|
|
118
|
-
t.spec_opts = spec_opts.call
|
|
89
|
+
Rake::RDocTask.new(:website_rdoc_adapters) do |rdoc|
|
|
90
|
+
rdoc.rdoc_dir = "www/public/rdoc-adapters"
|
|
91
|
+
rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
|
|
92
|
+
rdoc.rdoc_files.add %w"lib/sequel/adapters/**/*.rb"
|
|
119
93
|
end
|
|
120
94
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
t.spec_opts = spec_opts.call
|
|
95
|
+
Rake::RDocTask.new(:website_rdoc_plugins) do |rdoc|
|
|
96
|
+
rdoc.rdoc_dir = "www/public/rdoc-plugins"
|
|
97
|
+
rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
|
|
98
|
+
rdoc.rdoc_files.add %w"lib/sequel/{extensions,plugins}/**/*.rb"
|
|
126
99
|
end
|
|
127
100
|
|
|
128
|
-
desc "
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
t.spec_files = FileList[sequel_model_specs]
|
|
132
|
-
t.spec_opts = spec_opts.call
|
|
101
|
+
desc "Update Non-RDoc section of sequel.rubyforge.org"
|
|
102
|
+
task :website_rf_base=>[:website] do
|
|
103
|
+
sh %{rsync -rt www/public/*.html rubyforge.org:/var/www/gforge-projects/sequel/}
|
|
133
104
|
end
|
|
134
105
|
|
|
135
|
-
desc "
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
t.spec_files = FileList["spec/integration/*_test.rb"]
|
|
139
|
-
t.spec_opts = spec_opts.call
|
|
106
|
+
desc "Update sequel.rubyforge.org"
|
|
107
|
+
task :website_rf=>[:website, :website_rdoc] do
|
|
108
|
+
sh %{rsync -rvt www/public/* rubyforge.org:/var/www/gforge-projects/sequel/}
|
|
140
109
|
end
|
|
141
110
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
111
|
+
### Specs
|
|
112
|
+
|
|
113
|
+
begin
|
|
114
|
+
require "spec/rake/spectask"
|
|
115
|
+
|
|
116
|
+
spec_opts = lambda do
|
|
117
|
+
lib_dir = File.join(File.dirname(__FILE__), 'lib')
|
|
118
|
+
ENV['RUBYLIB'] ? (ENV['RUBYLIB'] += ":#{lib_dir}") : (ENV['RUBYLIB'] = lib_dir)
|
|
119
|
+
File.read("spec/spec.opts").split("\n")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
rcov_opts = lambda do
|
|
123
|
+
[true, File.read("spec/rcov.opts").split("\n")]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
desc "Run core and model specs with coverage"
|
|
127
|
+
Spec::Rake::SpecTask.new("spec_coverage") do |t|
|
|
128
|
+
t.spec_files = Dir["spec/{core,model}/*_spec.rb"]
|
|
129
|
+
t.spec_opts = spec_opts.call
|
|
130
|
+
t.rcov, t.rcov_opts = rcov_opts.call
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
desc "Run core and model specs"
|
|
134
|
+
task :default => [:spec]
|
|
135
|
+
Spec::Rake::SpecTask.new("spec") do |t|
|
|
136
|
+
t.spec_files = Dir["spec/{core,model}/*_spec.rb"]
|
|
137
|
+
t.spec_opts = spec_opts.call
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
desc "Run core specs"
|
|
141
|
+
Spec::Rake::SpecTask.new("spec_core") do |t|
|
|
142
|
+
t.spec_files = Dir["spec/core/*_spec.rb"]
|
|
146
143
|
t.spec_opts = spec_opts.call
|
|
147
144
|
end
|
|
145
|
+
|
|
146
|
+
desc "Run model specs"
|
|
147
|
+
Spec::Rake::SpecTask.new("spec_model") do |t|
|
|
148
|
+
t.spec_files = Dir["spec/model/*_spec.rb"]
|
|
149
|
+
t.spec_opts = spec_opts.call
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
desc "Run extension/plugin specs"
|
|
153
|
+
Spec::Rake::SpecTask.new("spec_plugin") do |t|
|
|
154
|
+
t.spec_files = Dir["spec/extensions/*_spec.rb"]
|
|
155
|
+
t.spec_opts = spec_opts.call
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
desc "Run integration tests"
|
|
159
|
+
Spec::Rake::SpecTask.new("integration") do |t|
|
|
160
|
+
t.spec_files = FileList["spec/integration/*_test.rb"]
|
|
161
|
+
t.spec_opts = spec_opts.call
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
%w'postgres sqlite mysql informix oracle ado'.each do |adapter|
|
|
165
|
+
desc "Run #{adapter} specs without coverage"
|
|
166
|
+
Spec::Rake::SpecTask.new("spec_#{adapter}") do |t|
|
|
167
|
+
t.spec_files = ["spec/adapters/#{adapter}_spec.rb"]
|
|
168
|
+
t.spec_opts = spec_opts.call
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
rescue LoadError
|
|
148
172
|
end
|
|
149
173
|
|
|
150
174
|
desc "check documentation coverage"
|
|
@@ -154,13 +178,9 @@ end
|
|
|
154
178
|
|
|
155
179
|
### Statistics
|
|
156
180
|
|
|
157
|
-
STATS_DIRECTORIES = [
|
|
158
|
-
%w(Code lib/),
|
|
159
|
-
%w(Spec spec),
|
|
160
|
-
].collect { |name, dir| [ name, "./#{dir}" ] }.select { |name, dir| File.directory?(dir) }
|
|
161
|
-
|
|
162
181
|
desc "Report code statistics (KLOCs, etc) from the application"
|
|
163
182
|
task :stats do
|
|
183
|
+
STATS_DIRECTORIES = [%w(Code lib/), %w(Spec spec)].map{|name, dir| [ name, "./#{dir}" ] }.select { |name, dir| File.directory?(dir)}
|
|
164
184
|
require "extra/stats"
|
|
165
185
|
verbose = true
|
|
166
186
|
CodeStatistics.new(*STATS_DIRECTORIES).to_s
|
|
@@ -168,5 +188,5 @@ end
|
|
|
168
188
|
|
|
169
189
|
desc "Print Sequel version"
|
|
170
190
|
task :version do
|
|
171
|
-
puts VERS
|
|
191
|
+
puts VERS.call
|
|
172
192
|
end
|
data/bin/sequel
CHANGED
|
@@ -63,7 +63,7 @@ opts.parse!
|
|
|
63
63
|
|
|
64
64
|
db = ARGV.shift
|
|
65
65
|
|
|
66
|
-
if db.
|
|
66
|
+
if db.nil? || db.empty?
|
|
67
67
|
puts opts
|
|
68
68
|
exit 1
|
|
69
69
|
end
|
|
@@ -88,6 +88,7 @@ begin
|
|
|
88
88
|
DB = Sequel.connect(*(db_config ? [db_config] : [db, db_opts]))
|
|
89
89
|
DB.test_connection
|
|
90
90
|
if migrate_dir
|
|
91
|
+
require 'sequel/extensions/migration'
|
|
91
92
|
Sequel::Migrator.apply(DB, migrate_dir, migrate_ver)
|
|
92
93
|
exit
|
|
93
94
|
end
|
|
@@ -4,7 +4,7 @@ Sequel::Model has the most powerful and flexible associations of any ruby ORM.
|
|
|
4
4
|
|
|
5
5
|
"Extraordinary claims require extraordinary proof" - Carl Sagan
|
|
6
6
|
|
|
7
|
-
==Background: Sequel::Model association options
|
|
7
|
+
== Background: Sequel::Model association options
|
|
8
8
|
|
|
9
9
|
There are a bunch of advanced association options that are available to
|
|
10
10
|
handle the other-than-bog-standard cases. First we'll go over some of
|
|
@@ -35,11 +35,10 @@ JOINing to the join table in a many_to_many association).
|
|
|
35
35
|
condition. The block is passed the associated table alias, current model
|
|
36
36
|
alias, and array of previous joins.
|
|
37
37
|
- :graph_only_conditions - Use these conditions instead of the standard
|
|
38
|
-
association conditions. This is necessary when
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
:graph_join_type).
|
|
38
|
+
association conditions. This is necessary when you don't want to have an
|
|
39
|
+
equal condition between the foreign key and primary key of the tables.
|
|
40
|
+
You can also use this to have a JOIN USING (array of symbols), or a NATURAL
|
|
41
|
+
or CROSS JOIN (nil, with the appropriate :graph_join_type).
|
|
43
42
|
|
|
44
43
|
These can be used like this:
|
|
45
44
|
|
|
@@ -55,21 +54,15 @@ These can be used like this:
|
|
|
55
54
|
Artist.one_to_many :gold_albums, :class=>:Album, \
|
|
56
55
|
:graph_block=>proc{|j,lj,js| :copies_sold.qualify(j) > 500000}
|
|
57
56
|
|
|
58
|
-
# Handles the case where the
|
|
59
|
-
# artist_name column in the albums table, when name is not the primary key
|
|
60
|
-
# of the artists table
|
|
57
|
+
# Handles the case where the to tables are associated by a case insensitive name string
|
|
61
58
|
Artist.one_to_many :albums, :key=>:artist_name, \
|
|
62
|
-
:graph_only_conditions=>
|
|
59
|
+
:graph_only_conditions=>nil, \
|
|
60
|
+
:graph_block=>proc{|j,lj,js| {:lower.sql_function(artist_name.qualify(j))=>:lower.sql_function(name.qualify(lj))}}
|
|
63
61
|
|
|
64
|
-
# Handles the
|
|
65
|
-
#
|
|
62
|
+
# Handles the case where both key columns have the name artist_name, and you want to use
|
|
63
|
+
# a JOIN USING
|
|
66
64
|
Artist.one_to_many :albums, :key=>:artist_name, :graph_only_conditions=>[:artist_name]
|
|
67
65
|
|
|
68
|
-
# Handles the case where all columns in both tables are uniquely named, except
|
|
69
|
-
# for the ones that handle associations
|
|
70
|
-
Artist.one_to_many :albums, :key=>:artist_name, :graph_only_conditions=>nil, \
|
|
71
|
-
:graph_join_type=>:natural
|
|
72
|
-
|
|
73
66
|
Remember, using #eager_graph is generally only necessary when you need to
|
|
74
67
|
filter/order based on columns in an associated table, it is recommended to
|
|
75
68
|
use #eager for eager loading if possible.
|
|
@@ -91,7 +84,7 @@ associations that are specified by multiple keys, or do multiple
|
|
|
91
84
|
queries depending on the content of the records (which would be
|
|
92
85
|
necessary for polymorphic associations). Inside the :eager_loader
|
|
93
86
|
proc, you should get the related objects and populate the
|
|
94
|
-
associations for all objects in the array of records. The hash
|
|
87
|
+
associations cache for all objects in the array of records. The hash
|
|
95
88
|
of dependent associations is available for you to cascade the eager
|
|
96
89
|
loading down multiple levels, but it is up to you to use it. The
|
|
97
90
|
key_hash is a performance enhancement that is used by the default
|
|
@@ -113,13 +106,13 @@ give an example:
|
|
|
113
106
|
Using these options, you can build associations Sequel doesn't natively support,
|
|
114
107
|
and still be able to use the same eager loading features that you are used to.
|
|
115
108
|
|
|
116
|
-
==ActiveRecord associations
|
|
109
|
+
== ActiveRecord associations
|
|
117
110
|
|
|
118
111
|
Sequel supports all of associations that ActiveRecord supports, one way or
|
|
119
112
|
another. Sometimes this requires more code, as Sequel is a toolkit and not
|
|
120
113
|
a swiss army chainsaw.
|
|
121
114
|
|
|
122
|
-
===Association callbacks
|
|
115
|
+
=== Association callbacks
|
|
123
116
|
|
|
124
117
|
Sequel supports the same callbacks that ActiveRecord does: :before_add,
|
|
125
118
|
:before_remove, :after_add, and :after_remove. It also supports a
|
|
@@ -142,9 +135,9 @@ remove callbacks on the existing object and the add callbacks on the
|
|
|
142
135
|
new object. The remove callback calls are placed around the add
|
|
143
136
|
callback calls.
|
|
144
137
|
|
|
145
|
-
===Association extensions
|
|
138
|
+
=== Association extensions
|
|
146
139
|
|
|
147
|
-
All associations come with
|
|
140
|
+
All associations come with an association_dataset method that can be further filtered or
|
|
148
141
|
otherwise modified:
|
|
149
142
|
|
|
150
143
|
class Author < Sequel::Model
|
|
@@ -159,8 +152,7 @@ association_reflection method:
|
|
|
159
152
|
|
|
160
153
|
module FindOrCreate
|
|
161
154
|
def find_or_create(vals)
|
|
162
|
-
first(vals) || association_reflection.
|
|
163
|
-
create(vals.merge(association_reflection[:key]=>model_object.id))
|
|
155
|
+
first(vals) || model.create(vals.merge(association_reflection[:key]=>model_object.id))
|
|
164
156
|
end
|
|
165
157
|
end
|
|
166
158
|
class Author < Sequel::Model
|
|
@@ -168,7 +160,7 @@ association_reflection method:
|
|
|
168
160
|
end
|
|
169
161
|
Author.first.authorships_dataset.find_or_create(:name=>'Blah', :number=>10)
|
|
170
162
|
|
|
171
|
-
===has_many :through associations
|
|
163
|
+
=== has_many :through associations
|
|
172
164
|
|
|
173
165
|
many_to_many handles the usual case of a has_many :through with a belongs_to in
|
|
174
166
|
the associated model. It doesn't break on the case where the join table is a
|
|
@@ -291,7 +283,7 @@ in the associations cache for each object, which ActiveRecord won't do for you.
|
|
|
291
283
|
The reason you would want to do this is that then firm.invoices.first.firm or
|
|
292
284
|
firm.invoices.first.client doesn't do another query to get the firm/client.
|
|
293
285
|
|
|
294
|
-
===Polymorphic Associations
|
|
286
|
+
=== Polymorphic Associations
|
|
295
287
|
|
|
296
288
|
Polymorphic associations are really a design flaw. The only advantage
|
|
297
289
|
polymorphic associations offer is that they require fewer join tables.
|
|
@@ -404,13 +396,13 @@ Sequel::Model:
|
|
|
404
396
|
@asset.attachable = @post
|
|
405
397
|
@asset.attachable = @note
|
|
406
398
|
|
|
407
|
-
==More advanced associations
|
|
399
|
+
== More advanced associations
|
|
408
400
|
|
|
409
401
|
So far, we've only shown that Sequel::Model has associations as powerful as
|
|
410
402
|
ActiveRecord's. Now we will show how Sequel::Model's associations are more
|
|
411
403
|
powerful.
|
|
412
404
|
|
|
413
|
-
===many_to_one/one_to_many not referencing primary key
|
|
405
|
+
=== many_to_one/one_to_many not referencing primary key
|
|
414
406
|
|
|
415
407
|
This can now be handled easily in Sequel using the :primary_key association
|
|
416
408
|
option. However, this example shows how the association was possible before
|
|
@@ -469,7 +461,7 @@ design, but sometimes you have to play with the cards you are dealt).
|
|
|
469
461
|
end
|
|
470
462
|
end
|
|
471
463
|
|
|
472
|
-
===Joining on multiple keys
|
|
464
|
+
=== Joining on multiple keys
|
|
473
465
|
|
|
474
466
|
Let's say you have two tables that are associated with each other with multiple
|
|
475
467
|
keys. For example:
|
|
@@ -511,7 +503,7 @@ keys. For example:
|
|
|
511
503
|
end)
|
|
512
504
|
end
|
|
513
505
|
|
|
514
|
-
===Tree - All Ancestors and Descendents
|
|
506
|
+
=== Tree - All Ancestors and Descendents
|
|
515
507
|
|
|
516
508
|
Let's say you want to store a tree relationship in your database, it's pretty
|
|
517
509
|
simple:
|
|
@@ -580,8 +572,7 @@ without knowing the depth of the tree?
|
|
|
580
572
|
end)
|
|
581
573
|
end
|
|
582
574
|
|
|
583
|
-
|
|
584
|
-
===Joining multiple keys to a single key, through a third table
|
|
575
|
+
=== Joining multiple keys to a single key, through a third table
|
|
585
576
|
|
|
586
577
|
Let's say you have a database, of songs, lyrics, and artists. Each song
|
|
587
578
|
may or may not have a lyric (most songs are instrumental). The lyric can be
|
data/doc/cheat_sheet.rdoc
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
DB = Sequel.sqlite('my_blog.db')
|
|
9
9
|
DB = Sequel.connect('postgres://user:password@localhost/my_db')
|
|
10
|
-
DB = Sequel.
|
|
10
|
+
DB = Sequel.postgres('my_db', :user => 'user', :password => 'password', :host => 'localhost')
|
|
11
11
|
DB = Sequel.ado('mydb')
|
|
12
12
|
|
|
13
13
|
== Open an SQLite memory database
|
|
14
14
|
|
|
15
|
-
Without a filename argument, the sqlite adapter will setup a new sqlite database in
|
|
15
|
+
Without a filename argument, the sqlite adapter will setup a new sqlite database in memory.
|
|
16
16
|
|
|
17
17
|
DB = Sequel.sqlite
|
|
18
18
|
|
|
@@ -26,56 +26,49 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
|
|
|
26
26
|
== Using raw SQL
|
|
27
27
|
|
|
28
28
|
DB << "CREATE TABLE users (name VARCHAR(255) NOT NULL, age INT(3) NOT NULL)"
|
|
29
|
+
dataset = DB["SELECT age FROM users WHERE name = ?", name]
|
|
30
|
+
dataset.map(:age)
|
|
29
31
|
DB.fetch("SELECT name FROM users") do |row|
|
|
30
32
|
p r[:name]
|
|
31
33
|
end
|
|
32
|
-
dataset = DB["SELECT age FROM users WHERE name = ?", name]
|
|
33
|
-
dataset.print
|
|
34
|
-
dataset.map(:age)
|
|
35
34
|
|
|
36
35
|
== Create a dataset
|
|
37
36
|
|
|
38
37
|
dataset = DB[:items]
|
|
39
|
-
dataset = DB.
|
|
38
|
+
dataset = DB.from(:items)
|
|
40
39
|
|
|
41
40
|
== Most dataset methods are chainable
|
|
42
41
|
|
|
43
42
|
dataset = DB[:managers].where(:salary => 5000..10000).order(:name, :department)
|
|
44
|
-
# or
|
|
45
|
-
dataset = DB.query do
|
|
46
|
-
from :managers
|
|
47
|
-
where :salary => 5000..10000
|
|
48
|
-
order :name, :department
|
|
49
|
-
end
|
|
50
43
|
|
|
51
44
|
== Insert rows
|
|
52
45
|
|
|
53
46
|
dataset.insert(:name => 'Sharon', :grade => 50)
|
|
54
|
-
dataset << {:name => 'Sharon', :grade => 50} # same effect as above
|
|
55
47
|
|
|
56
48
|
== Retrieve rows
|
|
57
49
|
|
|
58
|
-
dataset.each
|
|
50
|
+
dataset.each{|r| p r}
|
|
59
51
|
dataset.all #=> [{...}, {...}, ...]
|
|
60
52
|
dataset.first
|
|
61
|
-
dataset.order(:name).last # works only for ordered datasets
|
|
62
53
|
|
|
63
54
|
== Update/Delete rows
|
|
64
55
|
|
|
65
|
-
dataset.filter(
|
|
56
|
+
dataset.filter(~:active).delete
|
|
66
57
|
dataset.filter('price < ?', 100).update(:active => true)
|
|
67
58
|
|
|
68
59
|
== Datasets are Enumerable
|
|
69
60
|
|
|
70
|
-
dataset.map
|
|
71
|
-
dataset.map(:name) # same
|
|
61
|
+
dataset.map{|r| r[:name]}
|
|
62
|
+
dataset.map(:name) # same as above
|
|
72
63
|
|
|
73
64
|
dataset.inject(0){|sum, r| sum + r[:value]}
|
|
65
|
+
dataset.sum(:value) # same as above
|
|
74
66
|
|
|
75
67
|
== Filtering (see also doc/dataset_filtering.rdoc)
|
|
76
68
|
|
|
77
69
|
dataset.filter(:name => 'abc')
|
|
78
70
|
dataset.filter('name = ?', 'abc')
|
|
71
|
+
|
|
79
72
|
dataset.filter{|o| o.value > 100}
|
|
80
73
|
dataset.exclude{|o| o.value <= 100}
|
|
81
74
|
|
|
@@ -83,13 +76,13 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
|
|
|
83
76
|
dataset.where{|o| (o.value >= 50) & (o.value <= 100)}
|
|
84
77
|
|
|
85
78
|
dataset.where('value IN ?', [50,75,100])
|
|
79
|
+
dataset.where(:value=>[50,75,100])
|
|
86
80
|
|
|
87
|
-
# Get the first record that matches a condition
|
|
88
|
-
dataset[:name => 'abc'] # Same as:
|
|
89
81
|
dataset.filter(:name => 'abc').first
|
|
82
|
+
dataset[:name => 'abc'] # same as above
|
|
90
83
|
|
|
91
84
|
# Filter using a subquery
|
|
92
|
-
dataset.filter
|
|
85
|
+
dataset.filter{|o| o.price > dataset.select(o.avg(price) + 100)}
|
|
93
86
|
|
|
94
87
|
=== Advanced filtering using ruby expressions
|
|
95
88
|
|
|
@@ -112,8 +105,8 @@ You can use arithmetic operators and specify SQL functions:
|
|
|
112
105
|
DB[:items].filter((:x + :y) > :z).sql
|
|
113
106
|
#=> "SELECT * FROM items WHERE ((x + y) > z)"
|
|
114
107
|
|
|
115
|
-
DB[:items].filter{|o| :price - 100 < o.
|
|
116
|
-
#=> "SELECT * FROM items WHERE ((price - 100) <
|
|
108
|
+
DB[:items].filter{|o| :price - 100 < o.avg(:price)}.sql
|
|
109
|
+
#=> "SELECT * FROM items WHERE ((price - 100) < avg(price))"
|
|
117
110
|
|
|
118
111
|
== Ordering
|
|
119
112
|
|
|
@@ -126,16 +119,6 @@ You can use arithmetic operators and specify SQL functions:
|
|
|
126
119
|
dataset.limit(30) # LIMIT 30
|
|
127
120
|
dataset.limit(30, 10) # LIMIT 30 OFFSET 10
|
|
128
121
|
|
|
129
|
-
== Pagination
|
|
130
|
-
|
|
131
|
-
paginated = dataset.paginate(1, 10) # first page, 10 rows per page
|
|
132
|
-
paginated.page_count #=> number of pages in dataset
|
|
133
|
-
paginated.current_page #=> 1
|
|
134
|
-
paginated.next_page #=> next page number or nil
|
|
135
|
-
paginated.prev_page #=> previous page number or nil
|
|
136
|
-
paginated.first_page? #=> true if page number = 1
|
|
137
|
-
paginated.last_page? #=> true if page number = page_count
|
|
138
|
-
|
|
139
122
|
== Joins
|
|
140
123
|
|
|
141
124
|
DB[:items].left_outer_join(:categories, :id => :category_id).sql #=>
|
|
@@ -174,7 +157,7 @@ You can use arithmetic operators and specify SQL functions:
|
|
|
174
157
|
DB.drop_table :items
|
|
175
158
|
|
|
176
159
|
DB.create_table :test do
|
|
177
|
-
String :zipcode
|
|
160
|
+
String :zipcode
|
|
178
161
|
enum :system, :elements => ['mac', 'linux', 'windows']
|
|
179
162
|
end
|
|
180
163
|
|
|
@@ -188,8 +171,8 @@ You can use arithmetic operators and specify SQL functions:
|
|
|
188
171
|
== Transactions
|
|
189
172
|
|
|
190
173
|
DB.transaction do
|
|
191
|
-
dataset
|
|
192
|
-
dataset
|
|
174
|
+
dataset.insert(:first_name => 'Inigo', :last_name => 'Montoya')
|
|
175
|
+
dataset.insert(:first_name => 'Farm', :last_name => 'Boy')
|
|
193
176
|
end # Either both are inserted or neither are inserted
|
|
194
177
|
|
|
195
178
|
Database#transaction is re-entrant:
|
|
@@ -206,10 +189,10 @@ Transactions are aborted if an error is raised:
|
|
|
206
189
|
raise "some error occurred"
|
|
207
190
|
end # ROLLBACK issued and the error is re-raised
|
|
208
191
|
|
|
209
|
-
Transactions can also be aborted by raising Sequel::
|
|
192
|
+
Transactions can also be aborted by raising Sequel::Rollback:
|
|
210
193
|
|
|
211
194
|
DB.transaction do
|
|
212
|
-
raise(Sequel::
|
|
195
|
+
raise(Sequel::Rollback) if something_bad_happened
|
|
213
196
|
end # ROLLBACK issued and no error raised
|
|
214
197
|
|
|
215
198
|
Miscellaneous:
|
|
@@ -217,7 +200,7 @@ Miscellaneous:
|
|
|
217
200
|
dataset.sql #=> "SELECT * FROM items"
|
|
218
201
|
dataset.delete_sql #=> "DELETE FROM items"
|
|
219
202
|
dataset.where(:name => 'sequel').exists #=> "EXISTS ( SELECT 1 FROM items WHERE name = 'sequel' )"
|
|
220
|
-
dataset.print #=> pretty table print to $stdout
|
|
221
203
|
dataset.columns #=> array of columns in the result set, does a SELECT
|
|
204
|
+
|
|
205
|
+
# Works on PostgreSQL, MySQL, SQLite, and JDBC
|
|
222
206
|
DB.schema(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...]
|
|
223
|
-
# Works on PostgreSQL, MySQL, SQLite, and JDBC
|