sequel 2.11.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. data/CHANGELOG +168 -0
  2. data/README.rdoc +77 -95
  3. data/Rakefile +100 -80
  4. data/bin/sequel +2 -1
  5. data/doc/advanced_associations.rdoc +23 -32
  6. data/doc/cheat_sheet.rdoc +23 -40
  7. data/doc/dataset_filtering.rdoc +6 -6
  8. data/doc/prepared_statements.rdoc +22 -22
  9. data/doc/release_notes/2.12.0.txt +534 -0
  10. data/doc/schema.rdoc +3 -1
  11. data/doc/sharding.rdoc +8 -8
  12. data/doc/virtual_rows.rdoc +65 -0
  13. data/lib/sequel.rb +1 -1
  14. data/lib/{sequel_core → sequel}/adapters/ado.rb +3 -3
  15. data/lib/{sequel_core → sequel}/adapters/db2.rb +0 -0
  16. data/lib/{sequel_core → sequel}/adapters/dbi.rb +1 -1
  17. data/lib/{sequel_core → sequel}/adapters/do.rb +9 -5
  18. data/lib/{sequel_core → sequel}/adapters/do/mysql.rb +1 -1
  19. data/lib/{sequel_core → sequel}/adapters/do/postgres.rb +1 -1
  20. data/lib/{sequel_core → sequel}/adapters/do/sqlite.rb +1 -1
  21. data/lib/{sequel_core → sequel}/adapters/firebird.rb +84 -80
  22. data/lib/{sequel_core → sequel}/adapters/informix.rb +1 -1
  23. data/lib/{sequel_core → sequel}/adapters/jdbc.rb +21 -14
  24. data/lib/{sequel_core → sequel}/adapters/jdbc/h2.rb +14 -13
  25. data/lib/{sequel_core → sequel}/adapters/jdbc/mysql.rb +1 -1
  26. data/lib/{sequel_core → sequel}/adapters/jdbc/oracle.rb +1 -1
  27. data/lib/{sequel_core → sequel}/adapters/jdbc/postgresql.rb +1 -1
  28. data/lib/{sequel_core → sequel}/adapters/jdbc/sqlite.rb +1 -1
  29. data/lib/{sequel_core → sequel}/adapters/mysql.rb +60 -39
  30. data/lib/{sequel_core → sequel}/adapters/odbc.rb +8 -4
  31. data/lib/{sequel_core → sequel}/adapters/openbase.rb +0 -0
  32. data/lib/{sequel_core → sequel}/adapters/oracle.rb +38 -7
  33. data/lib/{sequel_core → sequel}/adapters/postgres.rb +24 -24
  34. data/lib/{sequel_core → sequel}/adapters/shared/mssql.rb +5 -5
  35. data/lib/{sequel_core → sequel}/adapters/shared/mysql.rb +126 -71
  36. data/lib/{sequel_core → sequel}/adapters/shared/oracle.rb +7 -10
  37. data/lib/{sequel_core → sequel}/adapters/shared/postgres.rb +159 -125
  38. data/lib/{sequel_core → sequel}/adapters/shared/progress.rb +1 -2
  39. data/lib/{sequel_core → sequel}/adapters/shared/sqlite.rb +72 -67
  40. data/lib/{sequel_core → sequel}/adapters/sqlite.rb +11 -7
  41. data/lib/{sequel_core → sequel}/adapters/utils/date_format.rb +0 -0
  42. data/lib/{sequel_core → sequel}/adapters/utils/stored_procedures.rb +0 -0
  43. data/lib/{sequel_core → sequel}/adapters/utils/unsupported.rb +19 -0
  44. data/lib/{sequel_core → sequel}/connection_pool.rb +7 -5
  45. data/lib/sequel/core.rb +221 -0
  46. data/lib/{sequel_core → sequel}/core_sql.rb +91 -49
  47. data/lib/{sequel_core → sequel}/database.rb +264 -149
  48. data/lib/{sequel_core/schema/generator.rb → sequel/database/schema_generator.rb} +6 -2
  49. data/lib/{sequel_core/database/schema.rb → sequel/database/schema_methods.rb} +12 -12
  50. data/lib/sequel/database/schema_sql.rb +224 -0
  51. data/lib/{sequel_core → sequel}/dataset.rb +78 -236
  52. data/lib/{sequel_core → sequel}/dataset/convenience.rb +99 -61
  53. data/lib/{sequel_core/object_graph.rb → sequel/dataset/graph.rb} +16 -14
  54. data/lib/{sequel_core → sequel}/dataset/prepared_statements.rb +1 -1
  55. data/lib/{sequel_core → sequel}/dataset/sql.rb +150 -99
  56. data/lib/sequel/deprecated.rb +593 -0
  57. data/lib/sequel/deprecated_migration.rb +91 -0
  58. data/lib/sequel/exceptions.rb +48 -0
  59. data/lib/sequel/extensions/blank.rb +42 -0
  60. data/lib/{sequel_model → sequel/extensions}/inflector.rb +8 -1
  61. data/lib/{sequel_core → sequel/extensions}/migration.rb +1 -1
  62. data/lib/{sequel_core/dataset → sequel/extensions}/pagination.rb +0 -0
  63. data/lib/{sequel_core → sequel/extensions}/pretty_table.rb +7 -0
  64. data/lib/{sequel_core/dataset → sequel/extensions}/query.rb +7 -0
  65. data/lib/sequel/extensions/string_date_time.rb +47 -0
  66. data/lib/sequel/metaprogramming.rb +43 -0
  67. data/lib/sequel/model.rb +110 -0
  68. data/lib/sequel/model/associations.rb +1300 -0
  69. data/lib/sequel/model/base.rb +937 -0
  70. data/lib/sequel/model/deprecated.rb +204 -0
  71. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  72. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  73. data/lib/sequel/model/deprecated_validations.rb +388 -0
  74. data/lib/sequel/model/errors.rb +39 -0
  75. data/lib/{sequel_model → sequel/model}/exceptions.rb +4 -4
  76. data/lib/sequel/model/inflections.rb +208 -0
  77. data/lib/sequel/model/plugins.rb +76 -0
  78. data/lib/sequel/plugins/caching.rb +122 -0
  79. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  80. data/lib/sequel/plugins/schema.rb +53 -0
  81. data/lib/sequel/plugins/serialization.rb +117 -0
  82. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  83. data/lib/sequel/plugins/validation_class_methods.rb +384 -0
  84. data/lib/sequel/plugins/validation_helpers.rb +150 -0
  85. data/lib/{sequel_core → sequel}/sql.rb +125 -190
  86. data/lib/{sequel_core → sequel}/version.rb +2 -1
  87. data/lib/sequel_core.rb +1 -172
  88. data/lib/sequel_model.rb +1 -91
  89. data/spec/adapters/firebird_spec.rb +5 -5
  90. data/spec/adapters/informix_spec.rb +1 -1
  91. data/spec/adapters/mysql_spec.rb +128 -42
  92. data/spec/adapters/oracle_spec.rb +47 -19
  93. data/spec/adapters/postgres_spec.rb +64 -52
  94. data/spec/adapters/spec_helper.rb +1 -1
  95. data/spec/adapters/sqlite_spec.rb +12 -17
  96. data/spec/{sequel_core → core}/connection_pool_spec.rb +10 -10
  97. data/spec/{sequel_core → core}/core_ext_spec.rb +19 -19
  98. data/spec/{sequel_core → core}/core_sql_spec.rb +68 -71
  99. data/spec/{sequel_core → core}/database_spec.rb +135 -99
  100. data/spec/{sequel_core → core}/dataset_spec.rb +398 -242
  101. data/spec/{sequel_core → core}/expression_filters_spec.rb +13 -13
  102. data/spec/core/migration_spec.rb +263 -0
  103. data/spec/{sequel_core → core}/object_graph_spec.rb +10 -10
  104. data/spec/{sequel_core → core}/pretty_table_spec.rb +2 -2
  105. data/spec/{sequel_core → core}/schema_generator_spec.rb +0 -0
  106. data/spec/{sequel_core → core}/schema_spec.rb +8 -10
  107. data/spec/{sequel_core → core}/spec_helper.rb +29 -2
  108. data/spec/{sequel_core → core}/version_spec.rb +0 -0
  109. data/spec/extensions/blank_spec.rb +67 -0
  110. data/spec/extensions/caching_spec.rb +201 -0
  111. data/spec/{sequel_model/hooks_spec.rb → extensions/hook_class_methods_spec.rb} +8 -23
  112. data/spec/{sequel_model → extensions}/inflector_spec.rb +3 -0
  113. data/spec/{sequel_core → extensions}/migration_spec.rb +4 -4
  114. data/spec/extensions/pagination_spec.rb +99 -0
  115. data/spec/extensions/pretty_table_spec.rb +91 -0
  116. data/spec/extensions/query_spec.rb +85 -0
  117. data/spec/{sequel_model → extensions}/schema_spec.rb +22 -1
  118. data/spec/extensions/serialization_spec.rb +109 -0
  119. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  120. data/spec/{sequel_model → extensions}/spec_helper.rb +13 -4
  121. data/spec/extensions/string_date_time_spec.rb +93 -0
  122. data/spec/{sequel_model/validations_spec.rb → extensions/validation_class_methods_spec.rb} +15 -103
  123. data/spec/extensions/validation_helpers_spec.rb +291 -0
  124. data/spec/integration/dataset_test.rb +31 -0
  125. data/spec/integration/eager_loader_test.rb +17 -30
  126. data/spec/integration/schema_test.rb +8 -5
  127. data/spec/integration/spec_helper.rb +17 -0
  128. data/spec/integration/transaction_test.rb +68 -0
  129. data/spec/{sequel_model → model}/association_reflection_spec.rb +0 -0
  130. data/spec/{sequel_model → model}/associations_spec.rb +23 -10
  131. data/spec/{sequel_model → model}/base_spec.rb +29 -20
  132. data/spec/{sequel_model → model}/caching_spec.rb +16 -14
  133. data/spec/{sequel_model → model}/dataset_methods_spec.rb +0 -0
  134. data/spec/{sequel_model → model}/eager_loading_spec.rb +8 -8
  135. data/spec/model/hooks_spec.rb +472 -0
  136. data/spec/model/inflector_spec.rb +126 -0
  137. data/spec/{sequel_model → model}/model_spec.rb +25 -20
  138. data/spec/model/plugins_spec.rb +142 -0
  139. data/spec/{sequel_model → model}/record_spec.rb +121 -62
  140. data/spec/model/schema_spec.rb +92 -0
  141. data/spec/model/spec_helper.rb +124 -0
  142. data/spec/model/validations_spec.rb +1080 -0
  143. metadata +136 -107
  144. data/lib/sequel_core/core_ext.rb +0 -217
  145. data/lib/sequel_core/dataset/callback.rb +0 -13
  146. data/lib/sequel_core/dataset/schema.rb +0 -15
  147. data/lib/sequel_core/deprecated.rb +0 -26
  148. data/lib/sequel_core/exceptions.rb +0 -44
  149. data/lib/sequel_core/schema.rb +0 -2
  150. data/lib/sequel_core/schema/sql.rb +0 -325
  151. data/lib/sequel_model/association_reflection.rb +0 -267
  152. data/lib/sequel_model/associations.rb +0 -499
  153. data/lib/sequel_model/base.rb +0 -539
  154. data/lib/sequel_model/caching.rb +0 -82
  155. data/lib/sequel_model/dataset_methods.rb +0 -26
  156. data/lib/sequel_model/eager_loading.rb +0 -370
  157. data/lib/sequel_model/hooks.rb +0 -101
  158. data/lib/sequel_model/plugins.rb +0 -62
  159. data/lib/sequel_model/record.rb +0 -568
  160. data/lib/sequel_model/schema.rb +0 -49
  161. data/lib/sequel_model/validations.rb +0 -429
  162. 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 # Create a new table
