composite_primary_keys 13.0.4 → 13.0.7
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.
- checksums.yaml +4 -4
- data/History.rdoc +12 -1
- data/lib/composite_primary_keys/associations/preloader/association.rb +19 -11
- data/lib/composite_primary_keys/composite_predicates.rb +50 -0
- data/lib/composite_primary_keys/relation.rb +2 -2
- data/lib/composite_primary_keys/version.rb +1 -1
- data/test/abstract_unit.rb +1 -1
- data/test/test_predicates.rb +130 -60
- metadata +3 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: e705c71e8e7a1f2d4aee39d46ba133177960963c2d126ee41caea675ad743dfe
         | 
| 4 | 
            +
              data.tar.gz: 266bba1595212c20101e3052cc2a24de8654ce817412b82cfbacee6cf3044c56
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 80a8ad394e2393f3fbae332a9ba5d8db8bea4484b09834e5ef0749395b188e796e13cab5625688530e4f299464400e2cf0dc67a37f6a27160890cbe08ae8857d
         | 
| 7 | 
            +
              data.tar.gz: 48a459a2296938f41a40e98e8f533ae0d7ee8bcd427406dd05af4a1a697466c19e1ba4d4c2212b7d4518e1308ef528ec83f1d52b5b59808016c65d8314c3f074
         | 
    
        data/History.rdoc
    CHANGED
    
    | @@ -1,4 +1,15 @@ | |
| 1 | 
            -
            == 13.0. | 
| 1 | 
            +
            == 13.0.7 (2023-02-04)
         | 
| 2 | 
            +
            * Fix #573 (Charlie Savage)
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            == 13.0.6 (2023-02-04)
         | 
| 5 | 
            +
            * Fix #577 (Charlie Savage)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            == 13.0.5 (2023-02-04)
         | 
| 8 | 
            +
            * Improve query generation for cpk_in_predicate. This reduces the length of
         | 
| 9 | 
            +
            queries when loading many keys and enables Postgres to use index scans
         | 
| 10 | 
            +
            more frequently. (Andrew Kiellor)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            == 13.0.4 (2022-12-05)
         | 
| 2 13 | 
             
            * Fix previously_new_record? not being set to true after create
         | 
| 3 14 |  | 
| 4 15 | 
             
            == 13.0.3 (2022-01-09)
         | 
| @@ -33,20 +33,28 @@ module ActiveRecord | |
| 33 33 | 
             
                      end
         | 
| 34 34 | 
             
                    end
         | 
| 35 35 |  | 
| 36 | 
            -
                    def  | 
