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/CHANGELOG
CHANGED
@@ -1,3 +1,171 @@
|
|
1
|
+
=== 2.12.0 (2009-04-03)
|
2
|
+
|
3
|
+
* Deprecate Java::JavaSQL::Timestamp#usec (jeremyevans)
|
4
|
+
|
5
|
+
* Fix Model.[] optimization introduced in 2.11.0 for databases that don't use LIMIT (jacaetevha)
|
6
|
+
|
7
|
+
* Don't use the model association plugin if SEQUEL_NO_ASSOCIATIONS constant or environment variable is defined (jeremyevans)
|
8
|
+
|
9
|
+
* Don't require core_sql if SEQUEL_NO_CORE_EXTENSIONS constant or environment variable is defined (jeremyevans)
|
10
|
+
|
11
|
+
* Add validation_helpers model plugin, which adds instance level validation support similar to previously standard validations, with a different API (jeremyevans)
|
12
|
+
|
13
|
+
* Split multi_insert into 2 methods with separate APIs, multi_insert for hashes, import for arrays of columns and values (jeremyevans)
|
14
|
+
|
15
|
+
* Deprecate Dataset#transform and Model.serialize, and model serialization plugin (jeremyevans)
|
16
|
+
|
17
|
+
* Add multi_insert_update to the MySQL adapter, used for setting specific update behavior when an error occurs when using multi_insert (dusty)
|
18
|
+
|
19
|
+
* Add multi_insert_ignore to the MySQL adapter, used for skipping errors on row inserts when using multi_insert (dusty)
|
20
|
+
|
21
|
+
* Add Sequel::MySQL.convert_invalid_date_time accessor for dealing with dates like "0000-00-00" and times like "25:00:00" (jeremyevans, epugh)
|
22
|
+
|
23
|
+
* Eliminate internal dependence on core_sql extensions (jeremyevans)
|
24
|
+
|
25
|
+
* Deprecate Migration and Migrator, require 'sequel/extensions/migration' if you want them (jeremyevans)
|
26
|
+
|
27
|
+
* Denamespace Sequel::Error decendants (e.g. use Sequel::Rollback instead of Sequel::Error::Rollback) (jeremyevans)
|
28
|
+
|
29
|
+
* Deprecate Error::InvalidTransform, Error::NoExistingFilter, and Error::InvalidStatement (jeremyevans)
|
30
|
+
|
31
|
+
* Deprecate Dataset#[] when called without an argument, and Dataset#map when called with an argument and a block (jeremyevans)
|
32
|
+
|
33
|
+
* Fix aliasing columns in the JDBC adapter (per.melin) (#263)
|
34
|
+
|
35
|
+
* Make Database#rename_table remove the cached schema entry for the table (jeremyevans)
|
36
|
+
|
37
|
+
* Make Database schema sql methods private (jeremyevans)
|
38
|
+
|
39
|
+
* Deprecate Database #multi_threaded? and #logger (jeremyevans)
|
40
|
+
|
41
|
+
* Make Dataset#where always affect the WHERE clause (jeremyevans)
|
42
|
+
|
43
|
+
* Deprecate Object#blank? and related extensions, require 'sequel/extensions/blank' to get them back (jeremyevans)
|
44
|
+
|
45
|
+
* Move lib/sequel_core into lib/sequel and lib/sequel_model into lib/sequel/model (jeremyevans)
|
46
|
+
|
47
|
+
* Remove Sequel::Schema::SQL module, move methods into Sequel::Database (jeremyevans)
|
48
|
+
|
49
|
+
* Support creating and dropping schema qualified views (jeremyevans)
|
50
|
+
|
51
|
+
* Fix saving a newly inserted record in an after_create or after_save hook (jeremyevans)
|
52
|
+
|
53
|
+
* Deprecate Dataset#print and PrettyTable, require 'sequel/extensions/pretty_table' if you want them (jeremyevans)
|
54
|
+
|
55
|
+
* Deprecate Database#query and Dataset#query, require 'sequel/extensions/query' if you want them (jeremyevans)
|
56
|
+
|
57
|
+
* Deprecate Dataset#paginate and #each_page, require 'sequel/extensions/pagination' if you want them (jeremyevans)
|
58
|
+
|
59
|
+
* Fix ~{:bool_col=>true} and related inversions of boolean values (jeremyevans)
|
60
|
+
|
61
|
+
* Add disable_insert_returning method to PostgreSQL datasets, so they fallback to just using INSERT (jeremyevans)
|
62
|
+
|
63
|
+
* Don't use savepoints by default on PostgreSQL, use the :savepoint option to Database#transaction to use a savepoint (jeremyevans)
|
64
|
+
|
65
|
+
* Deprecate Database#transaction accepting a server symbol argument, use an options hash with the :server option (jeremyevans)
|
66
|
+
|
67
|
+
* Add Model.use_transactions for setting whether models should use transactions when destroying/saving records (jeremyevans, mjwillson)
|
68
|
+
|
69
|
+
* Deprecate Model::Validation::Errors, use Model::Errors (jeremyevans)
|
70
|
+
|
71
|
+
* Deprecate string inflection methods, require 'sequel/extensions/inflector' if you use them (jeremyevans)
|
72
|
+
|
73
|
+
* Deprecate Model validation class methods, override Model#validate instead or Model.plugin validation_class_methods (jeremyevans)
|
74
|
+
|
75
|
+
* Deprecate Model schema methods, use Model.plugin :schema (jeremyevans)
|
76
|
+
|
77
|
+
* Deprecate Model hook class methods, use instance methods instead or Model.plugin :hook_class_methods (jeremyevans)
|
78
|
+
|
79
|
+
* Deprecate Model.set_sti_key, use Model.plugin :single_table_inheritance (jeremyevans)
|
80
|
+
|
81
|
+
* Deprecate Model.set_cache, use Model.plugin :caching (jeremyevans)
|
82
|
+
|
83
|
+
* Move most model instance methods into Model::InstanceMethods, for easier overriding of instance methods for all models (jeremyevans)
|
84
|
+
|
85
|
+
* Move most model class methods into Model::ClassMethods, for easier overriding of class methods for all models (jeremyevans)
|
86
|
+
|
87
|
+
* Deprecate String#to_date, #to_datetime, #to_time, and #to_sequel_time, use require 'sequel/extensions/string_date_time' if you want them (jeremyevans)
|
88
|
+
|
89
|
+
* Deprecate Array#extract_options! and Object#is_one_of? (jeremyevans)
|
90
|
+
|
91
|
+
* Deprecate Object#meta_def, #meta_eval, and #metaclass (jeremyevans)
|
92
|
+
|
93
|
+
* Deprecate Module#class_def, #class_attr_overridable, #class_attr_reader, #metaalias, #metaattr_reader, and #metaatt_accessor (jeremyevans)
|
94
|
+
|
95
|
+
* Speed up the calling of most column accessor methods, and reduce memory overhead of creating them (jeremyevans)
|
96
|
+
|
97
|
+
* Deprecate Model#set_restricted using Model#[] if no setter method exists, a symbol is used, and the columns are not set (jeremyevans)
|
98
|
+
|
99
|
+
* Deprecate Model#set_with_params and #update_with_params (jeremyevans)
|
100
|
+
|
101
|
+
* Deprecate Model#save!, use Model.save(:validate=>false) (jeremyevans)
|
102
|
+
|
103
|
+
* Deprecate Model#dataset (jeremyevans)
|
104
|
+
|
105
|
+
* Deprecate Model.is and Model.is_a, use Model.plugin for plugins (jeremyevans)
|
106
|
+
|
107
|
+
* Deprecate Model.str_columns, Model#str_columns, #set_values, #update_values (jeremyevans)
|
108
|
+
|
109
|
+
* Deprecate Model.delete_all, .destroy_all, .size, and .uniq (jeremyevans)
|
110
|
+
|
111
|
+
* Copy all current dataset options when calling Model.db= (jeremyevans)
|
112
|
+
|
113
|
+
* Deprecate Model.belongs_to, Model.has_many, and Model.has_and_belongs_to_many (jeremyevans)
|
114
|
+
|
115
|
+
* Remove SQL::SpecificExpression, have subclasses inherit from SQL::Expression instead (jeremyevans)
|
116
|
+
|
117
|
+
* Deprecate SQL::CastMethods#cast_as (jeremyevans)
|
118
|
+
|
119
|
+
* Deprecate calling Database#schema without a table argument (jeremyevans)
|
120
|
+
|
121
|
+
* Remove cached version of @db_schema in model instances to reduce memory and marshalling overhead (tmm1)
|
122
|
+
|
123
|
+
* Deprecate Dataset#quote_column_ref and Dataset#symbol_to_column_ref (jeremyevans)
|
124
|
+
|
125
|
+
* Deprecate Dataset#size and Dataset#uniq (jeremyevans)
|
126
|
+
|
127
|
+
* Deprecate passing options to Dataset#each, #all, #single_record, #single_value, #sql, #select_sql, #update, #update_sql, #delete, #delete_sql, and #exists (jeremyevans)
|
128
|
+
|
129
|
+
* Deprecate Dataset#[Integer] (jeremyevans)
|
130
|
+
|
131
|
+
* Deprecate Dataset#create_view and Dataset#create_or_replace_view (jeremyevans)
|
132
|
+
|
133
|
+
* Model datasets now have a model accessor that returns the related model (jeremyevans)
|
134
|
+
|
135
|
+
* Model datasets no longer have :models and :polymorphic_key options (jeremyevans)
|
136
|
+
|
137
|
+
* Deprecate Dataset.dataset_classes, Dataset#model_classes, Dataset#polymorphic_key, and Dataset#set_model (jeremyevans)
|
138
|
+
|
139
|
+
* Allow Database#get and Database#select to take a block (jeremyevans)
|
140
|
+
|
141
|
+
* Deprecate Database#>> (jeremyevans)
|
142
|
+
|
143
|
+
* Deprecate String#to_blob and Sequel::SQL::Blob#to_blob (jeremyevans)
|
144
|
+
|
145
|
+
* Deprecate use of Symbol#| for SQL array subscripts, add Symbol#sql_subscript (jeremyevans)
|
146
|
+
|
147
|
+
* Deprecate Symbol#to_column_ref (jeremyevans)
|
148
|
+
|
149
|
+
* Deprecate String#expr (jeremyevans)
|
150
|
+
|
151
|
+
* Deprecate Array#to_sql, String#to_sql, and String#split_sql (jeremyevans)
|
152
|
+
|
153
|
+
* Deprecate passing an array to Database#<< (jeremyevans)
|
154
|
+
|
155
|
+
* Deprecate Range#interval (jeremyevans)
|
156
|
+
|
157
|
+
* Deprecate Enumerable#send_each (jeremyevans)
|
158
|
+
|
159
|
+
* Deprecate Hash#key on ruby 1.8, change some SQLite adapter constants (jeremyevans)
|
160
|
+
|
161
|
+
* Deprecate Sequel.open, Sequel.use_parse_tree=?, and the upcase_identifier methods (jeremyevans)
|
162
|
+
|
163
|
+
* Deprecate virtual row blocks without block arguments, unless Sequel.virtual_row_instance_eval is enabled (jeremyevans)
|
164
|
+
|
165
|
+
* Support schema parsing in the Oracle adapter (jacaetevha)
|
166
|
+
|
167
|
+
* Allow virtual row blocks to be instance_evaled, add Sequel.virtual_row_instance_eval= (jeremyevans)
|
168
|
+
|
1
169
|
=== 2.11.0 (2009-03-02)
|
2
170
|
|
3
171
|
* Optimize Model.[] by using static sql when possible, for a 30-40% speed increase (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -42,31 +42,28 @@ If you have any comments or suggestions please post to the Google group.
|
|
42
42
|
|
43
43
|
DB = Sequel.sqlite # memory database
|
44
44
|
|
45
|
-
DB.create_table :items do
|
45
|
+
DB.create_table :items do
|
46
46
|
primary_key :id
|
47
|
-
|
48
|
-
|
47
|
+
String name
|
48
|
+
Float price
|
49
49
|
end
|
50
50
|
|
51
51
|
items = DB[:items] # Create a dataset
|
52
52
|
|
53
53
|
# Populate the table
|
54
|
-
items
|
55
|
-
items
|
56
|
-
items
|
54
|
+
items.insert(:name => 'abc', :price => rand * 100)
|
55
|
+
items.insert(name => 'def', :price => rand * 100)
|
56
|
+
items.insert(:name => 'ghi', :price => rand * 100)
|
57
57
|
|
58
58
|
# Print out the number of records
|
59
59
|
puts "Item count: #{items.count}"
|
60
60
|
|
61
|
-
# Print out the records in descending order by price
|
62
|
-
items.reverse_order(:price).print
|
63
|
-
|
64
61
|
# Print out the average price
|
65
62
|
puts "The average price is: #{items.avg(:price)}"
|
66
63
|
|
67
64
|
== The Sequel Console
|
68
65
|
|
69
|
-
Sequel includes an IRB console for quick
|
66
|
+
Sequel includes an IRB console for quick access to databases. You can use it like this:
|
70
67
|
|
71
68
|
sequel sqlite://test.db # test.db in current directory
|
72
69
|
|
@@ -86,7 +83,7 @@ Which is equivalent to:
|
|
86
83
|
|
87
84
|
SELECT avg(GDP) FROM countries WHERE region = 'Middle East' ORDER BY area DESC LIMIT 5
|
88
85
|
|
89
|
-
Since datasets retrieve records only when needed, they can be stored and later reused. Records are fetched as hashes (
|
86
|
+
Since datasets retrieve records only when needed, they can be stored and later reused. Records are fetched as hashes (or custom model objects), and are accessed using an Enumerable interface:
|
90
87
|
|
91
88
|
middle_east = DB[:countries].filter(:region => 'Middle East')
|
92
89
|
middle_east.order(:name).each{|r| puts r[:name]}
|
@@ -123,17 +120,12 @@ You can specify a block to connect, which will disconnect from the database afte
|
|
123
120
|
|
124
121
|
=== Arbitrary SQL queries
|
125
122
|
|
126
|
-
DB.execute_ddl("create table t (a text, b text)")
|
127
|
-
DB.execute_insert("insert into t values ('a', 'b')")
|
128
|
-
|
129
|
-
Or more succinctly:
|
130
|
-
|
131
123
|
DB << "create table t (a text, b text)"
|
132
124
|
DB << "insert into t values ('a', 'b')"
|
133
125
|
|
134
126
|
You can also create datasets based on raw SQL:
|
135
127
|
|
136
|
-
dataset = DB['select
|
128
|
+
dataset = DB['select id from items']
|
137
129
|
dataset.count # will return the number of records in the result set
|
138
130
|
dataset.map(:id) # will return an array containing all values of the id column in the result set
|
139
131
|
|
@@ -151,23 +143,16 @@ You can use placeholders in your SQL string as well:
|
|
151
143
|
|
152
144
|
=== Getting Dataset Instances
|
153
145
|
|
154
|
-
|
155
|
-
|
156
|
-
dataset = DB.dataset
|
157
|
-
|
158
|
-
Or by using the from methods:
|
146
|
+
Datasets are the primary way records are retrieved and manipulated. They are generally created via the Database#from or Database#[] methods:
|
159
147
|
|
160
148
|
posts = DB.from(:posts)
|
149
|
+
posts = DB[:posts] # same
|
161
150
|
|
162
|
-
|
163
|
-
|
164
|
-
posts = DB[:posts]
|
165
|
-
|
166
|
-
Datasets will only fetch records when you explicitly ask for them. Datasets can be manipulated to filter through records, change record order, join tables, etc..
|
151
|
+
Datasets will only fetch records when you tell them to. They can be manipulated to filter records, change ordering, join tables, etc..
|
167
152
|
|
168
153
|
=== Retrieving Records
|
169
154
|
|
170
|
-
You can retrieve records by using the all method:
|
155
|
+
You can retrieve all records by using the all method:
|
171
156
|
|
172
157
|
posts.all
|
173
158
|
|
@@ -179,8 +164,8 @@ You can also iterate through records one at a time:
|
|
179
164
|
|
180
165
|
Or perform more advanced stuff:
|
181
166
|
|
182
|
-
posts.map
|
183
|
-
posts.
|
167
|
+
names_and_dates = posts.map{|r| [r[:name], r[:date]]}
|
168
|
+
old_posts, recent_posts = posts.partition{|r| r[:date] < Date.today - 7}
|
184
169
|
|
185
170
|
You can also retrieve the first record in a dataset:
|
186
171
|
|
@@ -196,7 +181,7 @@ If the dataset is ordered, you can also ask for the last record:
|
|
196
181
|
|
197
182
|
=== Filtering Records
|
198
183
|
|
199
|
-
|
184
|
+
An easy way to filter records is to provide a hash of values to match:
|
200
185
|
|
201
186
|
my_posts = posts.filter(:category => 'ruby', :author => 'david')
|
202
187
|
|
@@ -212,27 +197,26 @@ Sequel also accepts expressions:
|
|
212
197
|
|
213
198
|
my_posts = posts.filter{|o| o.stamp > Date.today << 1}
|
214
199
|
|
215
|
-
Some adapters
|
200
|
+
Some adapters will also let you specify Regexps:
|
216
201
|
|
217
202
|
my_posts = posts.filter(:category => /ruby/i)
|
218
203
|
|
219
204
|
You can also use an inverse filter:
|
220
205
|
|
221
206
|
my_posts = posts.exclude(:category => /ruby/i)
|
222
|
-
my_posts = posts.filter(:category => /ruby/i).invert # same as above
|
223
207
|
|
224
208
|
You can also specify a custom WHERE clause using a string:
|
225
209
|
|
226
210
|
posts.filter('stamp IS NOT NULL')
|
227
211
|
|
228
|
-
You can use parameters in your string, as well
|
212
|
+
You can use parameters in your string, as well:
|
229
213
|
|
230
214
|
posts.filter('(stamp < ?) AND (author != ?)', Date.today - 3, author_name)
|
231
215
|
posts.filter{|o| (o.stamp < Date.today - 3) & ~{:author => author_name}} # same as above
|
232
216
|
|
233
217
|
Datasets can also be used as subqueries:
|
234
218
|
|
235
|
-
DB[:items].filter('price > ?', DB[:items].select(
|
219
|
+
DB[:items].filter('price > ?', DB[:items].select{|o| o.avg(:price) + 100})
|
236
220
|
|
237
221
|
After filtering you can retrieve the matching records by using any of the retrieval methods:
|
238
222
|
|
@@ -246,10 +230,12 @@ Counting records is easy:
|
|
246
230
|
posts.filter(:category => /ruby/i).count
|
247
231
|
|
248
232
|
And you can also query maximum/minimum values:
|
249
|
-
|
233
|
+
max = DB[:history].max(:value)
|
234
|
+
min = DB[:history].min(:value)
|
250
235
|
|
251
|
-
Or calculate a sum:
|
252
|
-
|
236
|
+
Or calculate a sum or average:
|
237
|
+
sum = DB[:items].sum(:price)
|
238
|
+
avg = DB[:items].avg(:price)
|
253
239
|
|
254
240
|
=== Ordering Records
|
255
241
|
|
@@ -266,7 +252,7 @@ The order_more method chains this way, though:
|
|
266
252
|
|
267
253
|
posts.order(:stamp).order_more(:name) # ORDER BY stamp, name
|
268
254
|
|
269
|
-
You can also specify descending order
|
255
|
+
You can also specify descending order:
|
270
256
|
|
271
257
|
posts.order(:stamp.desc) # ORDER BY stamp DESC
|
272
258
|
|
@@ -291,12 +277,14 @@ Deleting records from the table is done with delete:
|
|
291
277
|
|
292
278
|
posts.filter('stamp < ?', Date.today - 3).delete
|
293
279
|
|
280
|
+
Be very careful when deleting, as delete affects all rows in the dataset.
|
281
|
+
Filter first, delete second, unless you want to empty the table.
|
282
|
+
|
294
283
|
=== Inserting Records
|
295
284
|
|
296
285
|
Inserting records into the table is done with insert:
|
297
286
|
|
298
287
|
posts.insert(:category => 'ruby', :author => 'david')
|
299
|
-
posts << {:category => 'ruby', :author => 'david'} # same as above
|
300
288
|
|
301
289
|
=== Updating Records
|
302
290
|
|
@@ -304,9 +292,16 @@ Updating records in the table is done with update:
|
|
304
292
|
|
305
293
|
posts.filter('stamp < ?', Date.today - 7).update(:state => 'archived')
|
306
294
|
|
295
|
+
You can reference table columns when choosing what values to set:
|
296
|
+
|
297
|
+
posts.filter{|o| o.stamp < Date.today - 7}.update(:backup_number => :backup_number + 1)
|
298
|
+
|
299
|
+
As with delete, this affects all rows in the dataset, so filter first,
|
300
|
+
update second, unless you want to update all rows.
|
301
|
+
|
307
302
|
=== Joining Tables
|
308
303
|
|
309
|
-
|
304
|
+
Sequel makes it easy to join tables:
|
310
305
|
|
311
306
|
order_items = DB[:items].join(:order_items, :item_id => :id).
|
312
307
|
filter(:order_items__order_id => 1234)
|
@@ -332,7 +327,7 @@ Which is equivalent to the SQL:
|
|
332
327
|
When retrieving records from joined datasets, you get the results in a single hash, which is subject to clobbering if you have columns with the same name in multiple tables:
|
333
328
|
|
334
329
|
DB[:items].join(:order_items, :item_id => :id).first
|
335
|
-
=> {:id=>
|
330
|
+
=> {:id=>order_items.id), :item_id=>order_items.item_id}
|
336
331
|
|
337
332
|
Using graph, you can split the result hashes into subhashes, one per join:
|
338
333
|
|
@@ -346,6 +341,10 @@ Sequel expects column names to be specified using symbols. In addition, returned
|
|
346
341
|
items.filter(:x => 1) #=> "SELECT * FROM items WHERE (x = 1)"
|
347
342
|
items.filter(1 => :x) #=> "SELECT * FROM items WHERE (1 = x)"
|
348
343
|
|
344
|
+
Ruby strings are generally treated as SQL strings:
|
345
|
+
|
346
|
+
items.filter(:x => 'x') #=> "SELECT * FROM items WHERE (x = 'x')"
|
347
|
+
|
349
348
|
=== Qualifying column names
|
350
349
|
|
351
350
|
Column references can be qualified by using the double underscore special notation :table__column:
|
@@ -359,13 +358,13 @@ You can also alias columns by using the triple undersecore special notation :col
|
|
359
358
|
items.literal(:price___p) #=> "price AS p"
|
360
359
|
items.literal(:items__price___p) #=> "items.price AS p"
|
361
360
|
|
362
|
-
Another way to alias columns is to use the #
|
361
|
+
Another way to alias columns is to use the #as method:
|
363
362
|
|
364
363
|
items.literal(:price.as(:p)) #=> "price AS p"
|
365
364
|
|
366
365
|
== Sequel Models
|
367
366
|
|
368
|
-
|
367
|
+
A model class wraps a dataset, and an instance of that class wraps a single record in the dataset.
|
369
368
|
|
370
369
|
Model classes are defined as regular Ruby classes:
|
371
370
|
|
@@ -383,12 +382,15 @@ You can, however, explicitly set the table name or even the dataset used:
|
|
383
382
|
end
|
384
383
|
# or:
|
385
384
|
Post.set_dataset :my_posts
|
386
|
-
|
387
|
-
|
385
|
+
|
386
|
+
If you use a symbol, it assumes you are referring to the table with the same name. You can also give it a dataset:
|
387
|
+
|
388
|
+
Post.set_dataset DB[:my_posts].filter(:category => 'ruby')
|
389
|
+
Post.set_dataset DB[:my_posts].select(:id, :name).order(:date)
|
388
390
|
|
389
391
|
=== Model instances
|
390
392
|
|
391
|
-
Model instance are identified by a primary key. By default, Sequel assumes the primary key column to be :id. The Model
|
393
|
+
Model instance are identified by a primary key. By default, Sequel assumes the primary key column to be :id, unless it can get the primary key information from the database. The Model.[] method can be used to fetch records by their primary key:
|
392
394
|
|
393
395
|
post = Post[123]
|
394
396
|
|
@@ -466,23 +468,23 @@ You can also supply a block to Model.new and Model.create:
|
|
466
468
|
|
467
469
|
=== Hooks
|
468
470
|
|
469
|
-
You can execute custom code when creating, updating, or deleting records by
|
470
|
-
|
471
|
-
Hooks are defined by supplying a block:
|
471
|
+
You can execute custom code when creating, updating, or deleting records by defining hook methods. The before_create and after_create hook methods wrap record creation. The before_update and after_update hook methods wrap record updating. The before_save and after_save hook methods wrap record creation and updating. The before_destroy and after_destroy hook methods wrap destruction. The before_validation and after_validation hook methods wrap validation. Example:
|
472
472
|
|
473
473
|
class Post < Sequel::Model
|
474
|
-
after_create
|
474
|
+
def after_create
|
475
475
|
author.increase_post_count
|
476
476
|
end
|
477
477
|
|
478
|
-
after_destroy
|
478
|
+
def after_destroy
|
479
479
|
author.decrease_post_count
|
480
480
|
end
|
481
481
|
end
|
482
482
|
|
483
|
+
For the example above, you should probably use a database trigger if you can. Hooks can be used for data integrity, but they will only enforce that integrity when you are using the model. If you plan on allowing any other access to the database, it's best to use database triggers for data integrity.
|
484
|
+
|
483
485
|
=== Deleting records
|
484
486
|
|
485
|
-
You can delete individual records by calling #delete or #destroy. The only difference between the two methods is that #destroy invokes before_destroy and after_destroy
|
487
|
+
You can delete individual records by calling #delete or #destroy. The only difference between the two methods is that #destroy invokes before_destroy and after_destroy hook methods, while #delete does not:
|
486
488
|
|
487
489
|
post.delete #=> bypasses hooks
|
488
490
|
post.destroy #=> runs hooks
|
@@ -534,6 +536,14 @@ one_to_many and many_to_many create a getter method, a method for adding an obje
|
|
534
536
|
post.remove_tag(tag)
|
535
537
|
post.remove_all_tags
|
536
538
|
|
539
|
+
All associations add a dataset method that can be used to further filter or reorder the returned objects, or modify all of them:
|
540
|
+
|
541
|
+
# Delete all of this post's comments from the database
|
542
|
+
Post.comments_dataset.destroy
|
543
|
+
|
544
|
+
# Return all tags related to this post with no subscribers, ordered by the tag's name
|
545
|
+
Post.tags_dataset.filter(:subscribers=>0).order(:name).all
|
546
|
+
|
537
547
|
=== Eager Loading
|
538
548
|
|
539
549
|
Associations can be eagerly loaded via .eager and the :eager association option. Eager loading is used when loading a group of objects. It loads all associated objects for all of the current objects in one query, instead of using a separate query to get the associated objects for each current object. Eager loading requires that you retrieve all model objects at once via .all (instead of individually by .each). Eager loading can be cascaded, loading association's associated objects.
|
@@ -585,21 +595,7 @@ Associations can be eagerly loaded via .eager and the :eager association option.
|
|
585
595
|
# replies that have that tag. Uses a total of 8 queries.
|
586
596
|
Person.eager(:posts=>{:replies=>[:person, {:tags=>{:posts, :replies}}]}).all
|
587
597
|
|
588
|
-
In addition to using eager, you can also use eager_graph, which will use a single query to get the object and all associated objects. This may be necessary if you want to filter the result set based on columns in associated tables. It works with cascading as well, the syntax is exactly the same. Note that using eager_graph to eagerly load multiple *_to_many associations will cause the result set to be a cartesian product, so you should be very careful with your filters when using it in that case.
|
589
|
-
|
590
|
-
=== Caching model instances with memcached
|
591
|
-
|
592
|
-
Sequel models can be cached using memcached based on their primary keys. The use of memcached can significantly reduce database load by keeping model instances in memory. The set_cache method is used to specify caching:
|
593
|
-
|
594
|
-
require 'memcache'
|
595
|
-
CACHE = MemCache.new 'localhost:11211', :namespace => 'blog'
|
596
|
-
|
597
|
-
class Author < Sequel::Model
|
598
|
-
set_cache CACHE, :ttl => 3600
|
599
|
-
end
|
600
|
-
|
601
|
-
Author[333] # database hit
|
602
|
-
Author[333] # cache hit
|
598
|
+
In addition to using eager, you can also use eager_graph, which will use a single query to get the object and all associated objects. This may be necessary if you want to filter or order the result set based on columns in associated tables. It works with cascading as well, the syntax is exactly the same. Note that using eager_graph to eagerly load multiple *_to_many associations will cause the result set to be a cartesian product, so you should be very careful with your filters when using it in that case.
|
603
599
|
|
604
600
|
=== Extending the underlying dataset
|
605
601
|
|
@@ -638,33 +634,19 @@ Sequel models also provide a short hand notation for filters:
|
|
638
634
|
subset :invisible, ~:visible
|
639
635
|
end
|
640
636
|
|
641
|
-
===
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
numericality_of...
|
655
|
-
each...
|
637
|
+
=== Model Validations
|
638
|
+
|
639
|
+
You can define a validate method for your model, which save
|
640
|
+
will check before attempting to save the model in the database.
|
641
|
+
If an attribute of the model isn't valid, you should add a error
|
642
|
+
message for that attribute to the model object's errors. If an
|
643
|
+
object has any errors added by the validate method, save will
|
644
|
+
raise an error or return false depending on how it is configured.
|
645
|
+
|
646
|
+
class Post < Sequel::Model
|
647
|
+
def validate
|
648
|
+
errors[:name] << "can't be empty" if name.empty?
|
649
|
+
errors[:written_on] << "should be in the past" if written_on >= Time.now
|
656
650
|
end
|
657
651
|
end
|
658
652
|
|
659
|
-
You may also perform the usual 'longhand' way to assign default model validates directly within the model class itself:
|
660
|
-
|
661
|
-
class MyModel < Sequel::Model
|
662
|
-
validates_format_of...
|
663
|
-
validates_presence_of...
|
664
|
-
validates_acceptance_of...
|
665
|
-
validates_confirmation_of...
|
666
|
-
validates_length_of...
|
667
|
-
validates_numericality_of...
|
668
|
-
validates_format_of...
|
669
|
-
validates_each...
|
670
|
-
end
|