epugh-sequel 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. data/README.rdoc +652 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/sequel +104 -0
  4. data/lib/sequel.rb +1 -0
  5. data/lib/sequel/adapters/ado.rb +85 -0
  6. data/lib/sequel/adapters/db2.rb +132 -0
  7. data/lib/sequel/adapters/dbi.rb +101 -0
  8. data/lib/sequel/adapters/do.rb +197 -0
  9. data/lib/sequel/adapters/do/mysql.rb +38 -0
  10. data/lib/sequel/adapters/do/postgres.rb +92 -0
  11. data/lib/sequel/adapters/do/sqlite.rb +31 -0
  12. data/lib/sequel/adapters/firebird.rb +307 -0
  13. data/lib/sequel/adapters/informix.rb +75 -0
  14. data/lib/sequel/adapters/jdbc.rb +485 -0
  15. data/lib/sequel/adapters/jdbc/h2.rb +62 -0
  16. data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
  17. data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
  18. data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
  19. data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
  20. data/lib/sequel/adapters/mysql.rb +370 -0
  21. data/lib/sequel/adapters/odbc.rb +184 -0
  22. data/lib/sequel/adapters/openbase.rb +57 -0
  23. data/lib/sequel/adapters/oracle.rb +140 -0
  24. data/lib/sequel/adapters/postgres.rb +453 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +93 -0
  26. data/lib/sequel/adapters/shared/mysql.rb +341 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +62 -0
  28. data/lib/sequel/adapters/shared/postgres.rb +743 -0
  29. data/lib/sequel/adapters/shared/progress.rb +34 -0
  30. data/lib/sequel/adapters/shared/sqlite.rb +263 -0
  31. data/lib/sequel/adapters/sqlite.rb +243 -0
  32. data/lib/sequel/adapters/utils/date_format.rb +21 -0
  33. data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
  34. data/lib/sequel/adapters/utils/unsupported.rb +62 -0
  35. data/lib/sequel/connection_pool.rb +258 -0
  36. data/lib/sequel/core.rb +204 -0
  37. data/lib/sequel/core_sql.rb +185 -0
  38. data/lib/sequel/database.rb +687 -0
  39. data/lib/sequel/database/schema_generator.rb +324 -0
  40. data/lib/sequel/database/schema_methods.rb +164 -0
  41. data/lib/sequel/database/schema_sql.rb +324 -0
  42. data/lib/sequel/dataset.rb +422 -0
  43. data/lib/sequel/dataset/convenience.rb +237 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +220 -0
  45. data/lib/sequel/dataset/sql.rb +1105 -0
  46. data/lib/sequel/deprecated.rb +529 -0
  47. data/lib/sequel/exceptions.rb +44 -0
  48. data/lib/sequel/extensions/blank.rb +42 -0
  49. data/lib/sequel/extensions/inflector.rb +288 -0
  50. data/lib/sequel/extensions/pagination.rb +96 -0
  51. data/lib/sequel/extensions/pretty_table.rb +78 -0
  52. data/lib/sequel/extensions/query.rb +48 -0
  53. data/lib/sequel/extensions/string_date_time.rb +47 -0
  54. data/lib/sequel/metaprogramming.rb +44 -0
  55. data/lib/sequel/migration.rb +212 -0
  56. data/lib/sequel/model.rb +142 -0
  57. data/lib/sequel/model/association_reflection.rb +263 -0
  58. data/lib/sequel/model/associations.rb +1024 -0
  59. data/lib/sequel/model/base.rb +911 -0
  60. data/lib/sequel/model/deprecated.rb +188 -0
  61. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  62. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  63. data/lib/sequel/model/deprecated_validations.rb +384 -0
  64. data/lib/sequel/model/errors.rb +37 -0
  65. data/lib/sequel/model/exceptions.rb +7 -0
  66. data/lib/sequel/model/inflections.rb +230 -0
  67. data/lib/sequel/model/plugins.rb +74 -0
  68. data/lib/sequel/object_graph.rb +230 -0
  69. data/lib/sequel/plugins/caching.rb +122 -0
  70. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  71. data/lib/sequel/plugins/schema.rb +53 -0
  72. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  73. data/lib/sequel/plugins/validation_class_methods.rb +373 -0
  74. data/lib/sequel/sql.rb +854 -0
  75. data/lib/sequel/version.rb +11 -0
  76. data/lib/sequel_core.rb +1 -0
  77. data/lib/sequel_model.rb +1 -0
  78. data/spec/adapters/ado_spec.rb +46 -0
  79. data/spec/adapters/firebird_spec.rb +376 -0
  80. data/spec/adapters/informix_spec.rb +96 -0
  81. data/spec/adapters/mysql_spec.rb +875 -0
  82. data/spec/adapters/oracle_spec.rb +272 -0
  83. data/spec/adapters/postgres_spec.rb +692 -0
  84. data/spec/adapters/spec_helper.rb +10 -0
  85. data/spec/adapters/sqlite_spec.rb +550 -0
  86. data/spec/core/connection_pool_spec.rb +526 -0
  87. data/spec/core/core_ext_spec.rb +156 -0
  88. data/spec/core/core_sql_spec.rb +528 -0
  89. data/spec/core/database_spec.rb +1214 -0
  90. data/spec/core/dataset_spec.rb +3513 -0
  91. data/spec/core/expression_filters_spec.rb +363 -0
  92. data/spec/core/migration_spec.rb +261 -0
  93. data/spec/core/object_graph_spec.rb +280 -0
  94. data/spec/core/pretty_table_spec.rb +58 -0
  95. data/spec/core/schema_generator_spec.rb +167 -0
  96. data/spec/core/schema_spec.rb +778 -0
  97. data/spec/core/spec_helper.rb +82 -0
  98. data/spec/core/version_spec.rb +7 -0
  99. data/spec/extensions/blank_spec.rb +67 -0
  100. data/spec/extensions/caching_spec.rb +201 -0
  101. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  102. data/spec/extensions/inflector_spec.rb +122 -0
  103. data/spec/extensions/pagination_spec.rb +99 -0
  104. data/spec/extensions/pretty_table_spec.rb +91 -0
  105. data/spec/extensions/query_spec.rb +85 -0
  106. data/spec/extensions/schema_spec.rb +111 -0
  107. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  108. data/spec/extensions/spec_helper.rb +90 -0
  109. data/spec/extensions/string_date_time_spec.rb +93 -0
  110. data/spec/extensions/validation_class_methods_spec.rb +1054 -0
  111. data/spec/integration/dataset_test.rb +160 -0
  112. data/spec/integration/eager_loader_test.rb +683 -0
  113. data/spec/integration/prepared_statement_test.rb +130 -0
  114. data/spec/integration/schema_test.rb +183 -0
  115. data/spec/integration/spec_helper.rb +75 -0
  116. data/spec/integration/type_test.rb +96 -0
  117. data/spec/model/association_reflection_spec.rb +93 -0
  118. data/spec/model/associations_spec.rb +1780 -0
  119. data/spec/model/base_spec.rb +494 -0
  120. data/spec/model/caching_spec.rb +217 -0
  121. data/spec/model/dataset_methods_spec.rb +78 -0
  122. data/spec/model/eager_loading_spec.rb +1165 -0
  123. data/spec/model/hooks_spec.rb +472 -0
  124. data/spec/model/inflector_spec.rb +126 -0
  125. data/spec/model/model_spec.rb +588 -0
  126. data/spec/model/plugins_spec.rb +142 -0
  127. data/spec/model/record_spec.rb +1243 -0
  128. data/spec/model/schema_spec.rb +92 -0
  129. data/spec/model/spec_helper.rb +124 -0
  130. data/spec/model/validations_spec.rb +1080 -0
  131. data/spec/rcov.opts +6 -0
  132. data/spec/spec.opts +0 -0
  133. data/spec/spec_config.rb.example +10 -0
  134. metadata +202 -0