| 37 | 
            -
                       | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
                        owners_by_key[ | 
| 46 | 
            -
                          ( | 
| 36 | 
            +
                    def load_records
         | 
| 37 | 
            +
                      # owners can be duplicated when a relation has a collection association join
         | 
| 38 | 
            +
                      # #compare_by_identity makes such owners different hash keys
         | 
| 39 | 
            +
                      @records_by_owner = {}.compare_by_identity
         | 
| 40 | 
            +
                      raw_records = owner_keys.empty? ? [] : records_for(owner_keys)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                      @preloaded_records = raw_records.select do |record|
         | 
| 43 | 
            +
                        assignments = false
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                        owners_by_key[convert_key(record[association_key_name])].each do |owner|
         | 
| 46 | 
            +
                          entries = (@records_by_owner[owner] ||= [])
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                          if reflection.collection? || entries.empty?
         | 
| 49 | 
            +
                            entries << record
         | 
| 50 | 
            +
                            assignments = true
         | 
| 51 | 
            +
                          end
         | 
| 47 52 | 
             
                        end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                        assignments
         | 
| 48 55 | 
             
                      end
         | 
| 49 56 | 
             
                    end
         | 
| 57 | 
            +
             | 
| 50 58 | 
             
                  end
         | 
| 51 59 | 
             
                end
         | 
| 52 60 | 
             
              end
         | 
| @@ -51,9 +51,59 @@ module CompositePrimaryKeys | |
| 51 51 | 
             
                end
         | 
| 52 52 |  | 
| 53 53 | 
             
                def cpk_in_predicate(table, primary_keys, ids)
         | 
| 54 | 
            +
                  if primary_keys.length == 2
         | 
| 55 | 
            +
                    cpk_in_predicate_with_grouped_keys(table, primary_keys, ids)
         | 
| 56 | 
            +
                  else
         | 
| 57 | 
            +
                    cpk_in_predicate_with_non_grouped_keys(table, primary_keys, ids)
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def cpk_in_predicate_with_non_grouped_keys(table, primary_keys, ids)
         | 
| 54 62 | 
             
                  and_predicates = ids.map do |id|
         | 
| 55 63 | 
             
                    cpk_id_predicate(table, primary_keys, id)
         | 
| 56 64 | 
             
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  cpk_or_predicate(and_predicates)
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def cpk_in_predicate_with_grouped_keys(table, primary_keys, ids)
         | 
| 70 | 
            +
                  keys_by_first_column_name = Hash.new { |hash, key| hash[key] = [] }
         | 
| 71 | 
            +
                  keys_by_second_column_name = Hash.new { |hash, key| hash[key] = [] }
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  ids.map.each do |first_key_part, second_key_part|
         | 
| 74 | 
            +
                    keys_by_first_column_name[first_key_part] << second_key_part
         | 
| 75 | 
            +
                    keys_by_second_column_name[second_key_part] << first_key_part
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  low_cardinality_column_name, high_cardinality_column_name, groups = \
         | 
| 79 | 
            +
                    if keys_by_first_column_name.size <= keys_by_second_column_name.size
         | 
| 80 | 
            +
                      [primary_keys.first, primary_keys.second, keys_by_first_column_name]
         | 
| 81 | 
            +
                    else
         | 
| 82 | 
            +
                      [primary_keys.second, primary_keys.first, keys_by_second_column_name]
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  and_predicates = groups.map do |low_cardinality_value, high_cardinality_values|
         | 
| 86 | 
            +
                    non_nil_high_cardinality_values = high_cardinality_values.compact
         | 
| 87 | 
            +
                    in_clause = table[high_cardinality_column_name].in(non_nil_high_cardinality_values)
         | 
| 88 | 
            +
                    inclusion_clauses = if non_nil_high_cardinality_values.size != high_cardinality_values.size
         | 
| 89 | 
            +
                                          Arel::Nodes::Grouping.new(
         | 
| 90 | 
            +
                                            Arel::Nodes::Or.new(
         | 
| 91 | 
            +
                                              in_clause,
         | 
| 92 | 
            +
                                              table[high_cardinality_column_name].eq(nil)
         | 
| 93 | 
            +
                                            )
         | 
| 94 | 
            +
                                          )
         | 
| 95 | 
            +
                                        else
         | 
| 96 | 
            +
                                          in_clause
         | 
| 97 | 
            +
                                        end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                    Arel::Nodes::And.new(
         | 
| 100 | 
            +
                      [
         | 
| 101 | 
            +
                        table[low_cardinality_column_name].eq(low_cardinality_value),
         | 
| 102 | 
            +
                        inclusion_clauses
         | 
| 103 | 
            +
                      ]
         | 
| 104 | 
            +
                    )
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
             | 
| 57 107 | 
             
                  cpk_or_predicate(and_predicates)
         | 
| 58 108 | 
             
                end
         | 
| 59 109 | 
             
              end
         | 
| @@ -29,7 +29,7 @@ module ActiveRecord | |
| 29 29 | 
             
                  stmt.key = table[primary_key]
         | 
| 30 30 |  | 
| 31 31 | 
             
                  # CPK
         | 
| 32 | 
            -
                  if @klass.composite? | 
| 32 | 
            +
                  if @klass.composite?
         | 
| 33 33 | 
             
                    stmt = Arel::UpdateManager.new
         | 
| 34 34 | 
             
                    stmt.table(arel_table)
         | 
| 35 35 | 
             
                    cpk_subquery(stmt)
         | 
| @@ -74,7 +74,7 @@ module ActiveRecord | |
| 74 74 | 
             
                  stmt.key = table[primary_key]
         | 
| 75 75 |  | 
| 76 76 | 
             
                  # CPK
         | 
| 77 | 
            -
                  if @klass.composite? | 
| 77 | 
            +
                  if @klass.composite?
         | 
| 78 78 | 
             
                    stmt = Arel::DeleteManager.new
         | 
| 79 79 | 
             
                    stmt.from(arel_table)
         | 
| 80 80 | 
             
                    cpk_subquery(stmt)
         | 
    
        data/test/abstract_unit.rb
    CHANGED
    
    
    
        data/test/test_predicates.rb
    CHANGED
    
    | @@ -1,60 +1,130 @@ | |
| 1 | 
            -
            require File.expand_path('../abstract_unit', __FILE__)
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            class TestPredicates < ActiveSupport::TestCase
         | 
| 4 | 
            -
              fixtures :departments
         | 
| 5 | 
            -
             | 
| 6 | 
            -
              include CompositePrimaryKeys::Predicates
         | 
| 7 | 
            -
             | 
| 8 | 
            -
              def test_or
         | 
| 9 | 
            -
                dep = Department.arel_table
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                predicates = Array.new
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                3.times do |i|
         | 
| 14 | 
            -
                  predicates << dep[:id].eq(i)
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                connection = ActiveRecord::Base.connection
         | 
| 18 | 
            -
                quoted = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 19 | 
            -
                expected = "(#{quoted} = 0 OR #{quoted} = 1 OR #{quoted} = 2)"
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                pred = cpk_or_predicate(predicates)
         | 
| 22 | 
            -
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 23 | 
            -
              end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
              def test_or_with_many_values
         | 
| 26 | 
            -
                dep = Arel::Table.new(:departments)
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                predicates = Array.new
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                number_of_predicates = 3000 # This should really be big
         | 
| 31 | 
            -
                number_of_predicates.times do |i|
         | 
| 32 | 
            -
                  predicates << dep[:id].eq(i)
         | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                connection = ActiveRecord::Base.connection
         | 
| 36 | 
            -
                quoted = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 37 | 
            -
                expected_ungrouped = ((0...number_of_predicates).map { |i| "#{quoted} = #{i}" }).join(' OR ')
         | 
| 38 | 
            -
                expected = "(#{expected_ungrouped})"
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                pred = cpk_or_predicate(predicates)
         | 
| 41 | 
            -
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 42 | 
            -
              end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
              def test_and
         | 
| 45 | 
            -
                dep = Department.arel_table
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                predicates = Array.new
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                3.times do |i|
         | 
| 50 | 
            -
                  predicates << dep[:id].eq(i)
         | 
| 51 | 
            -
                end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                connection = ActiveRecord::Base.connection
         | 
| 54 | 
            -
                quoted = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 55 | 
            -
                expected = "#{quoted} = 0 AND #{quoted} = 1 AND #{quoted} = 2"
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                pred = cpk_and_predicate(predicates)
         | 
| 58 | 
            -
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 59 | 
            -
              end
         | 
| 60 | 
            -
             | 
| 1 | 
            +
            require File.expand_path('../abstract_unit', __FILE__)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestPredicates < ActiveSupport::TestCase
         | 
| 4 | 
            +
              fixtures :departments
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              include CompositePrimaryKeys::Predicates
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def test_or
         | 
| 9 | 
            +
                dep = Department.arel_table
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                predicates = Array.new
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                3.times do |i|
         | 
| 14 | 
            +
                  predicates << dep[:id].eq(i)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                connection = ActiveRecord::Base.connection
         | 
| 18 | 
            +
                quoted = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 19 | 
            +
                expected = "(#{quoted} = 0 OR #{quoted} = 1 OR #{quoted} = 2)"
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                pred = cpk_or_predicate(predicates)
         | 
| 22 | 
            +
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def test_or_with_many_values
         | 
| 26 | 
            +
                dep = Arel::Table.new(:departments)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                predicates = Array.new
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                number_of_predicates = 3000 # This should really be big
         | 
| 31 | 
            +
                number_of_predicates.times do |i|
         | 
| 32 | 
            +
                  predicates << dep[:id].eq(i)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                connection = ActiveRecord::Base.connection
         | 
| 36 | 
            +
                quoted = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 37 | 
            +
                expected_ungrouped = ((0...number_of_predicates).map { |i| "#{quoted} = #{i}" }).join(' OR ')
         | 
| 38 | 
            +
                expected = "(#{expected_ungrouped})"
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                pred = cpk_or_predicate(predicates)
         | 
| 41 | 
            +
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              def test_and
         | 
| 45 | 
            +
                dep = Department.arel_table
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                predicates = Array.new
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                3.times do |i|
         | 
| 50 | 
            +
                  predicates << dep[:id].eq(i)
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                connection = ActiveRecord::Base.connection
         | 
| 54 | 
            +
                quoted = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 55 | 
            +
                expected = "#{quoted} = 0 AND #{quoted} = 1 AND #{quoted} = 2"
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                pred = cpk_and_predicate(predicates)
         | 
| 58 | 
            +
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              def test_in
         | 
| 62 | 
            +
                dep = Department.arel_table
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                primary_keys = [[1, 1], [1, 2]]
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                connection = ActiveRecord::Base.connection
         | 
| 67 | 
            +
                quoted_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 68 | 
            +
                quoted_location_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('location_id')}"
         | 
| 69 | 
            +
                expected = "#{quoted_id_column} = 1 AND #{quoted_location_id_column} IN (1, 2)"
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                pred = cpk_in_predicate(dep, [:id, :location_id], primary_keys)
         | 
| 72 | 
            +
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              def test_in_with_low_cardinality_second_key_part
         | 
| 76 | 
            +
                dep = Department.arel_table
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                primary_keys = [[1, 1], [2, 1]]
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                connection = ActiveRecord::Base.connection
         | 
| 81 | 
            +
                quoted_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 82 | 
            +
                quoted_location_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('location_id')}"
         | 
