1. 05 5月, 2020 2 次提交
    • R
      Fix `rewhere` to truly overwrite collided where clause by new where clause · 6187b713
      Ryuta Kamizono 提交于
      ```ruby
      steve = Person.find_by(name: "Steve")
      david = Author.find_by(name: "David")
      
      relation = Essay.where(writer: steve)
      
      # Before
      relation.rewhere(writer: david).to_a # => []
      
      # After
      relation.rewhere(writer: david).to_a # => [david]
      ```
      
      For now `rewhere` only works for truly column names, doesn't work for
      alias attributes, nested conditions, associations.
      
      To fix that, need to build new where clause first, and then get
      attribute names from new where clause.
      6187b713
    • A
      Inspect time attributes with subsec · a3f4202c
      akinomaeni 提交于
      before
      ```
      p Knot.create
      => #<Knot id: 1, created_at: "2016-05-05 01:29:47">
      ```
      
      after
      ```
      p Knot.create
      => #<Knot id: 1, created_at: "2016-05-05 01:29:47.116928000">
      ```
      a3f4202c
  2. 04 5月, 2020 1 次提交
  3. 03 5月, 2020 4 次提交
  4. 02 5月, 2020 4 次提交
  5. 01 5月, 2020 5 次提交
    • R
      Remove internal `without_transaction_enrollment` callbacks · 75873d8f
      Ryuta Kamizono 提交于
      I've found the internal `without_transaction_enrollment` callbacks which
      have not been newly used over five years, when I tried to work reverting
      #9068 (https://github.com/rails/rails/pull/36049#issuecomment-487318060).
      
      I think that we will never make that callbacks public, since the
      mechanism of `without_transaction_enrollment` is too implementation
      specific, at least before #9068, records in a transaction had enrolled
      all into the transaction.
      
      That callbacks was introduced at #18936 to make `touch_later` #19324,
      but I think that the internal callbacks is overkill to just make the
      `touch_later` only, and invoking the extra callbacks also have a little
      overhead even if we haven't used that.
      
      So I think we can remove the internal callbacks for now, until we will
      come up with a good use for that callbacks.
      75873d8f
    • J
      Also batch attribute readers and writers · d12418a7
      Jean Boussier 提交于
      d12418a7
    • R
      Avoid quite useless loop in `find_by_sql` · 71e45582
      Ryuta Kamizono 提交于
      `column_types` is empty except PostgreSQL adapter, and
      `attribute_types.each_key { |k| column_types.delete k }` is also empty
      even if PostgreSQL adapter almost all case, so that code is quite
      useless. This improves performance for `find_by_sql` to avoid that
      useless loop as much as possible.
      
      ```ruby
      ActiveRecord::Schema.define do
        create_table :active_storage_blobs do |t|
          t.string   :key,          null: false
          t.string   :filename,     null: false
          t.string   :content_type
          t.text     :metadata
          t.string   :service_name, null: false
          t.bigint   :byte_size,    null: false
          t.string   :checksum,     null: false
          t.datetime :created_at,   null: false
      
          t.index [ :key ], unique: true
        end
      end
      
      class ActiveStorageBlob < ActiveRecord::Base
      end
      
      Benchmark.ips do |x|
        x.report("find_by") { ActiveStorageBlob.find_by(id: 1) }
      end
      ```
      
      Before:
      
      ```
      Warming up --------------------------------------
                   find_by     1.256k i/100ms
      Calculating -------------------------------------
                   find_by     12.595k (± 3.4%) i/s -     64.056k in   5.091599s
      ```
      
      After:
      
      ```
      Warming up --------------------------------------
                   find_by     1.341k i/100ms
      Calculating -------------------------------------
                   find_by     13.170k (± 3.5%) i/s -     67.050k in   5.097439s
      ```
      
      To avoid column types loop for PostgreSQL adapter, this skips returning
      additional column types if a column has already been type casted by pg
      decoders. Fortunately this fixes #36186 partly for common types.
      71e45582
    • R
      Replace `result_as_array` by type mapping · 348e142b
      Ryuta Kamizono 提交于
      348e142b
    • R
      Should not rely on the global `Arel::Table.engine` in the framework · bc99e401
      Ryuta Kamizono 提交于
      Relying on the `Arel::Table.engine` is convenient if an app have only a
      single kind of database, but if not so, the global state is not always
      the same with the current connection.
      bc99e401
  6. 30 4月, 2020 1 次提交
    • R
      Deprecate `allowed_index_name_length` in `DatabaseLimits` · ab2d859e
      Ryuta Kamizono 提交于
      `allowed_index_name_length` was used for internal temporary operations
      in SQLite3, since index name in SQLite3 must be globally unique and
      SQLite3 doesn't have ALTER TABLE feature (so it is emulated by creating
      temporary table with prefix).
      
      `allowed_index_name_length` was to reserve the margin for the prefix,
      but actually SQLite3 doesn't have a limitation for identifier name
      length, so the margin has removed at 36901e6e.
      
      Now `allowed_index_name_length` is no longer relied on by any adapter,
      so I'd like to remove the internal specific method which is no longer
      used.
      ab2d859e
  7. 29 4月, 2020 3 次提交
    • R
      Remove useless type cast on aggregated value · e10765cf
      Ryuta Kamizono 提交于
      Related #39039.
      
      Currently PostgreSQL adapter is the only adapter that rely on type
      casting by `result.column_types`, now the adapter can return numeric
      value without type casting by Active Record side.
      So we can remove that useless type cast on aggregated value.
      e10765cf
    • R
      Do not need `- 2` margin for `allowed_index_name_length` in SQLite3 · 36901e6e
      Ryuta Kamizono 提交于
      Actually SQLite3 doesn't have a limitation for identifier name length,
      so do not need `- 2` margin internally to perform temporary rename
      operations.
      36901e6e
    • R
      PERF: Improve performance of where when using an array of values · c3a2b54b
      Ryuta Kamizono 提交于
      This is a smaller alternative of performance improvement, without
      refactoring type casting mechanism #39009.
      
      This is relatively a smaller change (but about 40% faster than before),
      so I think this could be easier reviewed without discuss about
      refactoring type casting mechanism.
      
      This just makes `attribute.in(values)` less allocation from an array of
      casted nodes to one casted array node.
      
      ```ruby
      ids = (1..1000).each.map do |n|
        Post.create!.id
      end
      
      Benchmark.ips do |x|
        x.report("where with ids") do
          Post.where(id: ids).to_a
        end
      
        x.report("where with sanitize") do
          Post.where(ActiveRecord::Base.sanitize_sql(["id IN (?)", ids])).to_a
        end
      
        x.compare!
      end
      ```
      
      Before:
      
      ```
      Warming up --------------------------------------
            where with ids     7.000  i/100ms
       where with sanitize    13.000  i/100ms
      
      Calculating -------------------------------------
            where with ids     70.661  (± 5.7%) i/s -    357.000  in   5.072771s
       where with sanitize    130.993  (± 7.6%) i/s -    663.000  in   5.096085s
      
      Comparison:
       where with sanitize:      131.0 i/s
            where with ids:       70.7 i/s - 1.85x  slower
      ```
      
      After:
      
      ```
      Warming up --------------------------------------
            where with ids    10.000  i/100ms
       where with sanitize    13.000  i/100ms
      
      Calculating -------------------------------------
            where with ids     98.174  (± 7.1%) i/s -    490.000  in   5.012851s
       where with sanitize    132.289  (± 8.3%) i/s -    663.000  in   5.052728s
      
      Comparison:
       where with sanitize:      132.3 i/s
            where with ids:       98.2 i/s - 1.35x  slower
      ```
      c3a2b54b
  8. 28 4月, 2020 2 次提交
    • R
      Improve performance for `scope_for_create` · b66235d4
      Ryuta Kamizono 提交于
      ```ruby
      class Post < ActiveRecord::Base
      end
      
      posts = Post.where(id: 1, title: "foo")
      
      Benchmark.ips do |x|
        x.report("scope_for_create") { posts.scope_for_create }
      end
      ```
      
      Before:
      
      ```
      Warming up --------------------------------------
          scope_for_create    30.125k i/100ms
      Calculating -------------------------------------
          scope_for_create    334.033k (± 4.4%) i/s -      1.687M in   5.060493s
      ```
      
      After:
      
      ```
      Warming up --------------------------------------
          scope_for_create    35.088k i/100ms
      Calculating -------------------------------------
          scope_for_create    388.603k (±11.8%) i/s -      1.930M in   5.080998s
      ```
      b66235d4
    • R
      Refactor Arel node `Casted`, `Quoted`, and `BindParam` · 280d6eb2
      Ryuta Kamizono 提交于
      Define `value_for_database` and `value_before_type_cast` methods, and
      use those.
      280d6eb2
  9. 27 4月, 2020 2 次提交
  10. 26 4月, 2020 1 次提交
    • R
      More concise Arel `Or` ast and make `Or` visitor non recursive · 7d3bff1f
      Ryuta Kamizono 提交于
      Before this, 1000 `Or` nodes will raise "stack level too deep" due to
      visiting too deep Arel ast.
      
      This makes more concise Arel `Or` ast and `Or` visitor non recursive if
      `Or` nodes are adjoined, as a result, "stack level too deep" is no
      longer raised.
      
      ```ruby
      class Post < ActiveRecord::Base
      end
      
      posts = (0..500).map { |i| Post.where(id: i) }
      
      Benchmark.ips do |x|
        x.report("inject scopes") { posts.inject(&:or).to_sql }
      end
      ```
      
      Before:
      
      ```
      Warming up --------------------------------------
            where with ids     9.000  i/100ms
      Calculating -------------------------------------
            where with ids     96.126  (± 2.1%) i/s -    486.000  in   5.058960s
      ```
      
      After:
      
      ```
      Warming up --------------------------------------
             inject scopes    10.000  i/100ms
      Calculating -------------------------------------
             inject scopes    101.714  (± 2.9%) i/s -    510.000  in   5.018880s
      ```
      
      Fixes #39032.
      7d3bff1f
  11. 25 4月, 2020 3 次提交
    • R
      Improve `WhereClause#ast` to make concise Arel ast · 699b64ab
      Ryuta Kamizono 提交于
      If only one Arel node exist, wrapping a node by `And` node is obviously
      redundant, make concise Arel ast will improve performance for visiting
      the ast (about 20% faster for complex ast case).
      
      ```ruby
      class Post < ActiveRecord::Base
      end
      
      posts = (0..500).map { |i| Post.where(id: i) }
      
      Benchmark.ips do |x|
        x.report("inject scopes") { posts.inject { |res, scope| res.or(scope) }.to_sql }
      end
      ```
      
      Before:
      
      ```
      Warming up --------------------------------------
            where with ids     8.000  i/100ms
      Calculating -------------------------------------
            where with ids     80.416  (± 2.5%) i/s -    408.000  in   5.078118s
      ```
      
      After:
      
      ```
      Warming up --------------------------------------
            where with ids     9.000  i/100ms
      Calculating -------------------------------------
            where with ids     96.126  (± 2.1%) i/s -    486.000  in   5.058960s
      ```
      699b64ab
    • R
      Fix aggregate functions to return numeric value consistently even on custom attribute type · 89e1dd61
      Ryuta Kamizono 提交于
      Currently, `count` and `average` always returns numeric value, but
      `sum`, `maximum`, and `minimum` not always return numeric value if
      aggregated on custom attribute type.
      
      I think that inconsistent behavior is surprising:
      
      ```ruby
      # All adapters except postgresql adapter are affected
      # by custom type casting.
      
      Book.group(:status).sum(:status)
      # => { "proposed" => "proposed", "published" => nil }
      ```
      
      That is caused by fallback looking up cast type to `type_for(column)`.
      Now all supported adapters can return numeric value without that
      fallback, so I think we can remove that, it will also fix aggregate
      functions to return numeric value consistently.
      89e1dd61
    • R
      Support bulk insert/upsert on relation to preserve scope values · 5cec7ce3
      Ryuta Kamizono 提交于
      This allows to work `author.books.insert_all` as expected.
      Co-authored-by: NJosef Šimánek <josef.simanek@gmail.com>
      5cec7ce3
  12. 23 4月, 2020 4 次提交
    • A
    • R
      Remove unused `operand1`/`operand2` aliases · 9b8087af
      Ryuta Kamizono 提交于
      There is no worth to keep those unused aliases and tests which are
      private API.
      9b8087af
    • F
      Reload schema after ignored_columns reassignment · 712ef53c
      Flavio Wuensche 提交于
      reload column_names after ignored_columns assignment
      
      code review: remove unnecessary setup and move up reload_schema_from_cache
      712ef53c
    • G
      Fix typos [ci skip] · 1064c516
      Godfrey Chan 提交于
      I wrote this shell script to find words from the Rails repo,
      so I can paste them into https://www.horsepaste.com/ for
      the [codenames game](https://en.m.wikipedia.org/wiki/Codenames_(board_game)).
      
      ```bash
      git grep -Il '' | \
        grep -v -E "CHANGELOG|Gemfile|gemspec|package\.json|yarn\.lock" | \
        xargs cat | \
        sed '/[^ ]\{10,\}/d' | \
        sed 's/\([A-Z]\)/ \1/g' | \
        tr 'A-Z' 'a-z' | \
        tr -c -s 'a-z' '\n' | \
        sed '/^.\{0,3\}$/d' | \
        sort | \
        uniq | \
        tr '\n' ',' | \
        pbcopy
      ```
      
      You can see the result in https://www.horsepaste.com/rails-fixed.
      Click "Next game" to cycle the words.
      
      Found some typos in the codebase from this 😂
      
      This is how I generated the list of possible typos:
      
      ```bash
      git grep -Il '' | \
        grep -v -E "CHANGELOG|Gemfile|gemspec|package\.json|yarn\.lock" | \
        xargs cat | \
        sed '/[^ ]\{10,\}/d' | \
        sed 's/\([A-Z]\)/ \1/g' | \
        tr 'A-Z' 'a-z' | \
        tr -c -s 'a-z' '\n' | \
        sed '/^.\{0,3\}$/d' | \
        sort | \
        uniq | \
        aspell --ignore-case list
      ```
      
      I manually reviewed the list and made the corrections
      in this commit. The rest on the list are either:
      
      * Bugs in my script: it split things like "doesn't" into
        "doesn" and "t", if find things like `#ffffff` and
        extracts "ffffff" as a word, etc
      * British spelling: honour, optimised
      * Foreign words: bonjour, espanol
      * Names: nginx, hanekawa
      * Technical words: mutex, xhtml
      * Portmanteau words: autosave, nodelist
      * Invented words: camelize, coachee
      * Shortened words: attrs, repo
      * Deliberate typos: hllo, hillo (used in code examples, etc)
      * Lorem ipsum words: arcu, euismod
      
      This is the [output](https://gist.github.com/chancancode/eb0b573d667dc31906f33f1fb0b22313)
      of the script *after* fixing the typos included in this
      commit. In theory, someone can run that command again in
      the future and compare the output to catch new typos (i.e.
      using my list to filter out known typos).
      
      Limitations: the aspell dictionary could be wrong, I
      could have miss things, and my script ignores words that
      are less than 3 characters or longer than 10 characters.
      1064c516
  13. 20 4月, 2020 2 次提交
    • I
      Preserve column comment on renaming column · c22cad96
      Islam Taha 提交于
      Update activerecord changelog
      
      Specify DB name in changelog and fix typo
      c22cad96
    • E
      Use __id__ to dedup records for transactional callbacks · 8d3ca970
      Eugene Kenny 提交于
      While not a particularly good idea, it's possible to use `object_id` as
      an attribute name, typically by defining a polymorphic association named
      `object`. Since 718a32ca, transactional
      callbacks deduplicate records by their `object_id`, but this causes
      incorrect behaviour when the record has an attribute with that name.
      
      Using `__id__` instead makes a naming collision much less likely.
      8d3ca970
  14. 18 4月, 2020 1 次提交
  15. 17 4月, 2020 2 次提交
  16. 16 4月, 2020 1 次提交
    • E
      Add `if_exists` option to `remove_index` · 36ea1084
      eileencodes 提交于
      This PR allows for passing `if_exists` options to the `remove_index`
      method so that we can ignore already removed indexes. This work follows
      column `if/if_not_exists` from #38352 and `:if_not_exists` on `add_index`
      from #38555.
      
      We've found this useful at GitHub, there are migrations where we don't
      want to raise if an index was already removed. This will allow us to
      remove a monkey patch on `remove_index`.
      
      I considered raising after the `index_name_for_remove` method is called
      but that method will raise if the index doesn't exist before we get to
      execute. I have a commit that refactors this but after much
      consideration this change is cleaner and more straightforward than other
      ways of implementing this.
      
      This change also adds a little extra validation to the `add_index` test.
      Fix `nodoc` on edited methods.
      36ea1084
  17. 15 4月, 2020 2 次提交
    • R
      Fix unscoping association scope on joins not to raise an error · e93f416a
      Ryuta Kamizono 提交于
      #29589 changed merging scope order to allow to unscope default scopes on
      association scope (#29611), but that caused a regression #38811 that
      accidentally allow join constraint which is required.
      
      ```
      % bin/test test/cases/associations/has_many_associations_test.rb -n test_unscopes_the_default_scope_of_associated_model_when_used_with_include
      Run options: -n test_unscopes_the_default_scope_of_associated_model_when_used_with_include --seed 32978
      
      # Running:
      
      E
      
      Error:
      HasManyAssociationsTest#test_unscopes_the_default_scope_of_associated_model_when_used_with_include:
      NoMethodError: undefined method `children' for nil:NilClass
          ~/rails/activerecord/lib/active_record/associations/join_dependency/join_association.rb:39:in `block in join_constraints'
          ~/rails/activerecord/lib/active_record/associations/join_dependency/join_association.rb:30:in `reverse_each'
          ~/rails/activerecord/lib/active_record/associations/join_dependency/join_association.rb:30:in `with_index'
          ~/rails/activerecord/lib/active_record/associations/join_dependency/join_association.rb:30:in `join_constraints'
          ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:171:in `make_constraints'
          ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:196:in `block in walk'
          ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:196:in `each'
          ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:196:in `flat_map'
          ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:196:in `walk'
          ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:90:in `block in join_constraints'
          ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:87:in `each'
          ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:87:in `flat_map'
          ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:87:in `join_constraints'
          ~/rails/activerecord/lib/active_record/relation/query_methods.rb:1226:in `build_join_query'
          ~/rails/activerecord/lib/active_record/relation/query_methods.rb:1211:in `build_joins'
          ~/rails/activerecord/lib/active_record/relation/query_methods.rb:1091:in `build_arel'
          ~/rails/activerecord/lib/active_record/relation/query_methods.rb:1063:in `arel'
          ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:419:in `block in limited_ids_for'
          ~/rails/activerecord/lib/active_record/relation.rb:867:in `skip_query_cache_if_necessary'
          ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:419:in `limited_ids_for'
          ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:398:in `apply_join_dependency'
          ~/rails/activerecord/lib/active_record/relation.rb:839:in `block in exec_queries'
          ~/rails/activerecord/lib/active_record/relation.rb:867:in `skip_query_cache_if_necessary'
          ~/rails/activerecord/lib/active_record/relation.rb:834:in `exec_queries'
          ~/rails/activerecord/lib/active_record/relation.rb:639:in `load'
          ~/rails/activerecord/lib/active_record/relation.rb:250:in `records'
          ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:508:in `find_take'
          ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:98:in `take'
          ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:458:in `find_one'
          ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:442:in `find_with_ids'
          ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:69:in `find'
          ~/rails/activerecord/test/cases/associations/has_many_associations_test.rb:2689:in `block in <class:HasManyAssociationsTest>'
      
      bin/test test/cases/associations/has_many_associations_test.rb:2683
      ```
      
      Required join constraint should not be allowed to unscoping.
      
      Fixes #38811.
      e93f416a
    • R
      Remove unused Arel visitors in the code base · a2040ee3
      Ryuta Kamizono 提交于
      This removes ibm_db, informix, mssql, oracle, and oracle12 Arel visitors
      which are not used in the code base.
      
      Actually oracle and oracle12 visitors are used at oracle-enhanced
      adapter, but now I think that those visitors should be in the adapter's
      repo like sqlserver adapter and the dedicated Arel visitor
      (https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/master/lib/arel/visitors/sqlserver.rb),
      otherwise it is hard to find a bug and review PRs for the oracle
      visitors (e.g. #35838, #37646), since we don't have knowledge and
      environment enough for Oracle.
      a2040ee3