sequel 2.12.0 → 3.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.
- data/CHANGELOG +62 -0
 - data/README.rdoc +3 -3
 - data/Rakefile +7 -0
 - data/doc/advanced_associations.rdoc +44 -0
 - data/doc/release_notes/3.0.0.txt +221 -0
 - data/lib/sequel/adapters/amalgalite.rb +208 -0
 - data/lib/sequel/adapters/db2.rb +3 -0
 - data/lib/sequel/adapters/dbi.rb +9 -0
 - data/lib/sequel/adapters/do.rb +0 -4
 - data/lib/sequel/adapters/firebird.rb +16 -18
 - data/lib/sequel/adapters/informix.rb +5 -3
 - data/lib/sequel/adapters/jdbc.rb +24 -20
 - data/lib/sequel/adapters/jdbc/h2.rb +15 -4
 - data/lib/sequel/adapters/mysql.rb +4 -8
 - data/lib/sequel/adapters/odbc.rb +0 -4
 - data/lib/sequel/adapters/oracle.rb +0 -4
 - data/lib/sequel/adapters/shared/mssql.rb +16 -5
 - data/lib/sequel/adapters/shared/mysql.rb +87 -86
 - data/lib/sequel/adapters/shared/oracle.rb +92 -3
 - data/lib/sequel/adapters/shared/postgres.rb +85 -29
 - data/lib/sequel/adapters/shared/progress.rb +8 -3
 - data/lib/sequel/adapters/shared/sqlite.rb +53 -23
 - data/lib/sequel/adapters/sqlite.rb +4 -7
 - data/lib/sequel/adapters/utils/unsupported.rb +3 -3
 - data/lib/sequel/connection_pool.rb +18 -25
 - data/lib/sequel/core.rb +2 -21
 - data/lib/sequel/database.rb +60 -44
 - data/lib/sequel/database/schema_generator.rb +26 -31
 - data/lib/sequel/database/schema_methods.rb +8 -3
 - data/lib/sequel/database/schema_sql.rb +114 -28
 - data/lib/sequel/dataset.rb +14 -41
 - data/lib/sequel/dataset/convenience.rb +31 -54
 - data/lib/sequel/dataset/graph.rb +7 -13
 - data/lib/sequel/dataset/sql.rb +43 -54
 - data/lib/sequel/extensions/inflector.rb +0 -5
 - data/lib/sequel/extensions/schema_dumper.rb +238 -0
 - data/lib/sequel/metaprogramming.rb +0 -20
 - data/lib/sequel/model.rb +1 -2
 - data/lib/sequel/model/base.rb +18 -16
 - data/lib/sequel/model/inflections.rb +6 -9
 - data/lib/sequel/plugins/caching.rb +0 -6
 - data/lib/sequel/plugins/hook_class_methods.rb +1 -1
 - data/lib/sequel/sql.rb +2 -0
 - data/lib/sequel/version.rb +2 -2
 - data/spec/adapters/firebird_spec.rb +35 -8
 - data/spec/adapters/mysql_spec.rb +173 -266
 - data/spec/adapters/oracle_spec.rb +13 -0
 - data/spec/adapters/postgres_spec.rb +127 -227
 - data/spec/adapters/sqlite_spec.rb +13 -171
 - data/spec/core/connection_pool_spec.rb +15 -4
 - data/spec/core/core_sql_spec.rb +14 -170
 - data/spec/core/database_spec.rb +50 -132
 - data/spec/core/dataset_spec.rb +47 -930
 - data/spec/core/expression_filters_spec.rb +12 -0
 - data/spec/core/schema_generator_spec.rb +37 -45
 - data/spec/core/schema_spec.rb +26 -16
 - data/spec/core/spec_helper.rb +0 -25
 - data/spec/extensions/inflector_spec.rb +0 -3
 - data/spec/extensions/schema_dumper_spec.rb +292 -0
 - data/spec/extensions/serialization_spec.rb +9 -0
 - data/spec/extensions/single_table_inheritance_spec.rb +6 -1
 - data/spec/extensions/spec_helper.rb +1 -3
 - data/spec/extensions/validation_helpers_spec.rb +4 -4
 - data/spec/integration/database_test.rb +18 -0
 - data/spec/integration/dataset_test.rb +112 -1
 - data/spec/integration/eager_loader_test.rb +70 -9
 - data/spec/integration/prepared_statement_test.rb +2 -2
 - data/spec/integration/schema_test.rb +76 -27
 - data/spec/integration/spec_helper.rb +0 -14
 - data/spec/integration/transaction_test.rb +27 -0
 - data/spec/model/associations_spec.rb +0 -36
 - data/spec/model/base_spec.rb +18 -123
 - data/spec/model/hooks_spec.rb +2 -235
 - data/spec/model/inflector_spec.rb +15 -115
 - data/spec/model/model_spec.rb +0 -120
 - data/spec/model/plugins_spec.rb +0 -70
 - data/spec/model/record_spec.rb +35 -93
 - data/spec/model/spec_helper.rb +0 -27
 - data/spec/model/validations_spec.rb +0 -931
 - metadata +9 -14
 - data/lib/sequel/deprecated.rb +0 -593
 - data/lib/sequel/deprecated_migration.rb +0 -91
 - data/lib/sequel/model/deprecated.rb +0 -204
 - data/lib/sequel/model/deprecated_hooks.rb +0 -103
 - data/lib/sequel/model/deprecated_inflector.rb +0 -335
 - data/lib/sequel/model/deprecated_validations.rb +0 -388
 - data/spec/core/core_ext_spec.rb +0 -156
 - data/spec/core/migration_spec.rb +0 -263
 - data/spec/core/pretty_table_spec.rb +0 -58
 - data/spec/model/caching_spec.rb +0 -217
 - data/spec/model/schema_spec.rb +0 -92
 
    
        data/lib/sequel/dataset/graph.rb
    CHANGED
    
    | 
         @@ -17,8 +17,7 @@ module Sequel 
     | 
|
| 
       17 
17 
     | 
    
         
             
                # the tables are combined in the single return hash.  You can get around that by
         
     | 
| 
       18 
18 
     | 
    
         
             
                # using .select with correct aliases for all of the columns, but it is simpler to
         
     | 
| 
       19 
19 
     | 
    
         
             
                # use graph and have the result set split for you.  In addition, graph respects
         
     | 
| 
       20 
     | 
    
         
            -
                # any row_proc  
     | 
| 
       21 
     | 
    
         
            -
                # you use with graph.
         
     | 
| 
      
 20 
     | 
    
         
            +
                # any row_proc of the current dataset and the datasets you use with graph.
         
     | 
| 
       22 
21 
     | 
    
         
             
                #
         
     | 
| 
       23 
22 
     | 
    
         
             
                # If you are graphing a table and all columns for that table are nil, this
         
     | 
| 
       24 
23 
     | 
    
         
             
                # indicates that no matching rows existed in the table, so graph will return nil
         
     | 
| 
         @@ -186,7 +185,7 @@ module Sequel 
     | 
|
| 
       186 
185 
     | 
    
         
             
                # Fetch the rows, split them into component table parts,
         
     | 
| 
       187 
186 
     | 
    
         
             
                # tranform and run the row_proc on each part (if applicable),
         
     | 
| 
       188 
187 
     | 
    
         
             
                # and yield a hash of the parts.
         
     | 
| 
       189 
     | 
    
         
            -
                def graph_each 
     | 
| 
      
 188 
     | 
    
         
            +
                def graph_each
         
     | 
| 
       190 
189 
     | 
    
         
             
                  # Reject tables with nil datasets, as they are excluded from
         
     | 
| 
       191 
190 
     | 
    
         
             
                  # the result set
         
     | 
| 
       192 
191 
     | 
    
         
             
                  datasets = @opts[:graph][:table_aliases].to_a.reject{|ta,ds| ds.nil?}
         
     | 