| 83 | 
            +
                expected = "#{quoted_location_id_column} = 1 AND #{quoted_id_column} IN (1, 2)"
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                pred = cpk_in_predicate(dep, [:id, :location_id], primary_keys)
         | 
| 86 | 
            +
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 87 | 
            +
              end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
              def test_in_with_nil_primary_key_part
         | 
| 90 | 
            +
                dep = Department.arel_table
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                primary_keys = [[nil, 1], [nil, 2]]
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                connection = ActiveRecord::Base.connection
         | 
| 95 | 
            +
                quoted_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 96 | 
            +
                quoted_location_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('location_id')}"
         | 
| 97 | 
            +
                expected = "#{quoted_id_column} IS NULL AND #{quoted_location_id_column} IN (1, 2)"
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                pred = cpk_in_predicate(dep, [:id, :location_id], primary_keys)
         | 
| 100 | 
            +
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
              def test_in_with_nil_secondary_key_part
         | 
| 104 | 
            +
                dep = Department.arel_table
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                primary_keys = [[1, 1], [1, nil]]
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                connection = ActiveRecord::Base.connection
         | 
| 109 | 
            +
                quoted_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 110 | 
            +
                quoted_location_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('location_id')}"
         | 
| 111 | 
            +
                expected = "#{quoted_id_column} = 1 AND (#{quoted_location_id_column} IN (1) OR #{quoted_location_id_column} IS NULL)"
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                pred = cpk_in_predicate(dep, [:id, :location_id], primary_keys)
         | 