@@ -0,0 +1,44 @@
1
+ module Sequel
2
+ # Represents an error raised in Sequel code.
3
+ class Error < ::StandardError
4
+
5
+ # Raised when Sequel is unable to load a specified adapter.
6
+ class AdapterNotFound < Error ; end
7
+
8
+ # Raised on an invalid operation.
9
+ class InvalidOperation < Error; end
10
+
11
+ # Error raised when an invalid statement is executed.
12
+ class InvalidStatement < Error; end
13
+
14
+ # Represents an Invalid transform.
15
+ class InvalidTransform < Error ; end
16
+
17
+ # Represents an invalid value stored in the database.
18
+ class InvalidValue < Error ; end
19
+
20
+ # Represents an attempt to performing filter operations when no filter has been specified yet.
21
+ class NoExistingFilter < Error ; end
22
+
23
+ # There was an error while waiting on a connection from the connection pool
24
+ class PoolTimeoutError < Error ; end
25
+
26
+ # Rollback is a special error used to rollback a transactions.
27
+ # A transaction block will catch this error and won't pass further up the stack.
28
+ class Rollback < Error ; end
29
+ end
30
+
31
+ # Generic error raised by the database adapters, indicating a
32
+ # problem originating from the database server.
33
+ class DatabaseError < Error; end
34
+
35
+ # Error raised when the Sequel is unable to connect to the database with the
36
+ # connection parameters it was given.
37
+ class DatabaseConnectionError < DatabaseError; end
38
+
39
+ # Error that should be raised by adapters when they determine that the connection
40
+ # to the database has been lost. Instructs the connection pool code to
41
+ # remove that connection from the pool so that other connections can be acquired
42
+ # automatically.
43
+ class DatabaseDisconnectError < DatabaseError; end
44
+ end
@@ -0,0 +1,42 @@
1
+ class FalseClass
2
+ # false is always blank
3
+ def blank?
4
+ true
5
+ end
6
+ end
7
+
8
+ # Helpers from Metaid and a bit more
9
+ class Object
10
+ # Objects are blank if they respond true to empty?
11
+ def blank?
12
+ respond_to?(:empty?) && empty?
13
+ end
14
+ end
15
+
16
+ class NilClass
17
+ # nil is always blank
18
+ def blank?
19
+ true
20
+ end
21
+ end
22
+
23
+ class Numeric
24
+ # Numerics are never blank (not even 0)
25
+ def blank?
26
+ false
27
+ end
28
+ end
29
+
30
+ class String
31
+ # Strings are blank if they are empty or include only whitespace
32
+ def blank?
33
+ strip.empty?
34
+ end
35
+ end
36
+
37
+ class TrueClass
38
+ # true is never blank
39
+ def blank?
40
+ false
41
+ end
42
+ end
@@ -0,0 +1,288 @@
1
+ # Add inflection methods to String, which allows the easy transformation of
2
+ # words from singular to plural,class names to table names, modularized class
3
+ # names to ones without, and class names to foreign keys.
4
+
5
+ class String
6
+ # This module acts as a singleton returned/yielded by String.inflections,
7
+ # which is used to override or specify additional inflection rules. Examples:
8
+ #
9
+ # String.inflections do |inflect|
10
+ # inflect.plural /^(ox)$/i, '\1\2en'
11
+ # inflect.singular /^(ox)en/i, '\1'
12
+ #
13
+ # inflect.irregular 'octopus', 'octopi'
14
+ #
15
+ # inflect.uncountable "equipment"
16
+ # end
17
+ #
18
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
19
+ # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
20
+ # already have been loaded.
21
+ module Inflections
22
+ @plurals, @singulars, @uncountables = [], [], []
23
+
24
+ class << self
25
+ attr_reader :plurals, :singulars, :uncountables
26
+ end
27
+
28
+ # Clears the loaded inflections within a given scope (default is :all). Give the scope as a symbol of the inflection type,
29
+ # the options are: :plurals, :singulars, :uncountables
30
+ #
31
+ # Examples:
32
+ # clear :all
33
+ # clear :plurals
34
+ def self.clear(scope = :all)
35
+ Sequel::Inflections.clear(scope)
36
+ case scope
37
+ when :all
38
+ @plurals, @singulars, @uncountables = [], [], []
39
+ else
40
+ instance_variable_set("@#{scope}", [])
41
+ end
42
+ end
43
+
44
+ # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
45
+ # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
46
+ #
47
+ # Examples:
48
+ # irregular 'octopus', 'octopi'
49
+ # irregular 'person', 'people'
50
+ def self.irregular(singular, plural)
51
+ Sequel::Inflections.irregular(singular, plural)
52
+ plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
53
+ singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
54
+ end
55
+
56
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
57
+ # The replacement should always be a string that may include references to the matched data from the rule.
58
+ #
59
+ # Example:
60
+ # plural(/(x|ch|ss|sh)$/i, '\1es')
61
+ def self.plural(rule, replacement)
62
+ Sequel::Inflections.plural(rule, replacement)
63
+ @plurals.insert(0, [rule, replacement])
64
+ end
65
+
66
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
67
+ # The replacement should always be a string that may include references to the matched data from the rule.
68
+ #
69
+ # Example:
70
+ # singular(/([^aeiouy]|qu)ies$/i, '\1y')
71
+ def self.singular(rule, replacement)
72
+ Sequel::Inflections.singular(rule, replacement)
73
+ @singulars.insert(0, [rule, replacement])
74
+ end
75
+
76
+ # Add uncountable words that shouldn't be attempted inflected.
77
+ #
78
+ # Examples:
79
+ # uncountable "money"
80
+ # uncountable "money", "information"
81
+ # uncountable %w( money information rice )
82
+ def self.uncountable(*words)
83
+ Sequel::Inflections.uncountable(*words)
84
+ (@uncountables << words).flatten!
85
+ end
86
+
87
+ # Setup the default inflections
88
+ plural(/$/, 's')
89
+ plural(/s$/i, 's')
90
+ plural(/(ax|test)is$/i, '\1es')
91
+ plural(/(octop|vir)us$/i, '\1i')
92
+ plural(/(alias|status)$/i, '\1es')
93
+ plural(/(bu)s$/i, '\1ses')
94
+ plural(/(buffal|tomat)o$/i, '\1oes')
95
+ plural(/([ti])um$/i, '\1a')
96
+ plural(/sis$/i, 'ses')
97
+ plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
98
+ plural(/(hive)$/i, '\1s')
99
+ plural(/([^aeiouy]|qu)y$/i, '\1ies')
100
+ plural(/(x|ch|ss|sh)$/i, '\1es')
101
+ plural(/(matr|vert|ind)ix|ex$/i, '\1ices')
102
+ plural(/([m|l])ouse$/i, '\1ice')
103
+ plural(/^(ox)$/i, '\1en')
104
+ plural(/(quiz)$/i, '\1zes')
105
+
106
+ singular(/s$/i, '')
107
+ singular(/(n)ews$/i, '\1ews')
108
+ singular(/([ti])a$/i, '\1um')
109
+ singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
110
+ singular(/(^analy)ses$/i, '\1sis')
111
+ singular(/([^f])ves$/i, '\1fe')
112
+ singular(/(hive)s$/i, '\1')
113
+ singular(/(tive)s$/i, '\1')
114
+ singular(/([lr])ves$/i, '\1f')
115
+ singular(/([^aeiouy]|qu)ies$/i, '\1y')
116
+ singular(/(s)eries$/i, '\1eries')
117
+ singular(/(m)ovies$/i, '\1ovie')
118
+ singular(/(x|ch|ss|sh)es$/i, '\1')
119
+ singular(/([m|l])ice$/i, '\1ouse')
120
+ singular(/(bus)es$/i, '\1')
121
+ singular(/(o)es$/i, '\1')
122
+ singular(/(shoe)s$/i, '\1')
123
+ singular(/(cris|ax|test)es$/i, '\1is')
124
+ singular(/(octop|vir)i$/i, '\1us')
125
+ singular(/(alias|status)es$/i, '\1')
126
+ singular(/^(ox)en/i, '\1')
127
+ singular(/(vert|ind)ices$/i, '\1ex')
128
+ singular(/(matr)ices$/i, '\1ix')
129
+ singular(/(quiz)zes$/i, '\1')
130
+
131
+ irregular('person', 'people')
132
+ irregular('man', 'men')
133
+ irregular('child', 'children')
134
+ irregular('sex', 'sexes')
135
+ irregular('move', 'moves')
136
+
137
+ uncountable(%w(equipment information rice money species series fish sheep))
138
+ end
139
+
140
+ # Yield the Inflections module if a block is given, and return
141
+ # the Inflections module.
142
+ def self.inflections
143
+ yield Inflections if block_given?
144
+ Inflections
145
+ end
146
+
147
+ # By default, camelize converts the string to UpperCamelCase. If the argument to camelize
148
+ # is set to :lower then camelize produces lowerCamelCase.
149
+ #
150
+ # camelize will also convert '/' to '::' which is useful for converting paths to namespaces
151
+ #
152
+ # Examples
153
+ # "active_record".camelize #=> "ActiveRecord"
154
+ # "active_record".camelize(:lower) #=> "activeRecord"
155
+ # "active_record/errors".camelize #=> "ActiveRecord::Errors"
156
+ # "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
157
+ def camelize(first_letter_in_uppercase = :upper)
158
+ s = gsub(/\/(.?)/){|x| "::#{x[-1..-1].upcase unless x == '/'}"}.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
159
+ s[0...1] = s[0...1].downcase unless first_letter_in_uppercase == :upper
160
+ s
161
+ end
162
+ alias_method :camelcase, :camelize
163
+
164
+ # Singularizes and camelizes the string. Also strips out all characters preceding
165
+ # and including a period (".").
166
+ #
167
+ # Examples
168
+ # "egg_and_hams".classify #=> "EggAndHam"
169
+ # "post".classify #=> "Post"
170
+ # "schema.post".classify #=> "Post"
171
+ def classify
172
+ sub(/.*\./, '').singularize.camelize
173
+ end
174
+
175
+ # Constantize tries to find a declared constant with the name specified
176
+ # in the string. It raises a NameError when the name is not in CamelCase
177
+ # or is not initialized.
178
+ #
179
+ # Examples
180
+ # "Module".constantize #=> Module
181
+ # "Class".constantize #=> Class
182
+ def constantize
183
+ raise(NameError, "#{inspect} is not a valid constant name!") unless m = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.match(self)
184
+ Object.module_eval("::#{m[1]}", __FILE__, __LINE__)
185
+ end
186
+
187
+ # Replaces underscores with dashes in the string.
188
+ #
189
+ # Example
190
+ # "puni_puni".dasherize #=> "puni-puni"
191
+ def dasherize
192
+ gsub(/_/, '-')
193
+ end
194
+
195
+ # Removes the module part from the expression in the string
196
+ #
197
+ # Examples
198
+ # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
199
+ # "Inflections".demodulize #=> "Inflections"
200
+ def demodulize
201
+ gsub(/^.*::/, '')
202
+ end
203
+
204
+ # Creates a foreign key name from a class name.
205
+ # +use_underscore+ sets whether the method should put '_' between the name and 'id'.
206
+ #
207
+ # Examples
208
+ # "Message".foreign_key #=> "message_id"
209
+ # "Message".foreign_key(false) #=> "messageid"
210
+ # "Admin::Post".foreign_key #=> "post_id"
211
+ def foreign_key(use_underscore = true)
212
+ "#{demodulize.underscore}#{'_' if use_underscore}id"
213
+ end
214
+
215
+ # Capitalizes the first word and turns underscores into spaces and strips _id.
216
+ # Like titleize, this is meant for creating pretty output.
217
+ #
218
+ # Examples
219
+ # "employee_salary" #=> "Employee salary"
220
+ # "author_id" #=> "Author"
221
+ def humanize
222
+ gsub(/_id$/, "").gsub(/_/, " ").capitalize
223
+ end
224
+
225
+ # Returns the plural form of the word in the string.
226
+ #
227
+ # Examples
228
+ # "post".pluralize #=> "posts"
229
+ # "octopus".pluralize #=> "octopi"
230
+ # "sheep".pluralize #=> "sheep"
231
+ # "words".pluralize #=> "words"
232
+ # "the blue mailman".pluralize #=> "the blue mailmen"
233
+ # "CamelOctopus".pluralize #=> "CamelOctopi"
234
+ def pluralize
235
+ result = dup
236
+ Inflections.plurals.each{|(rule, replacement)| break if result.gsub!(rule, replacement)} unless Inflections.uncountables.include?(downcase)
237
+ result
238
+ end
239
+
240
+ # The reverse of pluralize, returns the singular form of a word in a string.
241
+ #
242
+ # Examples
243
+ # "posts".singularize #=> "post"
244
+ # "octopi".singularize #=> "octopus"
245
+ # "sheep".singluarize #=> "sheep"
246
+ # "word".singluarize #=> "word"
247
+ # "the blue mailmen".singularize #=> "the blue mailman"
248
+ # "CamelOctopi".singularize #=> "CamelOctopus"
249
+ def singularize
250
+ result = dup
251
+ Inflections.singulars.each{|(rule, replacement)| break if result.gsub!(rule, replacement)} unless Inflections.uncountables.include?(downcase)
252
+ result
253
+ end
254
+
255
+ # Underscores and pluralizes the string.
256
+ #
257
+ # Examples
258
+ # "RawScaledScorer".tableize #=> "raw_scaled_scorers"
259
+ # "egg_and_ham".tableize #=> "egg_and_hams"
260
+ # "fancyCategory".tableize #=> "fancy_categories"
261
+ def tableize
262
+ underscore.pluralize
263
+ end
264
+
265
+ # Capitalizes all the words and replaces some characters in the string to create
266
+ # a nicer looking title. Titleize is meant for creating pretty output.
267
+ #
268
+ # titleize is also aliased as as titlecase
269
+ #
270
+ # Examples
271
+ # "man from the boondocks".titleize #=> "Man From The Boondocks"
272
+ # "x-men: the last stand".titleize #=> "X Men: The Last Stand"
273
+ def titleize
274
+ underscore.humanize.gsub(/\b([a-z])/){|x| x[-1..-1].upcase}
275
+ end
276
+ alias_method :titlecase, :titleize
277
+
278
+ # The reverse of camelize. Makes an underscored form from the expression in the string.
279
+ # Also changes '::' to '/' to convert namespaces to paths.
280
+ #
281
+ # Examples
282
+ # "ActiveRecord".underscore #=> "active_record"
283
+ # "ActiveRecord::Errors".underscore #=> active_record/errors
284
+ def underscore
285
+ gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
286
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
287
+ end
288
+ end
@@ -0,0 +1,96 @@
1
+ module Sequel
2
+ class Dataset
3
+ # Returns a paginated dataset. The returned dataset is limited to
4
+ # the page size at the correct offset, and extended with the Pagination
5
+ # module. If a record count is not provided, does a count of total
6
+ # number of records for this dataset.
7
+ def paginate(page_no, page_size, record_count=nil)
8
+ raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
9
+ paginated = limit(page_size, (page_no - 1) * page_size)
10
+ paginated.extend(Pagination)
11
+ paginated.set_pagination_info(page_no, page_size, record_count || count)
12
+ end
13
+
14
+ # Yields a paginated dataset for each page and returns the receiver. Does
15
+ # a count to find the total number of records for this dataset.
16
+ def each_page(page_size, &block)
17
+ raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
18
+ record_count = count
19
+ total_pages = (record_count / page_size.to_f).ceil
20
+ (1..total_pages).each{|page_no| yield paginate(page_no, page_size, record_count)}
21
+ self
22
+ end
23
+
24
+ # Holds methods that only relate to paginated datasets. Paginated dataset
25
+ # have pages starting at 1 (page 1 is offset 0, page 1 is offset page_size).
26
+ module Pagination
27
+ # The number of records per page (the final page may have fewer than
28
+ # this number of records).
29
+ attr_accessor :page_size
30
+
31
+ # The number of pages in the dataset before pagination, of which
32
+ # this paginated dataset is one.
33
+ attr_accessor :page_count
34
+
35
+ # The current page of the dataset, starting at 1 and not 0.
36
+ attr_accessor :current_page
37
+
38
+ # The total number of records in the dataset before pagination.
39
+ attr_accessor :pagination_record_count
40
+
41
+ # Returns the record range for the current page
42
+ def current_page_record_range
43
+ return (0..0) if @current_page > @page_count
44
+
45
+ a = 1 + (@current_page - 1) * @page_size
46
+ b = a + @page_size - 1
47
+ b = @pagination_record_count if b > @pagination_record_count
48
+ a..b
49
+ end
50
+
51
+ # Returns the number of records in the current page
52
+ def current_page_record_count
53
+ return 0 if @current_page > @page_count
54
+
55
+ a = 1 + (@current_page - 1) * @page_size
56
+ b = a + @page_size - 1
57
+ b = @pagination_record_count if b > @pagination_record_count
58
+ b - a + 1
59
+ end
60
+
61
+ # Returns true if the current page is the first page
62
+ def first_page?
63
+ @current_page == 1
64
+ end
65
+
66
+ # Returns true if the current page is the last page
67
+ def last_page?
68
+ @current_page == @page_count
69
+ end
70
+
71
+ # Returns the next page number or nil if the current page is the last page
72
+ def next_page
73
+ current_page < page_count ? (current_page + 1) : nil
74
+ end
75
+
76
+ # Returns the page range
77
+ def page_range
78
+ 1..page_count
79
+ end
80
+
81
+ # Returns the previous page number or nil if the current page is the first
82
+ def prev_page
83
+ current_page > 1 ? (current_page - 1) : nil
84
+ end
85
+
86
+ # Sets the pagination info for this paginated dataset, and returns self.
87
+ def set_pagination_info(page_no, page_size, record_count)
88
+ @current_page = page_no
89
+ @page_size = page_size
90
+ @pagination_record_count = record_count
91
+ @page_count = (record_count / page_size.to_f).ceil
92
+ self
93
+ end
94
+ end
95
+ end
96
+ end