sequel 2.11.0 → 2.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|