| 
         @@ -194,13 +193,11 @@ module Sequel 
     | 
|
| 
       194 
193 
     | 
    
         
             
                  table_aliases = datasets.collect{|ta,ds| ta}
         
     | 
| 
       195 
194 
     | 
    
         
             
                  # Get an array of arrays, one for each dataset, with
         
     | 
| 
       196 
195 
     | 
    
         
             
                  # the necessary information about each dataset, for speed
         
     | 
| 
       197 
     | 
    
         
            -
                  datasets = datasets.collect  
     | 
| 
       198 
     | 
    
         
            -
                    [ta, ds, ds.instance_variable_get(:@transform), ds.row_proc]
         
     | 
| 
       199 
     | 
    
         
            -
                  end
         
     | 
| 
      
 196 
     | 
    
         
            +
                  datasets = datasets.collect{|ta, ds| [ta, ds, ds.row_proc]}
         
     | 
| 
       200 
197 
     | 
    
         
             
                  # Use the manually set graph aliases, if any, otherwise
         
     | 
| 
       201 
198 
     | 
    
         
             
                  # use the ones automatically created by .graph
         
     | 
| 
       202 
199 
     | 
    
         
             
                  column_aliases = @opts[:graph_aliases] || @opts[:graph][:column_aliases]
         
     | 