| 114 | 
            +
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 115 | 
            +
              end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
              def test_in_with_multiple_primary_key_parts
         | 
| 118 | 
            +
                dep = Department.arel_table
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                primary_keys = [[1, 1], [1, 2], [2, 3], [2, 4]]
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                connection = ActiveRecord::Base.connection
         | 
| 123 | 
            +
                quoted_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
         | 
| 124 | 
            +
                quoted_location_id_column = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('location_id')}"
         | 
| 125 | 
            +
                expected = "(#{quoted_id_column} = 1 AND #{quoted_location_id_column} IN (1, 2) OR #{quoted_id_column} = 2 AND #{quoted_location_id_column} IN (3, 4))"
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                pred = cpk_in_predicate(dep, [:id, :location_id], primary_keys)
         | 
| 128 | 
            +
                assert_equal(with_quoted_identifiers(expected), pred.to_sql)
         | 
| 129 | 
            +
              end
         | 
| 130 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: composite_primary_keys
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 13.0. | 
| 4 | 
            +
              version: 13.0.7
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Charlie Savage
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2023-02-04 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activerecord
         | 
| @@ -216,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 216 216 | 
             
                - !ruby/object:Gem::Version
         | 
| 217 217 | 
             
                  version: '0'
         | 
| 218 218 | 
             
            requirements: []
         | 
| 219 | 
            -
            rubygems_version: 3. | 
| 219 | 
            +
            rubygems_version: 3.4.6
         | 
| 220 220 | 
             
            signing_key:
         | 
| 221 221 | 
             
            specification_version: 4
         | 
| 222 222 | 
             
            summary: Composite key support for ActiveRecord
         |