45
+ DB.create_table :items do
46
46
  primary_key :id
47
- column :name, :text
48
- column :price, :float
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 << {:name => 'abc', :price => rand * 100}
55
- items << {:name => 'def', :price => rand * 100}
56
- items << {:name => 'ghi', :price => rand * 100}
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'n'dirty access to databases. You can use it like this:
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 (they can also be fetched as custom model objects), and are accessed using an Enumerable interface:
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 * from items']
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
- Dataset is the primary means through which records are retrieved and manipulated. You can create an blank dataset by using the dataset method:
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
- The recommended way is the equivalent shorthand:
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(:id)
183
- posts.inject({}){|h, r| h[r[:id]] = r[:name]}
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
- The simplest way to filter records is to provide a hash of values to match:
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 (like postgresql) will also let you specify Regexps:
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 (ActiveRecord style):
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('AVG(price) + 100'))
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
- max_value = DB[:history].max(:value)
233
+ max = DB[:history].max(:value)
234
+ min = DB[:history].min(:value)
250
235
 
251
- Or calculate a sum:
252
- total = DB[:items].sum(:price)
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
- Joining is very useful in a variety of scenarios, for example many-to-many relationships. With Sequel it's really easy:
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=>(could be items.id or order_items.id), :item_id=>order_items.order_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 #AS method:
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
- Models in Sequel are based on the Active Record pattern described by Martin Fowler (http://www.martinfowler.com/eaaCatalog/activeRecord.html). A model class corresponds to a table or a dataset, and an instance of that class wraps a single record in the model's underlying dataset.
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
- # or:
387
- Post.set_dataset DB[:my_posts].where(:category => 'ruby')
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#[] method can be used to fetch records by their primary key:
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 using hooks. The before_create and after_create hooks wrap record creation. The before_update and after_update wrap record updating. The before_save and after_save wrap record creation and updating. The before_destroy and after_destroy wrap destruction. The before_validation and after_validation hooks wrap validation.
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 do
474
+ def after_create
475
475
  author.increase_post_count
476
476
  end
477
477
 
478
- after_destroy do
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 hooks, while #delete does not:
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
- === Basic Model Validations
642
-
643
- To assign default validations to a sequel model:
644
-
645
- class MyModel < Sequel::Model
646
- validates do
647
- acceptance_of...
648
- confirmation_of...
649
- format_of...
650
- format_of...
651
- presence_of...
652
- length_of...
653
- not_string ...
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