| 
       203 
     | 
    
         
            -
                  fetch_rows( 
     | 
| 
      
 200 
     | 
    
         
            +
                  fetch_rows(select_sql) do |r|
         
     | 
| 
       204 
201 
     | 
    
         
             
                    graph = {}
         
     | 
| 
       205 
202 
     | 
    
         
             
                    # Create the sub hashes, one per table
         
     | 
| 
       206 
203 
     | 
    
         
             
                    table_aliases.each{|ta| graph[ta]={}}
         
     | 
| 
         @@ -211,14 +208,11 @@ module Sequel 
     | 
|
| 
       211 
208 
     | 
    
         
             
                      ta, column = tc
         
     | 
| 
       212 
209 
     | 
    
         
             
                      graph[ta][column] = r[col_alias]
         
     | 
| 
       213 
210 
     | 
    
         
             
                    end
         
     | 
| 
       214 
     | 
    
         
            -
                    # For each dataset 
     | 
| 
       215 
     | 
    
         
            -
                     
     | 
| 
       216 
     | 
    
         
            -
                    datasets.each do |ta,ds,tr,rp|
         
     | 
| 
      
 211 
     | 
    
         
            +
                    # For each dataset run the row_proc if applicable
         
     | 
| 
      
 212 
     | 
    
         
            +
                    datasets.each do |ta,ds,rp|
         
     | 
| 
       217 
213 
     | 
    
         
             
                      g = graph[ta]
         
     | 
| 
       218 
214 
     | 
    
         
             
                      graph[ta] = if g.values.any?{|x| !x.nil?}
         
     | 
| 
       219 
     | 
    
         
            -
                         
     | 
| 
       220 
     | 
    
         
            -
                        g = rp[g] if rp
         
     | 
| 
       221 
     | 
    
         
            -
                        g
         
     | 
| 
      
 215 
     | 
    
         
            +
                        rp ? rp.call(g) : g
         
     | 
| 
       222 
216 
     | 
    
         
             
                      else
         
     | 
| 
       223 
217 
     | 
    
         
             
                        nil
         
     | 
| 
       224 
218 
     | 
    
         
             
                      end
         
     | 
    
        data/lib/sequel/dataset/sql.rb
    CHANGED
    
    | 
         @@ -12,7 +12,7 @@ module Sequel 
     | 
|
| 
       12 
12 
     | 
    
         
             
                N_ARITY_OPERATORS = ::Sequel::SQL::ComplexExpression::N_ARITY_OPERATORS
         
     | 
| 
       13 
13 
     | 
    
         
             
                NULL = "NULL".freeze
         
     | 
| 
       14 
14 
     | 
    
         
             
                QUESTION_MARK = '?'.freeze
         
     | 
| 
       15 
     | 
    
         
            -
                STOCK_COUNT_OPTS = {:select => [LiteralString.new("COUNT(*)").freeze], :order => nil}.freeze
         
     | 
| 
      
 15 
     | 
    
         
            +
                STOCK_COUNT_OPTS = {:select => [SQL::AliasedExpression.new(LiteralString.new("COUNT(*)").freeze, :count)], :order => nil}.freeze
         
     | 
| 
       16 
16 
     | 
    
         
             
                SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit'.freeze
         
     | 
| 
       17 
17 
     | 
    
         
             
                TWO_ARITY_OPERATORS = ::Sequel::SQL::ComplexExpression::TWO_ARITY_OPERATORS
         
     | 
| 
       18 
18 
     | 
    
         
             
                WILDCARD = '*'.freeze
         
     | 
| 
         @@ -49,7 +49,7 @@ module Sequel 
     | 
|
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
                # SQL fragment for the SQL CAST expression.
         
     | 
| 
       51 
51 
     | 
    
         
             
                def cast_sql(expr, type)
         
     | 
| 
       52 
     | 
    
         
            -
                  "CAST(#{literal(expr)} AS #{db. 
     | 
| 
      
 52 
     | 
    
         
            +
                  "CAST(#{literal(expr)} AS #{db.cast_type_literal(type)})"
         
     | 
| 
       53 
53 
     | 
    
         
             
                end
         
     | 
| 
       54 
54 
     | 
    
         | 
| 
       55 
55 
     | 
    
         
             
                # SQL fragment for specifying all columns in a given table.
         
     | 
| 
         @@ -87,9 +87,8 @@ module Sequel 
     | 
|
| 
       87 
87 
     | 
    
         
             
                # 
         
     | 
| 
       88 
88 
     | 
    
         
             
                #   dataset.filter{|o| o.price >= 100}.delete_sql #=>
         
     | 
| 
       89 
89 
     | 
    
         
             
                #     "DELETE FROM items WHERE (price >= 100)"
         
     | 
| 
       90 
     | 
    
         
            -
                def delete_sql 
     | 
| 
       91 
     | 
    
         
            -
                   
     | 
| 
       92 
     | 
    
         
            -
                  opts = opts ? @opts.merge(opts) : @opts
         
     | 
| 
      
 90 
     | 
    
         
            +
                def delete_sql
         
     | 
| 
      
 91 
     | 
    
         
            +
                  opts = @opts
         
     | 
| 
       93 
92 
     | 
    
         | 
| 
       94 
93 
     | 
    
         
             
                  return static_sql(opts[:sql]) if opts[:sql]
         
     | 
| 
       95 
94 
     | 
    
         | 
| 
         @@ -136,7 +135,6 @@ module Sequel 
     | 
|
| 
       136 
135 
     | 
    
         
             
                def exclude(*cond, &block)
         
     | 
| 
       137 
136 
     | 
    
         
             
                  clause = (@opts[:having] ? :having : :where)
         
     | 
| 
       138 
137 
     | 
    
         
             
                  cond = cond.first if cond.size == 1
         
     | 
| 
       139 
     | 
    
         
            -
                  cond = SQL::BooleanExpression.from_value_pairs(cond, :OR) if Sequel.condition_specifier?(cond)
         
     | 
| 
       140 
138 
     | 
    
         
             
                  cond = filter_expr(cond, &block)
         
     | 
| 
       141 
139 
     | 
    
         
             
                  cond = SQL::BooleanExpression.invert(cond)
         
     | 
| 
       142 
140 
     | 
    
         
             
                  cond = SQL::BooleanExpression.new(:AND, @opts[clause], cond) if @opts[clause]
         
     | 
| 
         @@ -147,9 +145,8 @@ module Sequel 
     | 
|
| 
       147 
145 
     | 
    
         
             
                #
         
     | 
| 
       148 
146 
     | 
    
         
             
                #   DB.select(1).where(DB[:items].exists).sql
         
     | 
| 
       149 
147 
     | 
    
         
             
                #   #=> "SELECT 1 WHERE EXISTS (SELECT * FROM items)"
         
     | 
| 
       150 
     | 
    
         
            -
                def exists 
     | 
| 
       151 
     | 
    
         
            -
                   
     | 
| 
       152 
     | 
    
         
            -
                  LiteralString.new("EXISTS (#{defarg ? select_sql : select_sql(opts)})")
         
     | 
| 
      
 148 
     | 
    
         
            +
                def exists
         
     | 
| 
      
 149 
     | 
    
         
            +
                  LiteralString.new("EXISTS (#{select_sql})")
         
     | 
| 
       153 
150 
     | 
    
         
             
                end
         
     | 
| 
       154 
151 
     | 
    
         | 
| 
       155 
152 
     | 
    
         
             
                # Returns a copy of the dataset with the given conditions imposed upon it.  
         
     | 
| 
         @@ -223,10 +220,11 @@ module Sequel 
     | 
|
| 
       223 
220 
     | 
    
         | 
| 
       224 
221 
     | 
    
         
             
                # Returns a copy of the dataset with the source changed.
         
     | 
| 
       225 
222 
     | 
    
         
             
                #
         
     | 
| 
      
 223 
     | 
    
         
            +
                #   dataset.from # SQL: SELECT *
         
     | 
| 
       226 
224 
     | 
    
         
             
                #   dataset.from(:blah) # SQL: SELECT * FROM blah
         
     | 
| 
       227 
225 
     | 
    
         
             
                #   dataset.from(:blah, :foo) # SQL: SELECT * FROM blah, foo
         
     | 
| 
       228 
226 
     | 
    
         
             
                def from(*source)
         
     | 
| 
       229 
     | 
    
         
            -
                  clone(:from 
     | 
| 
      
 227 
     | 
    
         
            +
                  clone(:from=>source.empty? ? nil : source)
         
     | 
| 
       230 
228 
     | 
    
         
             
                end
         
     | 
| 
       231 
229 
     | 
    
         | 
| 
       232 
230 
     | 
    
         
             
                # Returns a dataset selecting from the current dataset.
         
     | 
| 
         @@ -324,7 +322,6 @@ module Sequel 
     | 
|
| 
       324 
322 
     | 
    
         
             
                  when Hash
         
     | 
| 
       325 
323 
     | 
    
         
             
                    values = @opts[:defaults].merge(values) if @opts[:defaults]
         
     | 
| 
       326 
324 
     | 
    
         
             
                    values = values.merge(@opts[:overrides]) if @opts[:overrides]
         
     | 
| 
       327 
     | 
    
         
            -
                    values = transform_save(values) if @transform
         
     | 
| 
       328 
325 
     | 
    
         
             
                    if values.empty?
         
     | 
| 
       329 
326 
     | 
    
         
             
                      insert_default_values_sql
         
     | 
| 
       330 
327 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -362,11 +359,6 @@ module Sequel 
     | 
|
| 
       362 
359 
     | 
    
         
             
                  clone(o)
         
     | 
| 
       363 
360 
     | 
    
         
             
                end
         
     | 
| 
       364 
361 
     | 
    
         | 
| 
       365 
     | 
    
         
            -
                # SQL fragment specifying an Irregular (cast/extract) SQL function call
         
     | 
| 
       366 
     | 
    
         
            -
                def irregular_function_sql(f)
         
     | 
| 
       367 
     | 
    
         
            -
                  "#{f.f}(#{literal(f.arg1)} #{f.joiner} #{literal(f.arg2)})"
         
     | 
| 
       368 
     | 
    
         
            -
                end
         
     | 
| 
       369 
     | 
    
         
            -
             
     | 
| 
       370 
362 
     | 
    
         
             
                # SQL fragment specifying a JOIN clause without ON or USING.
         
     | 
| 
       371 
363 
     | 
    
         
             
                def join_clause_sql(jc)
         
     | 
| 
       372 
364 
     | 
    
         
             
                  table = jc.table
         
     | 
| 
         @@ -608,6 +600,7 @@ module Sequel 
     | 
|
| 
       608 
600 
     | 
    
         
             
                # quote the name with quoted_identifier.
         
     | 
| 
       609 
601 
     | 
    
         
             
                def quote_identifier(name)
         
     | 
| 
       610 
602 
     | 
    
         
             
                  return name if name.is_a?(LiteralString)
         
     | 
| 
      
 603 
     | 
    
         
            +
                  name = name.value if name.is_a?(SQL::Identifier)
         
     | 
| 
       611 
604 
     | 
    
         
             
                  name = input_identifier(name)
         
     | 
| 
       612 
605 
     | 
    
         
             
                  name = quoted_identifier(name) if quote_identifiers?
         
     | 
| 
       613 
606 
     | 
    
         
             
                  name
         
     | 
| 
         @@ -683,24 +676,21 @@ module Sequel 
     | 
|
| 
       683 
676 
     | 
    
         
             
                # Formats a SELECT statement
         
     | 
| 
       684 
677 
     | 
    
         
             
                #
         
     | 
| 
       685 
678 
     | 
    
         
             
                #   dataset.select_sql # => "SELECT * FROM items"
         
     | 
| 
       686 
     | 
    
         
            -
                def select_sql 
     | 
| 
       687 
     | 
    
         
            -
                   
     | 
| 
       688 
     | 
    
         
            -
                  opts = opts ? @opts.merge(opts) : @opts
         
     | 
| 
       689 
     | 
    
         
            -
                  return static_sql(opts[:sql]) if opts[:sql]
         
     | 
| 
      
 679 
     | 
    
         
            +
                def select_sql
         
     | 
| 
      
 680 
     | 
    
         
            +
                  return static_sql(@opts[:sql]) if @opts[:sql]
         
     | 
| 
       690 
681 
     | 
    
         
             
                  sql = 'SELECT'
         
     | 
| 
       691 
     | 
    
         
            -
                  select_clause_order.each{|x| send("select_#{x}_sql", sql 
     | 
| 
      
 682 
     | 
    
         
            +
                  select_clause_order.each{|x| send(:"select_#{x}_sql", sql)}
         
     | 
| 
       692 
683 
     | 
    
         
             
                  sql
         
     | 
| 
       693 
684 
     | 
    
         
             
                end
         
     | 
| 
       694 
685 
     | 
    
         | 
| 
       695 
686 
     | 
    
         
             
                # Same as select_sql, not aliased directly to make subclassing simpler.
         
     | 
| 
       696 
     | 
    
         
            -
                def sql 
     | 
| 
       697 
     | 
    
         
            -
                   
     | 
| 
       698 
     | 
    
         
            -
                  defarg ? select_sql : select_sql(opts)
         
     | 
| 
      
 687 
     | 
    
         
            +
                def sql
         
     | 
| 
      
 688 
     | 
    
         
            +
                  select_sql
         
     | 
| 
       699 
689 
     | 
    
         
             
                end
         
     | 
| 
       700 
690 
     | 
    
         | 
| 
       701 
691 
     | 
    
         
             
                # SQL fragment for specifying subscripts (SQL arrays)
         
     | 
| 
       702 
692 
     | 
    
         
             
                def subscript_sql(s)
         
     | 
| 
       703 
     | 
    
         
            -
                  "#{s.f}[#{s.sub.join(COMMA_SEPARATOR)}]"
         
     | 
| 
      
 693 
     | 
    
         
            +
                  "#{literal(s.f)}[#{s.sub.join(COMMA_SEPARATOR)}]"
         
     | 
| 
       704 
694 
     | 
    
         
             
                end
         
     | 
| 
       705 
695 
     | 
    
         | 
| 
       706 
696 
     | 
    
         
             
                # Returns a copy of the dataset with no filters (HAVING or WHERE clause) applied.
         
     | 
| 
         @@ -733,9 +723,8 @@ module Sequel 
     | 
|
| 
       733 
723 
     | 
    
         
             
                #
         
     | 
| 
       734 
724 
     | 
    
         
             
                # Raises an error if the dataset is grouped or includes more
         
     | 
| 
       735 
725 
     | 
    
         
             
                # than one table.
         
     | 
| 
       736 
     | 
    
         
            -
                def update_sql(values = {} 
     | 
| 
       737 
     | 
    
         
            -
                   
     | 
| 
       738 
     | 
    
         
            -
                  opts = opts ? @opts.merge(opts) : @opts
         
     | 
| 
      
 726 
     | 
    
         
            +
                def update_sql(values = {})
         
     | 
| 
      
 727 
     | 
    
         
            +
                  opts = @opts
         
     | 
| 
       739 
728 
     | 
    
         | 
| 
       740 
729 
     | 
    
         
             
                  return static_sql(opts[:sql]) if opts[:sql]
         
     | 
| 
       741 
730 
     | 
    
         | 
| 
         @@ -750,7 +739,6 @@ module Sequel 
     | 
|
| 
       750 
739 
     | 
    
         
             
                    values = opts[:defaults].merge(values) if opts[:defaults]
         
     | 
| 
       751 
740 
     | 
    
         
             
                    values = values.merge(opts[:overrides]) if opts[:overrides]
         
     | 
| 
       752 
741 
     | 
    
         
             
                    # get values from hash
         
     | 
| 
       753 
     | 
    
         
            -
                    values = transform_save(values) if @transform
         
     | 
| 
       754 
742 
     | 
    
         
             
                    values.map do |k, v|
         
     | 
| 
       755 
743 
     | 
    
         
             
                      "#{[String, Symbol].any?{|c| k.is_a?(c)} ? quote_identifier(k) : literal(k)} = #{literal(v)}"
         
     | 
| 
       756 
744 
     | 
    
         
             
                    end.join(COMMA_SEPARATOR)
         
     | 
| 
         @@ -775,7 +763,7 @@ module Sequel 
     | 
|
| 
       775 
763 
     | 
    
         
             
                end
         
     | 
| 
       776 
764 
     | 
    
         | 
| 
       777 
765 
     | 
    
         
             
                # Returns a copy of the dataset with the static SQL used.  This is useful if you want
         
     | 
| 
       778 
     | 
    
         
            -
                # to keep the same row_proc/ 
     | 
| 
      
 766 
     | 
    
         
            +
                # to keep the same row_proc/graph, but change the SQL used to custom SQL.
         
     | 
| 
       779 
767 
     | 
    
         
             
                #
         
     | 
| 
       780 
768 
     | 
    
         
             
                #   dataset.with_sql('SELECT * FROM foo') # SELECT * FROM foo
         
     | 
| 
       781 
769 
     | 
    
         
             
                def with_sql(sql, *args)
         
     | 
| 
         @@ -802,7 +790,6 @@ module Sequel 
     | 
|
| 
       802 
790 
     | 
    
         
             
                # Internal filter method so it works on either the having or where clauses.
         
     | 
| 
       803 
791 
     | 
    
         
             
                def _filter(clause, *cond, &block)
         
     | 
| 
       804 
792 
     | 
    
         
             
                  cond = cond.first if cond.size == 1
         
     | 
| 
       805 
     | 
    
         
            -
                  cond = transform_save(cond) if @transform if cond.is_a?(Hash)
         
     | 
| 
       806 
793 
     | 
    
         
             
                  cond = filter_expr(cond, &block)
         
     | 
| 
       807 
794 
     | 
    
         
             
                  cond = SQL::BooleanExpression.new(:AND, @opts[clause], cond) if @opts[clause]
         
     | 
| 
       808 
795 
     | 
    
         
             
                  clone(clause => cond)
         
     | 
| 
         @@ -851,8 +838,10 @@ module Sequel 
     | 
|
| 
       851 
838 
     | 
    
         
             
                  when Array
         
     | 
| 
       852 
839 
     | 
    
         
             
                    if String === expr[0]
         
     | 
| 
       853 
840 
     | 
    
         
             
                      SQL::PlaceholderLiteralString.new(expr.shift, expr, true)
         
     | 
| 
       854 
     | 
    
         
            -
                     
     | 
| 
      
 841 
     | 
    
         
            +
                    elsif Sequel.condition_specifier?(expr)
         
     | 
| 
       855 
842 
     | 
    
         
             
                      SQL::BooleanExpression.from_value_pairs(expr)
         
     | 
| 
      
 843 
     | 
    
         
            +
                    else
         
     | 
| 
      
 844 
     | 
    
         
            +
                      SQL::BooleanExpression.new(:AND, *expr.map{|x| filter_expr(x)})
         
     | 
| 
       856 
845 
     | 
    
         
             
                    end
         
     | 
| 
       857 
846 
     | 
    
         
             
                  when Proc
         
     | 
| 
       858 
847 
     | 
    
         
             
                    filter_expr(virtual_row_block_call(expr))
         
     | 
| 
         @@ -1021,13 +1010,13 @@ module Sequel 
     | 
|
| 
       1021 
1010 
     | 
    
         
             
                end
         
     | 
| 
       1022 
1011 
     | 
    
         | 
| 
       1023 
1012 
     | 
    
         
             
                # Modify the sql to add the columns selected
         
     | 
| 
       1024 
     | 
    
         
            -
                def select_columns_sql(sql 
     | 
| 
       1025 
     | 
    
         
            -
                  sql << " #{column_list(opts[:select])}"
         
     | 
| 
      
 1013 
     | 
    
         
            +
                def select_columns_sql(sql)
         
     | 
| 
      
 1014 
     | 
    
         
            +
                  sql << " #{column_list(@opts[:select])}"
         
     | 
| 
       1026 
1015 
     | 
    
         
             
                end
         
     | 
| 
       1027 
1016 
     | 
    
         | 
| 
       1028 
1017 
     | 
    
         
             
                # Modify the sql to add the DISTINCT modifier
         
     | 
| 
       1029 
     | 
    
         
            -
                def select_distinct_sql(sql 
     | 
| 
       1030 
     | 
    
         
            -
                  if distinct = opts[:distinct]
         
     | 
| 
      
 1018 
     | 
    
         
            +
                def select_distinct_sql(sql)
         
     | 
| 
      
 1019 
     | 
    
         
            +
                  if distinct = @opts[:distinct]
         
     | 
| 
       1031 
1020 
     | 
    
         
             
                    sql << " DISTINCT#{" ON (#{expression_list(distinct)})" unless distinct.empty?}"
         
     | 
| 
       1032 
1021 
     | 
    
         
             
                  end
         
     | 
| 
       1033 
1022 
     | 
    
         
             
                end
         
     | 
| 
         @@ -1035,9 +1024,9 @@ module Sequel 
     | 
|
| 
       1035 
1024 
     | 
    
         
             
                # Modify the sql to add a dataset to the via an EXCEPT, INTERSECT, or UNION clause.
         
     | 
| 
       1036 
1025 
     | 
    
         
             
                # This uses a subselect for the compound datasets used, because using parantheses doesn't
         
     | 
| 
       1037 
1026 
     | 
    
         
             
                # work on all databases.  I consider this an ugly hack, but can't I think of a better default.
         
     | 
| 
       1038 
     | 
    
         
            -
                def select_compounds_sql(sql 
     | 
| 
       1039 
     | 
    
         
            -
                  return unless opts[:compounds]
         
     | 
| 
       1040 
     | 
    
         
            -
                  opts[:compounds].each do |type, dataset, all|
         
     | 
| 
      
 1027 
     | 
    
         
            +
                def select_compounds_sql(sql)
         
     | 
| 
      
 1028 
     | 
    
         
            +
                  return unless @opts[:compounds]
         
     | 
| 
      
 1029 
     | 
    
         
            +
                  @opts[:compounds].each do |type, dataset, all|
         
     | 
| 
       1041 
1030 
     | 
    
         
             
                    compound_sql = subselect_sql(dataset)
         
     | 
| 
       1042 
1031 
     | 
    
         
             
                    compound_sql = "SELECT * FROM (#{compound_sql})" if dataset.opts[:compounds]
         
     | 
| 
       1043 
1032 
     | 
    
         
             
                    sql.replace("#{sql} #{type.to_s.upcase}#{' ALL' if all} #{compound_sql}")
         
     | 
| 
         @@ -1045,39 +1034,39 @@ module Sequel 
     | 
|
| 
       1045 
1034 
     | 
    
         
             
                end
         
     | 
| 
       1046 
1035 
     | 
    
         | 
| 
       1047 
1036 
     | 
    
         
             
                # Modify the sql to add the list of tables to select FROM
         
     | 
| 
       1048 
     | 
    
         
            -
                def select_from_sql(sql 
     | 
| 
       1049 
     | 
    
         
            -
                  sql << " FROM #{source_list(opts[:from])}" if opts[:from]
         
     | 
| 
      
 1037 
     | 
    
         
            +
                def select_from_sql(sql)
         
     | 
| 
      
 1038 
     | 
    
         
            +
                  sql << " FROM #{source_list(@opts[:from])}" if @opts[:from]
         
     | 
| 
       1050 
1039 
     | 
    
         
             
                end
         
     | 
| 
       1051 
1040 
     | 
    
         | 
| 
       1052 
1041 
     | 
    
         
             
                # Modify the sql to add the expressions to GROUP BY
         
     | 
| 
       1053 
     | 
    
         
            -
                def select_group_sql(sql 
     | 
| 
       1054 
     | 
    
         
            -
                  sql << " GROUP BY #{expression_list(opts[:group])}" if opts[:group]
         
     | 
| 
      
 1042 
     | 
    
         
            +
                def select_group_sql(sql)
         
     | 
| 
      
 1043 
     | 
    
         
            +
                  sql << " GROUP BY #{expression_list(@opts[:group])}" if @opts[:group]
         
     | 
| 
       1055 
1044 
     | 
    
         
             
                end
         
     | 
| 
       1056 
1045 
     | 
    
         | 
| 
       1057 
1046 
     | 
    
         
             
                # Modify the sql to add the filter criteria in the HAVING clause
         
     | 
| 
       1058 
     | 
    
         
            -
                def select_having_sql(sql 
     | 
| 
       1059 
     | 
    
         
            -
                  sql << " HAVING #{literal(opts[:having])}" if opts[:having]
         
     | 
| 
      
 1047 
     | 
    
         
            +
                def select_having_sql(sql)
         
     | 
| 
      
 1048 
     | 
    
         
            +
                  sql << " HAVING #{literal(@opts[:having])}" if @opts[:having]
         
     | 
| 
       1060 
1049 
     | 
    
         
             
                end
         
     | 
| 
       1061 
1050 
     | 
    
         | 
| 
       1062 
1051 
     | 
    
         
             
                # Modify the sql to add the list of tables to JOIN to
         
     | 
| 
       1063 
     | 
    
         
            -
                def select_join_sql(sql 
     | 
| 
       1064 
     | 
    
         
            -
                  opts[:join].each{|j| sql << literal(j)} if opts[:join]
         
     | 
| 
      
 1052 
     | 
    
         
            +
                def select_join_sql(sql)
         
     | 
| 
      
 1053 
     | 
    
         
            +
                  @opts[:join].each{|j| sql << literal(j)} if @opts[:join]
         
     | 
| 
       1065 
1054 
     | 
    
         
             
                end
         
     | 
| 
       1066 
1055 
     | 
    
         | 
| 
       1067 
1056 
     | 
    
         
             
                # Modify the sql to limit the number of rows returned and offset
         
     | 
| 
       1068 
     | 
    
         
            -
                def select_limit_sql(sql 
     | 
| 
       1069 
     | 
    
         
            -
                  sql << " LIMIT #{opts[:limit]}" if opts[:limit]
         
     | 
| 
       1070 
     | 
    
         
            -
                  sql << " OFFSET #{opts[:offset]}" if opts[:offset]
         
     | 
| 
      
 1057 
     | 
    
         
            +
                def select_limit_sql(sql)
         
     | 
| 
      
 1058 
     | 
    
         
            +
                  sql << " LIMIT #{@opts[:limit]}" if @opts[:limit]
         
     | 
| 
      
 1059 
     | 
    
         
            +
                  sql << " OFFSET #{@opts[:offset]}" if @opts[:offset]
         
     | 
| 
       1071 
1060 
     | 
    
         
             
                end
         
     | 
| 
       1072 
1061 
     | 
    
         | 
| 
       1073 
1062 
     | 
    
         
             
                # Modify the sql to add the expressions to ORDER BY
         
     | 
| 
       1074 
     | 
    
         
            -
                def select_order_sql(sql 
     | 
| 
       1075 
     | 
    
         
            -
                  sql << " ORDER BY #{expression_list(opts[:order])}" if opts[:order]
         
     | 
| 
      
 1063 
     | 
    
         
            +
                def select_order_sql(sql)
         
     | 
| 
      
 1064 
     | 
    
         
            +
                  sql << " ORDER BY #{expression_list(@opts[:order])}" if @opts[:order]
         
     | 
| 
       1076 
1065 
     | 
    
         
             
                end
         
     | 
| 
       1077 
1066 
     | 
    
         | 
| 
       1078 
1067 
     | 
    
         
             
                # Modify the sql to add the filter criteria in the WHERE clause
         
     | 
| 
       1079 
     | 
    
         
            -
                def select_where_sql(sql 
     | 
| 
       1080 
     | 
    
         
            -
                  sql << " WHERE #{literal(opts[:where])}" if opts[:where]
         
     | 
| 
      
 1068 
     | 
    
         
            +
                def select_where_sql(sql)
         
     | 
| 
      
 1069 
     | 
    
         
            +
                  sql << " WHERE #{literal(@opts[:where])}" if @opts[:where]
         
     | 
| 
       1081 
1070 
     | 
    
         
             
                end
         
     | 
| 
       1082 
1071 
     | 
    
         | 
| 
       1083 
1072 
     | 
    
         
             
                # Converts an array of source names into into a comma separated list.
         
     | 
| 
         @@ -32,7 +32,6 @@ class String 
     | 
|
| 
       32 
32 
     | 
    
         
             
                #   clear :all
         
     | 
| 
       33 
33 
     | 
    
         
             
                #   clear :plurals
         
     | 
| 
       34 
34 
     | 
    
         
             
                def self.clear(scope = :all)
         
     | 
| 
       35 
     | 
    
         
            -
                  Sequel::Inflections.clear(scope)
         
     | 
| 
       36 
35 
     | 
    
         
             
                  case scope
         
     | 
| 
       37 
36 
     | 
    
         
             
                  when :all
         
     | 
| 
       38 
37 
     | 
    
         
             
                    @plurals, @singulars, @uncountables = [], [], []
         
     | 
| 
         @@ -48,7 +47,6 @@ class String 
     | 
|
| 
       48 
47 
     | 
    
         
             
                #   irregular 'octopus', 'octopi'
         
     | 
| 
       49 
48 
     | 
    
         
             
                #   irregular 'person', 'people'
         
     | 
| 
       50 
49 
     | 
    
         
             
                def self.irregular(singular, plural)
         
     | 
| 
       51 
     | 
    
         
            -
                  Sequel::Inflections.irregular(singular, plural)
         
     | 
| 
       52 
50 
     | 
    
         
             
                  plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
         
     | 
| 
       53 
51 
     | 
    
         
             
                  singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
         
     | 
| 
       54 
52 
     | 
    
         
             
                end
         
     | 
| 
         @@ -59,7 +57,6 @@ class String 
     | 
|
| 
       59 
57 
     | 
    
         
             
                # Example:
         
     | 
| 
       60 
58 
     | 
    
         
             
                #   plural(/(x|ch|ss|sh)$/i, '\1es')
         
     | 
| 
       61 
59 
     | 
    
         
             
                def self.plural(rule, replacement)
         
     | 
| 
       62 
     | 
    
         
            -
                  Sequel::Inflections.plural(rule, replacement)
         
     | 
| 
       63 
60 
     | 
    
         
             
                  @plurals.insert(0, [rule, replacement])
         
     | 
| 
       64 
61 
     | 
    
         
             
                end
         
     | 
| 
       65 
62 
     | 
    
         | 
| 
         @@ -69,7 +66,6 @@ class String 
     | 
|
| 
       69 
66 
     | 
    
         
             
                # Example:
         
     | 
| 
       70 
67 
     | 
    
         
             
                #   singular(/([^aeiouy]|qu)ies$/i, '\1y') 
         
     | 
| 
       71 
68 
     | 
    
         
             
                def self.singular(rule, replacement)
         
     | 
| 
       72 
     | 
    
         
            -
                  Sequel::Inflections.singular(rule, replacement)
         
     | 
| 
       73 
69 
     | 
    
         
             
                  @singulars.insert(0, [rule, replacement])
         
     | 
| 
       74 
70 
     | 
    
         
             
                end
         
     | 
| 
       75 
71 
     | 
    
         | 
| 
         @@ -80,7 +76,6 @@ class String 
     | 
|
| 
       80 
76 
     | 
    
         
             
                #   uncountable "money", "information"
         
     | 
| 
       81 
77 
     | 
    
         
             
                #   uncountable %w( money information rice )
         
     | 
| 
       82 
78 
     | 
    
         
             
                def self.uncountable(*words)
         
     | 
| 
       83 
     | 
    
         
            -
                  Sequel::Inflections.uncountable(*words)
         
     | 
| 
       84 
79 
     | 
    
         
             
                  (@uncountables << words).flatten!
         
     | 
| 
       85 
80 
     | 
    
         
             
                end
         
     | 
| 
       86 
81 
     | 
    
         | 
| 
         @@ -0,0 +1,238 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Sequel
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Database
         
     | 
| 
      
 3 
     | 
    
         
            +
                # Dump indexes for all tables as a migration.  This complements
         
     | 
| 
      
 4 
     | 
    
         
            +
                # the :indexes=>false option to dump_schema_migration.
         
     | 
| 
      
 5 
     | 
    
         
            +
                def dump_indexes_migration
         
     | 
| 
      
 6 
     | 
    
         
            +
                  ts = tables
         
     | 
| 
      
 7 
     | 
    
         
            +
                  <<END_MIG
         
     | 
| 
      
 8 
     | 
    
         
            +
            Class.new(Sequel::Migration) do
         
     | 
| 
      
 9 
     | 
    
         
            +
              def up
         
     | 
| 
      
 10 
     | 
    
         
            +
            #{ts.map{|t| dump_table_indexes(t, :add_index)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, '    ')}
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
              
         
     | 
| 
      
 13 
     | 
    
         
            +
              def down
         
     | 
| 
      
 14 
     | 
    
         
            +
            #{ts.map{|t| dump_table_indexes(t, :drop_index)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, '    ')}
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
      
 17 
     | 
    
         
            +
            END_MIG
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                # Return a string that contains a Sequel::Migration subclass that when
         
     | 
| 
      
 21 
     | 
    
         
            +
                # run would recreate the database structure. Options:
         
     | 
| 
      
 22 
     | 
    
         
            +
                # * :same_db - Don't attempt to translate database types to ruby types.
         
     | 
| 
      
 23 
     | 
    
         
            +
                #   If this isn't set to true, all database types will be translated to
         
     | 
| 
      
 24 
     | 
    
         
            +
                #   ruby types, but there is no guarantee that the migration generated
         
     | 
| 
      
 25 
     | 
    
         
            +
                #   will yield the same type.  Without this set, types that aren't
         
     | 
| 
      
 26 
     | 
    
         
            +
                #   recognized will be translated to a string-like type.
         
     | 
| 
      
 27 
     | 
    
         
            +
                # * :indexes - If set to false, don't dump indexes (they can be added
         
     | 
| 
      
 28 
     | 
    
         
            +
                #   later via dump_index_migration).
         
     | 
| 
      
 29 
     | 
    
         
            +
                def dump_schema_migration(options={})
         
     | 
| 
      
 30 
     | 
    
         
            +
                  ts = tables
         
     | 
| 
      
 31 
     | 
    
         
            +
                  <<END_MIG
         
     | 
| 
      
 32 
     | 
    
         
            +
            Class.new(Sequel::Migration) do
         
     | 
| 
      
 33 
     | 
    
         
            +
              def up
         
     | 
| 
      
 34 
     | 
    
         
            +
            #{ts.map{|t| dump_table_schema(t, options)}.join("\n\n").gsub(/^/o, '    ')}
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
              
         
     | 
| 
      
 37 
     | 
    
         
            +
              def down
         
     | 
| 
      
 38 
     | 
    
         
            +
                drop_table(#{ts.inspect[1...-1]})
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
      
 41 
     | 
    
         
            +
            END_MIG
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                # Return a string with a create table block that will recreate the given
         
     | 
| 
      
 45 
     | 
    
         
            +
                # table's schema.  Takes the same options as dump_schema_migration.
         
     | 
| 
      
 46 
     | 
    
         
            +
                def dump_table_schema(table, options={})
         
     | 
| 
      
 47 
     | 
    
         
            +
                  s = schema(table).dup
         
     | 
| 
      
 48 
     | 
    
         
            +
                  pks = s.find_all{|x| x.last[:primary_key] == true}.map{|x| x.first}
         
     | 
| 
      
 49 
     | 
    
         
            +
                  options = options.merge(:single_pk=>true) if pks.length == 1
         
     | 
| 
      
 50 
     | 
    
         
            +
                  m = method(:column_schema_to_generator_opts)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  im = method(:index_to_generator_opts)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  indexes = indexes(table).sort_by{|k,v| k.to_s} if options[:indexes] != false and respond_to?(:indexes)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  gen = Schema::Generator.new(self) do
         
     | 
| 
      
 54 
     | 
    
         
            +
                    s.each{|name, info| send(*m.call(name, info, options))}
         
     | 
| 
      
 55 
     | 
    
         
            +
                    primary_key(pks) if !@primary_key && pks.length > 0
         
     | 
| 
      
 56 
     | 
    
         
            +
                    indexes.each{|iname, iopts| send(:index, iopts[:columns], im.call(table, iname, iopts))} if indexes
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                  commands = [gen.dump_columns, gen.dump_constraints, gen.dump_indexes].reject{|x| x == ''}.join("\n\n")
         
     | 
| 
      
 59 
     | 
    
         
            +
                  "create_table(#{table.inspect}) do\n#{commands.gsub(/^/o, '  ')}\nend"
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                private
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                # Convert the given default, which should be a database specific string, into
         
     | 
| 
      
 65 
     | 
    
         
            +
                # a ruby object.  If it can't be converted, return the string with the inspect
         
     | 
| 
      
 66 
     | 
    
         
            +
                # method modified so that .lit is always appended after it.
         
     | 
| 
      
 67 
     | 
    
         
            +
                def column_schema_to_ruby_default(default, type)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  case default 
         
     | 
| 
      
 69 
     | 
    
         
            +
                  when /false/
         
     | 
| 
      
 70 
     | 
    
         
            +
                    false
         
     | 
| 
      
 71 
     | 
    
         
            +
                  when 'true'
         
     | 
| 
      
 72 
     | 
    
         
            +
                    true
         
     | 
| 
      
 73 
     | 
    
         
            +
                  when /\A\d+\z/
         
     | 
| 
      
 74 
     | 
    
         
            +
                    default.to_i
         
     | 
| 
      
 75 
     | 
    
         
            +
                  else
         
     | 
| 
      
 76 
     | 
    
         
            +
                    def default.inspect
         
     | 
| 
      
 77 
     | 
    
         
            +
                      "#{super}.lit"
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
                    default
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                # Convert the given name and parsed database schema into an array with a method
         
     | 
| 
      
 84 
     | 
    
         
            +
                # name and arguments to it to pass to a Schema::Generator to recreate the column.
         
     | 
| 
      
 85 
     | 
    
         
            +
                def column_schema_to_generator_opts(name, schema, options)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  if options[:single_pk] && schema_autoincrementing_primary_key?(schema)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    [:primary_key, name]
         
     | 
| 
      
 88 
     | 
    
         
            +
                  else
         
     | 
| 
      
 89 
     | 
    
         
            +
                    col_opts = options[:same_db] ? {:type=>schema[:db_type]} : column_schema_to_ruby_type(schema)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    type = col_opts.delete(:type)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    col_opts.delete(:size) if col_opts[:size].nil?
         
     | 
| 
      
 92 
     | 
    
         
            +
                    col_opts[:default] = column_schema_to_ruby_default(schema[:default], type) if schema[:default]
         
     | 
| 
      
 93 
     | 
    
         
            +
                    col_opts[:null] = false if schema[:allow_null] == false
         
     | 
| 
      
 94 
     | 
    
         
            +
                    [:column, name, type, col_opts]
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                # Convert the column schema information to a hash of column options, one of which must
         
     | 
| 
      
 99 
     | 
    
         
            +
                # be :type.  The other options added should modify that type (e.g. :size).  If a
         
     | 
| 
      
 100 
     | 
    
         
            +
                # database type is not recognized, return it as a String type.
         
     | 
| 
      
 101 
     | 
    
         
            +
                def column_schema_to_ruby_type(schema)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  case t = schema[:db_type].downcase
         
     | 
| 
      
 103 
     | 
    
         
            +
                  when /\A(?:medium|small)?int(?:eger)?(?:\((?:\d+)\))?\z/o
         
     | 
| 
      
 104 
     | 
    
         
            +
                    {:type=>Integer}
         
     | 
| 
      
 105 
     | 
    
         
            +
                  when /\Atinyint(?:\((?:\d+)\))?\z/o
         
     | 
| 
      
 106 
     | 
    
         
            +
                    {:type=>(Sequel.convert_tinyint_to_bool ? TrueClass : Integer)}
         
     | 
| 
      
 107 
     | 
    
         
            +
                  when /\Abigint(?:\((?:\d+)\))?\z/o
         
     | 
| 
      
 108 
     | 
    
         
            +
                    {:type=>Bignum}
         
     | 
| 
      
 109 
     | 
    
         
            +
                  when /\A(?:real|float|double(?: precision)?)\z/o
         
     | 
| 
      
 110 
     | 
    
         
            +
                    {:type=>Float}
         
     | 
| 
      
 111 
     | 
    
         
            +
                  when 'boolean'
         
     | 
| 
      
 112 
     | 
    
         
            +
                    {:type=>TrueClass}
         
     | 
| 
      
 113 
     | 
    
         
            +
                  when /\A(?:(?:tiny|medium|long)?text|clob)\z/o
         
     | 
| 
      
 114 
     | 
    
         
            +
                    {:type=>String, :text=>true}
         
     | 
| 
      
 115 
     | 
    
         
            +
                  when 'date'
         
     | 
| 
      
 116 
     | 
    
         
            +
                    {:type=>Date}
         
     | 
| 
      
 117 
     | 
    
         
            +
                  when 'datetime'
         
     | 
| 
      
 118 
     | 
    
         
            +
                    {:type=>DateTime}
         
     | 
| 
      
 119 
     | 
    
         
            +
                  when /\Atimestamp(?: with(?:out)? time zone)?\z/o
         
     | 
| 
      
 120 
     | 
    
         
            +
                    {:type=>DateTime}
         
     | 
| 
      
 121 
     | 
    
         
            +
                  when /\Atime(?: with(?:out)? time zone)?\z/o
         
     | 
| 
      
 122 
     | 
    
         
            +
                    {:type=>Time, :only_time=>true}
         
     | 
| 
      
 123 
     | 
    
         
            +
                  when /\Achar(?:acter)?(?:\((\d+)\))?\z/o
         
     | 
| 
      
 124 
     | 
    
         
            +
                    {:type=>String, :size=>($1.to_i if $1), :fixed=>true}
         
     | 
| 
      
 125 
     | 
    
         
            +
                  when /\A(?:varchar|character varying|bpchar|string)(?:\((\d+)\))?\z/o
         
     | 
| 
      
 126 
     | 
    
         
            +
                    s = ($1.to_i if $1)
         
     | 
| 
      
 127 
     | 
    
         
            +
                    {:type=>String, :size=>(s == 255 ? nil : s)}
         
     | 
| 
      
 128 
     | 
    
         
            +
                  when 'money'
         
     | 
| 
      
 129 
     | 
    
         
            +
                    {:type=>BigDecimal, :size=>[19,2]}
         
     | 
| 
      
 130 
     | 
    
         
            +
                  when /\A(?:decimal|numeric|number)(?:\((\d+)(?:,\s*(\d+))?\))?\z/o
         
     | 
| 
      
 131 
     | 
    
         
            +
                    s = [($1.to_i if $1), ($2.to_i if $2)].compact
         
     | 
| 
      
 132 
     | 
    
         
            +
                    {:type=>BigDecimal, :size=>(s.empty? ? nil : s)}
         
     | 
| 
      
 133 
     | 
    
         
            +
                  when /\A(?:bytea|(?:tiny|medium|long)?blob|(?:var)?binary)(?:\((\d+)\))?\z/o
         
     | 
| 
      
 134 
     | 
    
         
            +
                    {:type=>File, :size=>($1.to_i if $1)}
         
     | 
| 
      
 135 
     | 
    
         
            +
                  when 'year'
         
     | 
| 
      
 136 
     | 
    
         
            +
                    {:type=>Integer}
         
     | 
| 
      
 137 
     | 
    
         
            +
                  else
         
     | 
| 
      
 138 
     | 
    
         
            +
                    {:type=>String}
         
     | 
| 
      
 139 
     | 
    
         
            +
                  end
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                # Return a string that containing add_index/drop_index method calls for
         
     | 
| 
      
 143 
     | 
    
         
            +
                # creating the index migration.
         
     | 
| 
      
 144 
     | 
    
         
            +
                def dump_table_indexes(table, meth)
         
     | 
| 
      
 145 
     | 
    
         
            +
                  return '' unless respond_to?(:indexes)
         
     | 
| 
      
 146 
     | 
    
         
            +
                  im = method(:index_to_generator_opts)
         
     | 
| 
      
 147 
     | 
    
         
            +
                  indexes = indexes(table).sort_by{|k,v| k.to_s} 
         
     | 
| 
      
 148 
     | 
    
         
            +
                  gen = Schema::Generator.new(self) do
         
     | 
| 
      
 149 
     | 
    
         
            +
                    indexes.each{|iname, iopts| send(:index, iopts[:columns], im.call(table, iname, iopts))}
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
                  gen.dump_indexes(meth=>table)
         
     | 
| 
      
 152 
     | 
    
         
            +
                end
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                # Convert the parsed index information into options to the Generators index method. 
         
     | 
| 
      
 155 
     | 
    
         
            +
                def index_to_generator_opts(table, name, index_opts)
         
     | 
| 
      
 156 
     | 
    
         
            +
                  h = {}
         
     | 
| 
      
 157 
     | 
    
         
            +
                  h[:name] = name unless default_index_name(table, index_opts[:columns]) == name.to_s
         
     | 
| 
      
 158 
     | 
    
         
            +
                  h[:unique] = true if index_opts[:unique]
         
     | 
| 
      
 159 
     | 
    
         
            +
                  h
         
     | 
| 
      
 160 
     | 
    
         
            +
                end
         
     | 
| 
      
 161 
     | 
    
         
            +
              end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
              module Schema
         
     | 
| 
      
 164 
     | 
    
         
            +
                class Generator
         
     | 
| 
      
 165 
     | 
    
         
            +
                  # Dump this generator's columns to a string that could be evaled inside
         
     | 
| 
      
 166 
     | 
    
         
            +
                  # another instance to represent the same columns
         
     | 
| 
      
 167 
     | 
    
         
            +
                  def dump_columns
         
     | 
| 
      
 168 
     | 
    
         
            +
                    strings = []
         
     | 
| 
      
 169 
     | 
    
         
            +
                    cols = columns.dup
         
     | 
| 
      
 170 
     | 
    
         
            +
                    if pkn = primary_key_name
         
     | 
| 
      
 171 
     | 
    
         
            +
                      cols.delete_if{|x| x[:name] == pkn}
         
     | 
| 
      
 172 
     | 
    
         
            +
                      pk = @primary_key.dup
         
     | 
| 
      
 173 
     | 
    
         
            +
                      pkname = pk.delete(:name)
         
     | 
| 
      
 174 
     | 
    
         
            +
                      @db.serial_primary_key_options.each{|k,v| pk.delete(k) if v == pk[k]}
         
     | 
| 
      
 175 
     | 
    
         
            +
                      strings << "primary_key #{pkname.inspect}#{opts_inspect(pk)}"
         
     | 
| 
      
 176 
     | 
    
         
            +
                    end
         
     | 
| 
      
 177 
     | 
    
         
            +
                    cols.each do |c|
         
     | 
| 
      
 178 
     | 
    
         
            +
                      c = c.dup
         
     | 
| 
      
 179 
     | 
    
         
            +
                      name = c.delete(:name)
         
     | 
| 
      
 180 
     | 
    
         
            +
                      type = c.delete(:type)
         
     | 
| 
      
 181 
     | 
    
         
            +
                      opts = opts_inspect(c)
         
     | 
| 
      
 182 
     | 
    
         
            +
                      strings << if type.is_a?(Class)
         
     | 
| 
      
 183 
     | 
    
         
            +
                        "#{type.name} #{name.inspect}#{opts}"
         
     | 
| 
      
 184 
     | 
    
         
            +
                      else
         
     | 
| 
      
 185 
     | 
    
         
            +
                        "column #{name.inspect}, #{type.inspect}#{opts}"
         
     | 
| 
      
 186 
     | 
    
         
            +
                      end
         
     | 
| 
      
 187 
     | 
    
         
            +
                    end
         
     | 
| 
      
 188 
     | 
    
         
            +
                    strings.join("\n")
         
     | 
| 
      
 189 
     | 
    
         
            +
                  end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
                  # Dump this generator's constraints to a string that could be evaled inside
         
     | 
| 
      
 192 
     | 
    
         
            +
                  # another instance to represent the same constraints
         
     | 
| 
      
 193 
     | 
    
         
            +
                  def dump_constraints
         
     | 
| 
      
 194 
     | 
    
         
            +
                    constraints.map do |c|
         
     | 
| 
      
 195 
     | 
    
         
            +
                      c = c.dup
         
     | 
| 
      
 196 
     | 
    
         
            +
                      type = c.delete(:type)
         
     | 
| 
      
 197 
     | 
    
         
            +
                      case type
         
     | 
| 
      
 198 
     | 
    
         
            +
                      when :check
         
     | 
| 
      
 199 
     | 
    
         
            +
                        raise(Error, "can't dump check/constraint specified with Proc") if c[:check].is_a?(Proc)
         
     | 
| 
      
 200 
     | 
    
         
            +
                        name = c.delete(:name)
         
     | 
| 
      
 201 
     | 
    
         
            +
                        if !name and c[:check].length == 1 and c[:check].first.is_a?(Hash)
         
     | 
| 
      
 202 
     | 
    
         
            +
                          "check #{c[:check].first.inspect[1...-1]}"
         
     | 
| 
      
 203 
     | 
    
         
            +
                        else
         
     | 
| 
      
 204 
     | 
    
         
            +
                          "#{name ? "constraint #{name.inspect}," : 'check'} #{c[:check].map{|x| x.inspect}.join(', ')}"
         
     | 
| 
      
 205 
     | 
    
         
            +
                        end
         
     | 
| 
      
 206 
     | 
    
         
            +
                      else
         
     | 
| 
      
 207 
     | 
    
         
            +
                        cols = c.delete(:columns)
         
     | 
| 
      
 208 
     | 
    
         
            +
                        "#{type} #{cols.inspect}#{opts_inspect(c)}"
         
     | 
| 
      
 209 
     | 
    
         
            +
                      end
         
     | 
| 
      
 210 
     | 
    
         
            +
                    end.join("\n")
         
     | 
| 
      
 211 
     | 
    
         
            +
                  end
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                  # Dump this generator's indexes to a string that could be evaled inside
         
     | 
| 
      
 214 
     | 
    
         
            +
                  # another instance to represent the same indexes. Options:
         
     | 
| 
      
 215 
     | 
    
         
            +
                  # * :add_index - Use add_index instead of index, so the methods
         
     | 
| 
      
 216 
     | 
    
         
            +
                  #   can be called outside of a generator but inside a migration.
         
     | 
| 
      
 217 
     | 
    
         
            +
                  #   The value of this option should be the table name to use.
         
     | 
| 
      
 218 
     | 
    
         
            +
                  # * :drop_index - Same as add_index, but create drop_index statements.
         
     | 
| 
      
 219 
     | 
    
         
            +
                  def dump_indexes(options={})
         
     | 
| 
      
 220 
     | 
    
         
            +
                    indexes.map do |c|
         
     | 
| 
      
 221 
     | 
    
         
            +
                      c = c.dup
         
     | 
| 
      
 222 
     | 
    
         
            +
                      cols = c.delete(:columns)
         
     | 
| 
      
 223 
     | 
    
         
            +
                      if table = options[:add_index] || options[:drop_index]
         
     | 
| 
      
 224 
     | 
    
         
            +
                        "#{options[:drop_index] ? 'drop' : 'add'}_index #{table.inspect}, #{cols.inspect}#{opts_inspect(c)}"
         
     | 
| 
      
 225 
     | 
    
         
            +
                      else
         
     | 
| 
      
 226 
     | 
    
         
            +
                        "index #{cols.inspect}#{opts_inspect(c)}"
         
     | 
| 
      
 227 
     | 
    
         
            +
                      end
         
     | 
| 
      
 228 
     | 
    
         
            +
                    end.join("\n")
         
     | 
| 
      
 229 
     | 
    
         
            +
                  end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                  private
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                  def opts_inspect(opts)
         
     | 
| 
      
 234 
     | 
    
         
            +
                    ", #{opts.inspect[1...-1]}" if opts.length > 0
         
     | 
| 
      
 235 
     | 
    
         
            +
                  end
         
     | 
| 
      
 236 
     | 
    
         
            +
                end
         
     | 
| 
      
 237 
     | 
    
         
            +
              end
         
     | 
| 
      
 238 
     | 
    
         
            +
            end
         
     |