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,78 @@
1
+ module Sequel
2
+ class Dataset
3
+ # Pretty prints the records in the dataset as plain-text table.
4
+ def print(*cols)
5
+ Sequel::PrettyTable.print(naked.all, cols.empty? ? columns : cols)
6
+ end
7
+ end
8
+
9
+ module PrettyTable
10
+ # Prints nice-looking plain-text tables via puts
11
+ #
12
+ # +--+-------+
13
+ # |id|name |
14
+ # |--+-------|
15
+ # |1 |fasdfas|
16
+ # |2 |test |
17
+ # +--+-------+
18
+ def self.print(records, columns = nil) # records is an array of hashes
19
+ columns ||= records.first.keys.sort_by{|x|x.to_s}
20
+ sizes = column_sizes(records, columns)
21
+ sep_line = separator_line(columns, sizes)
22
+
23
+ puts sep_line
24
+ puts header_line(columns, sizes)
25
+ puts sep_line
26
+ records.each {|r| puts data_line(columns, sizes, r)}
27
+ puts sep_line
28
+ end
29
+
30
+ ### Private Module Methods ###
31
+
32
+ # Hash of the maximum size of the value for each column
33
+ def self.column_sizes(records, columns) # :nodoc:
34
+ sizes = Hash.new {0}
35
+ columns.each do |c|
36
+ s = c.to_s.size
37
+ sizes[c.to_sym] = s if s > sizes[c.to_sym]
38
+ end
39
+ records.each do |r|
40
+ columns.each do |c|
41
+ s = r[c].to_s.size
42
+ sizes[c.to_sym] = s if s > sizes[c.to_sym]
43
+ end
44
+ end
45
+ sizes
46
+ end
47
+
48
+ # String for each data line
49
+ def self.data_line(columns, sizes, record) # :nodoc:
50
+ '|' << columns.map {|c| format_cell(sizes[c], record[c])}.join('|') << '|'
51
+ end
52
+
53
+ # Format the value so it takes up exactly size characters
54
+ def self.format_cell(size, v) # :nodoc:
55
+ case v
56
+ when Bignum, Fixnum
57
+ "%#{size}d" % v
58
+ when Float
59
+ "%#{size}g" % v
60
+ else
61
+ "%-#{size}s" % v.to_s
62
+ end
63
+ end
64
+
65
+ # String for header line
66
+ def self.header_line(columns, sizes) # :nodoc:
67
+ '|' << columns.map {|c| "%-#{sizes[c]}s" % c.to_s}.join('|') << '|'
68
+ end
69
+
70
+ # String for separtor line
71
+ def self.separator_line(columns, sizes) # :nodoc:
72
+ '+' << columns.map {|c| '-' * sizes[c]}.join('+') << '+'
73
+ end
74
+
75
+ private_class_method :column_sizes, :data_line, :format_cell, :header_line, :separator_line
76
+ end
77
+ end
78
+
@@ -0,0 +1,48 @@
1
+ module Sequel
2
+ class Database
3
+ # Return a dataset modified by the query block
4
+ def query(&block)
5
+ dataset.query(&block)
6
+ end
7
+ end
8
+
9
+ class Dataset
10
+ # Translates a query block into a dataset. Query blocks can be useful
11
+ # when expressing complex SELECT statements, e.g.:
12
+ #
13
+ # dataset = DB[:items].query do
14
+ # select :x, :y, :z
15
+ # filter{|o| (o.x > 1) & (o.y > 2)}
16
+ # order :z.desc
17
+ # end
18
+ #
19
+ # Which is the same as:
20
+ #
21
+ # dataset = DB[:items].select(:x, :y, :z).filter{|o| (o.x > 1) & (o.y > 2)}.order(:z.desc)
22
+ #
23
+ # Note that inside a call to query, you cannot call each, insert, update,
24
+ # or delete (or any method that calls those), or Sequel will raise an
25
+ # error.
26
+ def query(&block)
27
+ copy = clone({})
28
+ copy.extend(QueryBlockCopy)
29
+ copy.instance_eval(&block)
30
+ clone(copy.opts)
31
+ end
32
+
33
+ # Module used by Dataset#query that has the effect of making all
34
+ # dataset methods into !-style methods that modify the receiver.
35
+ module QueryBlockCopy
36
+ %w'each insert update delete'.each do |meth|
37
+ define_method(meth){|*args| raise Error, "##{meth} cannot be invoked inside a query block."}
38
+ end
39
+
40
+ # Merge the given options into the receiver's options and return the receiver
41
+ # instead of cloning the receiver.
42
+ def clone(opts = nil)
43
+ @opts.merge!(opts)
44
+ self
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,47 @@
1
+ # This file contains the previous extensions to String for date/time
2
+ # conversions. These are provided mainly for backward compatibility,
3
+ # Sequel now uses a module level method instead of extending string
4
+ # to handle the internal conversions.
5
+
6
+ class String
7
+ # Converts a string into a Date object.
8
+ def to_date
9
+ begin
10
+ Date.parse(self, Sequel.convert_two_digit_years)
11
+ rescue => e
12
+ raise Sequel::Error::InvalidValue, "Invalid Date value '#{self}' (#{e.message})"
13
+ end
14
+ end
15
+
16
+ # Converts a string into a DateTime object.
17
+ def to_datetime
18
+ begin
19
+ DateTime.parse(self, Sequel.convert_two_digit_years)
20
+ rescue => e
21
+ raise Sequel::Error::InvalidValue, "Invalid DateTime value '#{self}' (#{e.message})"
22
+ end
23
+ end
24
+
25
+ # Converts a string into a Time or DateTime object, depending on the
26
+ # value of Sequel.datetime_class
27
+ def to_sequel_time
28
+ begin
29
+ if Sequel.datetime_class == DateTime
30
+ DateTime.parse(self, Sequel.convert_two_digit_years)
31
+ else
32
+ Sequel.datetime_class.parse(self)
33
+ end
34
+ rescue => e
35
+ raise Sequel::Error::InvalidValue, "Invalid #{Sequel.datetime_class} value '#{self}' (#{e.message})"
36
+ end
37
+ end
38
+
39
+ # Converts a string into a Time object.
40
+ def to_time
41
+ begin
42
+ Time.parse(self)
43
+ rescue => e
44
+ raise Sequel::Error::InvalidValue, "Invalid Time value '#{self}' (#{e.message})"
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,44 @@
1
+ module Sequel
2
+ # Contains methods that ease metaprogramming, used by some of Sequel's classes.
3
+ module Metaprogramming
4
+ # Add methods to the object's metaclass
5
+ def meta_def(name, &block)
6
+ meta_eval{define_method(name, &block)}
7
+ end
8
+
9
+ private
10
+
11
+ # Make a singleton/class attribute accessor method(s).
12
+ # Replaces the construct:
13
+ #
14
+ # class << self
15
+ # attr_accessor *meths
16
+ # end
17
+ def metaattr_accessor(*meths)
18
+ meta_eval{attr_accessor(*meths)}
19
+ end
20
+
21
+ # Make a singleton/class method(s) private.
22
+ # Make a singleton/class attribute reader method(s).
23
+ # Replaces the construct:
24
+ #
25
+ # class << self
26
+ # attr_reader *meths
27
+ # end
28
+ def metaattr_reader(*meths)
29
+ meta_eval{attr_reader(*meths)}
30
+ end
31
+
32
+ # Evaluate the block in the context of the object's metaclass
33
+ def meta_eval(&block)
34
+ metaclass.instance_eval(&block)
35
+ end
36
+
37
+ # The hidden singleton lurks behind everyone
38
+ def metaclass
39
+ class << self
40
+ self
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,212 @@
1
+ module Sequel
2
+ # The Migration class describes a database migration that can be reversed.
3
+ # The migration looks very similar to ActiveRecord (Rails) migrations, e.g.:
4
+ #
5
+ # class CreateSessions < Sequel::Migration
6
+ # def up
7
+ # create_table :sessions do
8
+ # primary_key :id
9
+ # String :session_id, :size => 32, :unique => true
10
+ # DateTime :created_at
11
+ # text :data
12
+ # end
13
+ # end
14
+ #
15
+ # def down
16
+ # # You can use raw SQL if you need to
17
+ # self << 'DROP TABLE sessions'
18
+ # end
19
+ # end
20
+ #
21
+ # class AlterItems < Sequel::Migration
22
+ # def up
23
+ # alter_table :items do
24
+ # add_column :category, String, :default => 'ruby'
25
+ # end
26
+ # end
27
+ #
28
+ # def down
29
+ # alter_table :items do
30
+ # drop_column :category
31
+ # end
32
+ # end
33
+ # end
34
+ #
35
+ # To apply a migration to a database, you can invoke the #apply with
36
+ # the target database instance and the direction :up or :down, e.g.:
37
+ #
38
+ # DB = Sequel.connect('sqlite://mydb')
39
+ # CreateSessions.apply(DB, :up)
40
+ #
41
+ # See Sequel::Schema::Generator for the syntax to use for creating tables,
42
+ # and Sequel::Schema::AlterTableGenerator for the syntax to use when
43
+ # altering existing tables. Migrations act as a proxy for the database
44
+ # given in #apply, so inside #down and #up, you can act as though self
45
+ # refers to the database. So you can use any of the Sequel::Database
46
+ # instance methods directly.
47
+ class Migration
48
+ # Creates a new instance of the migration and sets the @db attribute.
49
+ def initialize(db)
50
+ @db = db
51
+ end
52
+
53
+ # Applies the migration to the supplied database in the specified
54
+ # direction.
55
+ def self.apply(db, direction)
56
+ obj = new(db)
57
+ case direction
58
+ when :up
59
+ obj.up
60
+ when :down
61
+ obj.down
62
+ else
63
+ raise ArgumentError, "Invalid migration direction specified (#{direction.inspect})"
64
+ end
65
+ end
66
+
67
+ # Returns the list of Migration descendants.
68
+ def self.descendants
69
+ @descendants ||= []
70
+ end
71
+
72
+ # Adds the new migration class to the list of Migration descendants.
73
+ def self.inherited(base)
74
+ descendants << base
75
+ end
76
+
77
+ # The default down action does nothing
78
+ def down
79
+ end
80
+
81
+ # Intercepts method calls intended for the database and sends them along.
82
+ def method_missing(method_sym, *args, &block)
83
+ @db.send(method_sym, *args, &block)
84
+ end
85
+
86
+ # The default up action does nothing
87
+ def up
88
+ end
89
+ end
90
+
91
+ # The Migrator module performs migrations based on migration files in a
92
+ # specified directory. The migration files should be named using the
93
+ # following pattern (in similar fashion to ActiveRecord migrations):
94
+ #
95
+ # <version>_<title>.rb
96
+ #
97
+ # For example, the following files are considered migration files:
98
+ #
99
+ # 001_create_sessions.rb
100
+ # 002_add_data_column.rb
101
+ # ...
102
+ #
103
+ # The migration files should contain one or more migration classes based
104
+ # on Sequel::Migration.
105
+ #
106
+ # Migrations are generally run via the sequel command line tool,
107
+ # using the -m and -M switches. The -m switch specifies the migration
108
+ # directory, and the -M switch specifies the version to which to migrate.
109
+ #
110
+ # You can apply migrations using the Migrator API, as well (this is necessary
111
+ # if you want to specify the version from which to migrate in addition to the version
112
+ # to which to migrate).
113
+ # To apply a migration, the #apply method must be invoked with the database
114
+ # instance, the directory of migration files and the target version. If
115
+ # no current version is supplied, it is read from the database. The migrator
116
+ # automatically creates a schema_info table in the database to keep track
117
+ # of the current migration version. If no migration version is stored in the
118
+ # database, the version is considered to be 0. If no target version is
119
+ # specified, the database is migrated to the latest version available in the
120
+ # migration directory.
121
+ #
122
+ # For example, to migrate the database to the latest version:
123
+ #
124
+ # Sequel::Migrator.apply(DB, '.')
125
+ #
126
+ # To migrate the database from version 1 to version 5:
127
+ #
128
+ # Sequel::Migrator.apply(DB, '.', 5, 1)
129
+ module Migrator
130
+ MIGRATION_FILE_PATTERN = /\A\d+_.+\.rb\z/.freeze
131
+
132
+ # Migrates the supplied database in the specified directory from the
133
+ # current version to the target version. If no current version is
134
+ # supplied, it is extracted from a schema_info table. The schema_info
135
+ # table is automatically created and maintained by the apply function.
136
+ def self.apply(db, directory, target = nil, current = nil)
137
+ # determine current and target version and direction
138
+ current ||= get_current_migration_version(db)
139
+ target ||= latest_migration_version(directory)
140
+ raise Error, "No current version available" if current.nil?
141
+ raise Error, "No target version available" if target.nil?
142
+
143
+ direction = current < target ? :up : :down
144
+
145
+ classes = migration_classes(directory, target, current, direction)
146
+
147
+ db.transaction do
148
+ classes.each {|c| c.apply(db, direction)}
149
+ set_current_migration_version(db, target)
150
+ end
151
+
152
+ target
153
+ end
154
+
155
+ # Gets the current migration version stored in the database. If no version
156
+ # number is stored, 0 is returned.
157
+ def self.get_current_migration_version(db)
158
+ r = schema_info_dataset(db).first
159
+ r ? r[:version] : 0
160
+ end
161
+
162
+ # Returns the latest version available in the specified directory.
163
+ def self.latest_migration_version(directory)
164
+ l = migration_files(directory).last
165
+ l ? File.basename(l).to_i : nil
166
+ end
167
+
168
+ # Returns a list of migration classes filtered for the migration range and
169
+ # ordered according to the migration direction.
170
+ def self.migration_classes(directory, target, current, direction)
171
+ range = direction == :up ?
172
+ (current + 1)..target : (target + 1)..current
173
+
174
+ # Remove class definitions
175
+ Migration.descendants.each do |c|
176
+ Object.send(:remove_const, c.to_s) rescue nil
177
+ end
178
+ Migration.descendants.clear # remove any defined migration classes
179
+
180
+ # load migration files
181
+ migration_files(directory, range).each {|fn| load(fn)}
182
+
183
+ # get migration classes
184
+ classes = Migration.descendants
185
+ classes.reverse! if direction == :down
186
+ classes
187
+ end
188
+
189
+ # Returns any found migration files in the supplied directory.
190
+ def self.migration_files(directory, range = nil)
191
+ files = []
192
+ Dir.new(directory).each do |file|
193
+ files[file.to_i] = File.join(directory, file) if MIGRATION_FILE_PATTERN.match(file)
194
+ end
195
+ filtered = range ? files[range] : files
196
+ filtered ? filtered.compact : []
197
+ end
198
+
199
+ # Returns the dataset for the schema_info table. If no such table
200
+ # exists, it is automatically created.
201
+ def self.schema_info_dataset(db)
202
+ db.create_table(:schema_info) {integer :version} unless db.table_exists?(:schema_info)
203
+ db[:schema_info]
204
+ end
205
+
206
+ # Sets the current migration version stored in the database.
207
+ def self.set_current_migration_version(db, version)
208
+ dataset = schema_info_dataset(db)
209
+ dataset.send(dataset.first ? :update : :<<, :version => version)
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,142 @@
1
+ require 'sequel/core'
2
+
3
+ module Sequel
4
+ # Holds the nameless subclasses that are created with
5
+ # Sequel::Model(), necessary for reopening subclasses with the
6
+ # Sequel::Model() superclass specified.
7
+ @models = {}
8
+
9
+ # Lets you create a Model subclass with its dataset already set.
10
+ # source can be an existing dataset or a symbol (in which case
11
+ # it will create a dataset using the default database with
12
+ # source as the table name).
13
+ #
14
+ # Example:
15
+ # class Comment < Sequel::Model(:something)
16
+ # table_name # => :something
17
+ # end
18
+ def self.Model(source)
19
+ @models[source] ||= Class.new(Model).set_dataset(source)
20
+ end
21
+
22
+ # Model has some methods that are added via metaprogramming:
23
+ #
24
+ # * All of the methods in DATASET_METHODS have class methods created that call
25
+ # the Model's dataset with the method of the same name with the given
26
+ # arguments.
27
+ # * All of the methods in HOOKS have class methods created that accept
28
+ # either a method name symbol or an optional tag and a block. These
29
+ # methods run the code as a callback at the specified time. For example:
30
+ #
31
+ # Model.before_save :do_something
32
+ # Model.before_save(:do_something_else){ self.something_else = 42}
33
+ # object = Model.new
34
+ # object.save
35
+ #
36
+ # Would run the object's :do_something method following by the code
37
+ # block related to :do_something_else. Note that if you specify a
38
+ # block, a tag is optional. If the tag is not nil, it will overwrite
39
+ # a previous block with the same tag. This allows hooks to work with
40
+ # systems that reload code.
41
+ # * All of the methods in HOOKS also create instance methods, but you
42
+ # should not override these instance methods.
43
+ # * The following instance_methods all call the class method of the same
44
+ # name: columns, dataset, db, primary_key, db_schema.
45
+ # * The following class level attr_readers are created: allowed_columns,
46
+ # dataset_methods, primary_key, and restricted_columns.
47
+ # You should not usually need to access these directly.
48
+ # * All validation methods also accept the options specified in #validates_each,
49
+ # in addition to the options specified in the RDoc for that method.
50
+ # * The following class level attr_accessors are created: raise_on_typecast_failure,
51
+ # raise_on_save_failure, strict_param_setting, typecast_empty_string_to_nil,
52
+ # and typecast_on_assignment:
53
+ #
54
+ # # Don't raise an error if a validation attempt fails in
55
+ # # save/create/save_changes/etc.
56
+ # Model.raise_on_save_failure = false
57
+ # Model.before_save{false}
58
+ # Model.new.save # => nil
59
+ # # Don't raise errors in new/set/update/etc. if an attempt to
60
+ # # access a missing/restricted method occurs (just silently
61
+ # # skip it)
62
+ # Model.strict_param_setting = false
63
+ # Model.new(:id=>1) # No Error
64
+ # # Don't typecast attribute values on assignment
65
+ # Model.typecast_on_assignment = false
66
+ # m = Model.new
67
+ # m.number = '10'
68
+ # m.number # => '10' instead of 10
69
+ # # Don't typecast empty string to nil for non-string, non-blob columns.
70
+ # Model.typecast_empty_string_to_nil = false
71
+ # m.number = ''
72
+ # m.number # => '' instead of nil
73
+ # # Don't raise if unable to typecast data for a column
74
+ # Model.typecast_empty_string_to_nil = true
75
+ # Model.raise_on_typecast_failure = false
76
+ # m.not_null_column = '' # => nil
77
+ # m.number = 'A' # => 'A'
78
+ #
79
+ # * The following class level method aliases are defined:
80
+ # * Model.dataset= => set_dataset
81
+ # * Model.is_a => is
82
+ class Model
83
+ # Dataset methods to proxy via metaprogramming
84
+ DATASET_METHODS = %w'<< all avg count delete distinct eager eager_graph each each_page
85
+ empty? except exclude filter first from from_self full_outer_join get graph
86
+ group group_and_count group_by having inner_join insert
87
+ insert_multiple intersect interval join join_table last
88
+ left_outer_join limit map multi_insert naked order order_by order_more
89
+ paginate print query range reverse_order right_outer_join select
90
+ select_all select_more server set set_graph_aliases single_value to_csv to_hash
91
+ transform union unfiltered unordered update where with_sql'.map{|x| x.to_sym}
92
+
93
+ # Regular expression that much match for a public instance method of a plugin
94
+ # dataset to have a model method created that calls it
95
+ DATASET_METHOD_RE = /\A[A-Za-z_][A-Za-z0-9_]*\z/
96
+
97
+ # Empty instance variables, for -w compliance
98
+ EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@transform, :@db, :@skip_superclass_validations]
99
+
100
+ # Hooks that are safe for public use
101
+ HOOKS = [:after_initialize, :before_create, :after_create, :before_update,
102
+ :after_update, :before_save, :after_save, :before_destroy, :after_destroy,
103
+ :before_validation, :after_validation]
104
+
105
+ # Instance variables that are inherited in subclasses
106
+ INHERITED_INSTANCE_VARIABLES = {:@allowed_columns=>:dup, :@dataset_methods=>:dup,
107
+ :@dataset_method_modules=>:dup, :@primary_key=>nil, :@use_transactions=>nil,
108
+ :@raise_on_save_failure=>nil, :@restricted_columns=>:dup, :@restrict_primary_key=>nil,
109
+ :@simple_pk=>nil, :@simple_table=>nil, :@strict_param_setting=>nil,
110
+ :@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil,
111
+ :@raise_on_typecast_failure=>nil, :@association_reflections=>:dup}
112
+
113
+ # The setter methods (methods ending with =) that are never allowed
114
+ # to be called automatically via set.
115
+ RESTRICTED_SETTER_METHODS = %w"== === []= taguri= typecast_empty_string_to_nil= typecast_on_assignment= strict_param_setting= raise_on_save_failure= raise_on_typecast_failure="
116
+
117
+ @allowed_columns = nil
118
+ @association_reflections = {}
119
+ @cache_store = nil
120
+ @cache_ttl = nil
121
+ @db = nil
122
+ @db_schema = nil
123
+ @dataset_method_modules = []
124
+ @dataset_methods = {}
125
+ @overridable_methods_module = nil
126
+ @primary_key = :id
127
+ @raise_on_save_failure = true
128
+ @raise_on_typecast_failure = true
129
+ @restrict_primary_key = true
130
+ @restricted_columns = nil
131
+ @simple_pk = nil
132
+ @simple_table = nil
133
+ @skip_superclass_validations = nil
134
+ @strict_param_setting = true
135
+ @transform = nil
136
+ @typecast_empty_string_to_nil = true
137
+ @typecast_on_assignment = true
138
+ @use_transactions = true
139
+ end
140
+ end
141
+
142
+ Sequel.require %w"inflections plugins base association_reflection associations exceptions errors deprecated", "model"