pg_party 0.2.1 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +177 -3
- data/lib/pg_party/{connection_adapters/abstract_adapter.rb → adapter/abstract_methods.rb} +9 -9
- data/lib/pg_party/adapter/postgresql_methods.rb +35 -0
- data/lib/pg_party/adapter_decorator.rb +133 -0
- data/lib/pg_party/model/list_methods.rb +23 -0
- data/lib/pg_party/model/methods.rb +19 -0
- data/lib/pg_party/model/range_methods.rb +23 -0
- data/lib/pg_party/model_decorator.rb +62 -0
- data/lib/pg_party/model_injector.rb +39 -0
- data/lib/pg_party/version.rb +1 -1
- data/lib/pg_party.rb +11 -6
- metadata +11 -10
- data/lib/pg_party/connection_adapters/postgresql_adapter.rb +0 -125
- data/lib/pg_party/connection_handling.rb +0 -15
- data/lib/pg_party/injected_list_model_methods.rb +0 -21
- data/lib/pg_party/injected_model_methods.rb +0 -23
- data/lib/pg_party/injected_range_model_methods.rb +0 -24
- data/lib/pg_party/model_methods.rb +0 -23
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 820e7b5d4a74330f2871d8e8d5e278974001dd1f
         | 
| 4 | 
            +
              data.tar.gz: 80a59da979fa45c339aa3abe0201c154809a4eb4
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 4e14b35c529df6ea91d093e444962be64d65a112ab706b67bdce500904fb74eb88c31fd944aa06c9386f8cd365286841723ea71ecb883086604912ce6484d6db
         | 
| 7 | 
            +
              data.tar.gz: 622f8c66614c01ef3a2a649f6e0c9123b07a7d73d8adbd74ef2428215ff70d78a70e554f5bd4b98e246beb2327d174b5badce0131d6127c19b59234f9bf10022
         | 
    
        data/README.md
    CHANGED
    
    | @@ -2,11 +2,20 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            [][rubygems]
         | 
| 4 4 | 
             
            [][circle]
         | 
| 5 | 
            +
            [][climate]
         | 
| 5 6 |  | 
| 6 7 | 
             
            [rubygems]: https://rubygems.org/gems/pg_party
         | 
| 7 8 | 
             
            [circle]:   https://circleci.com/gh/rkrage/pg_party
         | 
| 9 | 
            +
            [climate]:  https://codeclimate.com/github/rkrage/pg_party
         | 
| 8 10 |  | 
| 9 | 
            -
            Active Record migrations and model helpers for creating and managing PostgreSQL 10 partitions!
         | 
| 11 | 
            +
            [Active Record](http://guides.rubyonrails.org/active_record_basics.html) migrations and model helpers for creating and managing [PostgreSQL 10 partitions](https://www.postgresql.org/docs/10/static/ddl-partitioning.html)!
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Features:
         | 
| 14 | 
            +
              - migration methods for partition specific database operations
         | 
| 15 | 
            +
              - model methods for querying partitioned data
         | 
| 16 | 
            +
              - model methods for creating adhoc partitions
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Note: PostgreSQL 10 is currently in beta. This gem should not be used in production environments (yet).
         | 
| 10 19 |  | 
| 11 20 | 
             
            ## Installation
         | 
| 12 21 |  | 
| @@ -26,11 +35,176 @@ Or install it yourself as: | |
| 26 35 |  | 
| 27 36 | 
             
            ## Usage
         | 
| 28 37 |  | 
| 29 | 
            -
             | 
| 38 | 
            +
            Full API documentation is in progress.
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            In the meantime, take a look at the [Combustion](https://github.com/pat/combustion) schema definition and integration specs:
         | 
| 41 | 
            +
              - https://github.com/rkrage/pg_party/blob/master/spec/internal/db/schema.rb
         | 
| 42 | 
            +
              - https://github.com/rkrage/pg_party/tree/master/spec/integration
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            ### Migration Examples
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            Create range partition on `created_at::date` with two child partitions:
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            ```ruby
         | 
| 49 | 
            +
            class CreateSomeRangeRecord < ActiveRecord::Migration[5.1]
         | 
| 50 | 
            +
              def up
         | 
| 51 | 
            +
                current_date = Date.current
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                create_range_partition :some_range_records, partition_key: "created_at::date" do |t|
         | 
| 54 | 
            +
                  t.text :some_value
         | 
| 55 | 
            +
                  t.timestamps
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                create_range_partition_of \
         | 
| 59 | 
            +
                  :some_range_records,
         | 
| 60 | 
            +
                  partition_key: "created_at::date",
         | 
| 61 | 
            +
                  start_range: current_date,
         | 
| 62 | 
            +
                  end_range: current_date + 1.day
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                 create_range_partition_of \
         | 
| 65 | 
            +
                   :some_range_records,
         | 
| 66 | 
            +
                   partition_key: "created_at::date",
         | 
| 67 | 
            +
                   start_range: current_date + 1.day,
         | 
| 68 | 
            +
                   end_range: current_date + 2.days
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
            end
         | 
| 71 | 
            +
            ```
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            Create list partition on `id` with two child partitions:
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            ```ruby
         | 
| 76 | 
            +
            class CreateSomeListRecord < ActiveRecord::Migration[5.1]
         | 
| 77 | 
            +
              def up
         | 
| 78 | 
            +
                create_list_partition :some_list_records, partition_key: :id do |t|
         | 
| 79 | 
            +
                  t.text :some_value
         | 
| 80 | 
            +
                  t.timestamps
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                create_list_partition_of \
         | 
| 84 | 
            +
                  :some_list_records,
         | 
| 85 | 
            +
                  partition_key: :id,
         | 
| 86 | 
            +
                  values: (1..100).to_a
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                 create_list_partition_of \
         | 
| 89 | 
            +
                   :some_list_records,
         | 
| 90 | 
            +
                   partition_key: :id,
         | 
| 91 | 
            +
                   values: (100..200).to_a
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
            end
         | 
| 94 | 
            +
            ```
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            Attach an existing table to a range partition:
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            ```ruby
         | 
| 99 | 
            +
            class AttachRangePartition < ActiveRecord::Migration[5.1]
         | 
| 100 | 
            +
              def up
         | 
| 101 | 
            +
                attach_range_partition("parent_table", "child_table")
         | 
| 102 | 
            +
              end
         | 
| 103 | 
            +
            end
         | 
| 104 | 
            +
            ```
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            Attach an existing table to a list partition:
         | 
| 107 | 
            +
             | 
| 108 | 
            +
            ```ruby
         | 
| 109 | 
            +
            class AttachListPartition < ActiveRecord::Migration[5.1]
         | 
| 110 | 
            +
              def up
         | 
| 111 | 
            +
                attach_list_partition("parent_table", "child_table")
         | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
            end
         | 
| 114 | 
            +
            ```
         | 
| 115 | 
            +
             | 
| 116 | 
            +
            Detach a child table from any partition:
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            ```ruby
         | 
| 119 | 
            +
            class DetachPartition < ActiveRecord::Migration[5.1]
         | 
| 120 | 
            +
              def up
         | 
| 121 | 
            +
                detach_partition("parent_table", "child_table")
         | 
| 122 | 
            +
              end
         | 
| 123 | 
            +
            end
         | 
| 124 | 
            +
            ```
         | 
| 125 | 
            +
             | 
| 126 | 
            +
            ### Model Examples
         | 
| 127 | 
            +
             | 
| 128 | 
            +
            Define model that is backed by a range partition:
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            ```ruby
         | 
| 131 | 
            +
            class SomeRangeRecord < ApplicationRecord
         | 
| 132 | 
            +
              range_partition_by "created_at::date"
         | 
| 133 | 
            +
            end
         | 
| 134 | 
            +
             ```
         | 
| 135 | 
            +
             | 
| 136 | 
            +
            Define model that is backed by a list partition:
         | 
| 137 | 
            +
             | 
| 138 | 
            +
            ```ruby
         | 
| 139 | 
            +
            class SomeListRecord < ApplicationRecord
         | 
| 140 | 
            +
              list_partition_by :id
         | 
| 141 | 
            +
            end
         | 
| 142 | 
            +
            ```
         | 
| 143 | 
            +
             | 
| 144 | 
            +
            Create child partition from range partition model:
         | 
| 145 | 
            +
             | 
| 146 | 
            +
            ```ruby
         | 
| 147 | 
            +
            current_date = Date.current
         | 
| 148 | 
            +
             | 
| 149 | 
            +
            SomeRangeRecord.create_partition(start_range: current_date + 1.day, end_range: current_date + 2.days)
         | 
| 150 | 
            +
            ```
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            Create child partition from list partition model:
         | 
| 153 | 
            +
             | 
| 154 | 
            +
            ```ruby
         | 
| 155 | 
            +
            SomeListRecord.create_partition(values: (200..300).to_a)
         | 
| 156 | 
            +
            ```
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            Query for records within partition range:
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            ```ruby
         | 
| 161 | 
            +
            SomeRangeRecord.partition_key_in("2017-01-01".to_date, "2017-02-01".to_date)
         | 
| 162 | 
            +
            ```
         | 
| 163 | 
            +
             | 
| 164 | 
            +
            Query for records in partition list:
         | 
| 165 | 
            +
             | 
| 166 | 
            +
            ```ruby
         | 
| 167 | 
            +
            SomeListRecord.partition_key_in(1, 2, 3, 4)
         | 
| 168 | 
            +
            ```
         | 
| 169 | 
            +
             | 
| 170 | 
            +
            Query for records matching partition key:
         | 
| 171 | 
            +
             | 
| 172 | 
            +
            ```ruby
         | 
| 173 | 
            +
            SomeRangeRecord.partition_key_eq(Date.current)
         | 
| 174 | 
            +
             | 
| 175 | 
            +
            SomeListRecord.partition_key_eq(100)
         | 
| 176 | 
            +
            ```
         | 
| 177 | 
            +
             | 
| 178 | 
            +
            Query for records by partition name:
         | 
| 179 | 
            +
             | 
| 180 | 
            +
            ```ruby
         | 
| 181 | 
            +
            # returns a collection of anonymous ActiveRecord::Base subclassed instances
         | 
| 182 | 
            +
            SomeRangeRecord.in_partition("some_range_records_partition_name")
         | 
| 183 | 
            +
             | 
| 184 | 
            +
            # returns a collection of anonymous ActiveRecord::Base subclassed instances
         | 
| 185 | 
            +
            SomeListRecord.in_partition("some_list_records_partition_name")
         | 
| 186 | 
            +
            ```
         | 
| 30 187 |  | 
| 31 188 | 
             
            ## Development
         | 
| 32 189 |  | 
| 33 | 
            -
             | 
| 190 | 
            +
            The development / test environment relies heavily on [Docker](https://docs.docker.com).
         | 
| 191 | 
            +
             | 
| 192 | 
            +
            Start the containers in the background:
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                $ docker-compose up -d
         | 
| 195 | 
            +
             | 
| 196 | 
            +
            Install dependencies:
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                $ bin/de bundle
         | 
| 199 | 
            +
                $ bin/de appraisal
         | 
| 200 | 
            +
             | 
| 201 | 
            +
            Run the tests:
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                $ bin/de rake
         | 
| 204 | 
            +
             | 
| 205 | 
            +
            Open a Pry console to play around with the sample Rails app:
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                $ bin/de console
         | 
| 34 208 |  | 
| 35 209 | 
             
            ## Contributing
         | 
| 36 210 |  | 
| @@ -1,31 +1,31 @@ | |
| 1 1 | 
             
            module PgParty
         | 
| 2 | 
            -
              module  | 
| 3 | 
            -
                module  | 
| 4 | 
            -
                  def create_range_partition(* | 
| 2 | 
            +
              module Adapter
         | 
| 3 | 
            +
                module AbstractMethods
         | 
| 4 | 
            +
                  def create_range_partition(*)
         | 
| 5 5 | 
             
                    raise NotImplementedError, "#create_range_partition is not implemented"
         | 
| 6 6 | 
             
                  end
         | 
| 7 7 |  | 
| 8 | 
            -
                  def create_list_partition(* | 
| 8 | 
            +
                  def create_list_partition(*)
         | 
| 9 9 | 
             
                    raise NotImplementedError, "#create_list_partition is not implemented"
         | 
| 10 10 | 
             
                  end
         | 
| 11 11 |  | 
| 12 | 
            -
                  def create_range_partition_of(* | 
| 12 | 
            +
                  def create_range_partition_of(*)
         | 
| 13 13 | 
             
                    raise NotImplementedError, "#create_range_partition_of is not implemented"
         | 
| 14 14 | 
             
                  end
         | 
| 15 15 |  | 
| 16 | 
            -
                  def create_list_partition_of(* | 
| 16 | 
            +
                  def create_list_partition_of(*)
         | 
| 17 17 | 
             
                    raise NotImplementedError, "#create_list_partition_of is not implemented"
         | 
| 18 18 | 
             
                  end
         | 
| 19 19 |  | 
| 20 | 
            -
                  def attach_range_partition(* | 
| 20 | 
            +
                  def attach_range_partition(*)
         | 
| 21 21 | 
             
                    raise NotImplementedError, "#attach_range_partition is not implemented"
         | 
| 22 22 | 
             
                  end
         | 
| 23 23 |  | 
| 24 | 
            -
                  def attach_list_partition(* | 
| 24 | 
            +
                  def attach_list_partition(*)
         | 
| 25 25 | 
             
                    raise NotImplementedError, "#attach_list_partition is not implemented"
         | 
| 26 26 | 
             
                  end
         | 
| 27 27 |  | 
| 28 | 
            -
                  def detach_partition(* | 
| 28 | 
            +
                  def detach_partition(*)
         | 
| 29 29 | 
             
                    raise NotImplementedError, "#detach_partition is not implemented"
         | 
| 30 30 | 
             
                  end
         | 
| 31 31 | 
             
                end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            require "pg_party/adapter_decorator"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module PgParty
         | 
| 4 | 
            +
              module Adapter
         | 
| 5 | 
            +
                module PostgreSQLMethods
         | 
| 6 | 
            +
                  def create_range_partition(*args, &blk)
         | 
| 7 | 
            +
                    PgParty::AdapterDecorator.new(self).create_range_partition(*args, &blk)
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def create_list_partition(*args, &blk)
         | 
| 11 | 
            +
                    PgParty::AdapterDecorator.new(self).create_list_partition(*args, &blk)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def create_range_partition_of(*args)
         | 
| 15 | 
            +
                    PgParty::AdapterDecorator.new(self).create_range_partition_of(*args)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def create_list_partition_of(*args)
         | 
| 19 | 
            +
                    PgParty::AdapterDecorator.new(self).create_list_partition_of(*args)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def attach_range_partition(*args)
         | 
| 23 | 
            +
                    PgParty::AdapterDecorator.new(self).attach_range_partition(*args)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def attach_list_partition(*args)
         | 
| 27 | 
            +
                    PgParty::AdapterDecorator.new(self).attach_list_partition(*args)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def detach_partition(*args)
         | 
| 31 | 
            +
                    PgParty::AdapterDecorator.new(self).detach_partition(*args)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,133 @@ | |
| 1 | 
            +
            require "digest"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module PgParty
         | 
| 4 | 
            +
              class AdapterDecorator < SimpleDelegator
         | 
| 5 | 
            +
                def initialize(adapter)
         | 
| 6 | 
            +
                  super(adapter)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  raise "Partitioning only supported in PostgreSQL >= 10.0" unless supports_partitions?
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def create_range_partition(table_name, partition_key:, **options, &blk)
         | 
| 12 | 
            +
                  create_partition(table_name, :range, partition_key, **options, &blk)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def create_list_partition(table_name, partition_key:, **options, &blk)
         | 
| 16 | 
            +
                  create_partition(table_name, :list, partition_key, **options, &blk)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def create_range_partition_of(table_name, start_range:, end_range:, **options)
         | 
| 20 | 
            +
                  if options[:name]
         | 
| 21 | 
            +
                    child_table_name = options[:name]
         | 
| 22 | 
            +
                  else
         | 
| 23 | 
            +
                    child_table_name = hashed_table_name(table_name, "#{start_range}#{end_range}")
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  constraint_clause = "FROM (#{quote(start_range)}) TO (#{quote(end_range)})"
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  create_partition_of(table_name, child_table_name, constraint_clause, **options)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def create_list_partition_of(table_name, values:, **options)
         | 
| 32 | 
            +
                  if options[:name]
         | 
| 33 | 
            +
                    child_table_name = options[:name]
         | 
| 34 | 
            +
                  else
         | 
| 35 | 
            +
                    child_table_name = hashed_table_name(table_name, values.to_s)
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  constraint_clause = "IN (#{Array.wrap(values).map(&method(:quote)).join(",")})"
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  create_partition_of(table_name, child_table_name, constraint_clause, **options)
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def attach_range_partition(parent_table_name, child_table_name, start_range:, end_range:)
         | 
| 44 | 
            +
                  execute(<<-SQL)
         | 
| 45 | 
            +
                    ALTER TABLE #{quote_table_name(parent_table_name)}
         | 
| 46 | 
            +
                    ATTACH PARTITION #{quote_table_name(child_table_name)}
         | 
| 47 | 
            +
                    FOR VALUES FROM (#{quote(start_range)}) TO (#{quote(end_range)})
         | 
| 48 | 
            +
                  SQL
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def attach_list_partition(parent_table_name, child_table_name, values:)
         | 
| 52 | 
            +
                  execute(<<-SQL)
         | 
| 53 | 
            +
                    ALTER TABLE #{quote_table_name(parent_table_name)}
         | 
| 54 | 
            +
                    ATTACH PARTITION #{quote_table_name(child_table_name)}
         | 
| 55 | 
            +
                    FOR VALUES IN (#{Array.wrap(values).map(&method(:quote)).join(",")})
         | 
| 56 | 
            +
                  SQL
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def detach_partition(parent_table_name, child_table_name)
         | 
| 60 | 
            +
                  execute(<<-SQL)
         | 
| 61 | 
            +
                    ALTER TABLE #{quote_table_name(parent_table_name)}
         | 
| 62 | 
            +
                    DETACH PARTITION #{quote_table_name(child_table_name)}
         | 
| 63 | 
            +
                  SQL
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                private
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def create_partition(table_name, type, partition_key, **options)
         | 
| 69 | 
            +
                  modified_options = options.except(:id, :primary_key)
         | 
| 70 | 
            +
                  id               = options.fetch(:id, :bigserial)
         | 
| 71 | 
            +
                  primary_key      = options.fetch(:primary_key, :id)
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  raise ArgumentError, "composite primary key not supported" if primary_key.is_a?(Array)
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  modified_options[:id]      = false
         | 
| 76 | 
            +
                  modified_options[:options] = "PARTITION BY #{type.to_s.upcase} ((#{quote_partition_key(partition_key)}))"
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  create_table(table_name, modified_options) do |td|
         | 
| 79 | 
            +
                    if id == :uuid
         | 
| 80 | 
            +
                      td.send(id, primary_key, null: false, default: uuid_function)
         | 
| 81 | 
            +
                    elsif id
         | 
| 82 | 
            +
                      td.send(id, primary_key, null: false)
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    yield(td) if block_given?
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                def create_partition_of(table_name, child_table_name, constraint_clause, **options)
         | 
| 90 | 
            +
                  primary_key   = options.fetch(:primary_key, :id)
         | 
| 91 | 
            +
                  index         = options.fetch(:index, true)
         | 
| 92 | 
            +
                  partition_key = options[:partition_key]
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  raise ArgumentError, "composite primary key not supported" if primary_key.is_a?(Array)
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  partition_clause = <<-SQL
         | 
| 97 | 
            +
                    PARTITION OF #{quote_table_name(table_name)}
         | 
| 98 | 
            +
                    FOR VALUES #{constraint_clause}
         | 
| 99 | 
            +
                  SQL
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                  create_table(child_table_name, id: false, options: partition_clause)
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  if primary_key
         | 
| 104 | 
            +
                    execute(<<-SQL)
         | 
| 105 | 
            +
                      ALTER TABLE #{quote_table_name(child_table_name)}
         | 
| 106 | 
            +
                      ADD PRIMARY KEY (#{quote_column_name(primary_key)})
         | 
| 107 | 
            +
                    SQL
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                  if index && partition_key && primary_key != partition_key
         | 
| 111 | 
            +
                    add_index(child_table_name, "((#{quote_partition_key(partition_key)}))")
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                  child_table_name
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                def quote_partition_key(key)
         | 
| 118 | 
            +
                  key.to_s.split("::").map(&method(:quote_column_name)).join("::")
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                def uuid_function
         | 
| 122 | 
            +
                  try(:supports_pgcrypto_uuid?) ? "gen_random_uuid()" : "uuid_generate_v4()"
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                def hashed_table_name(table_name, key)
         | 
| 126 | 
            +
                  "#{table_name}_#{Digest::MD5.hexdigest(key)[0..6]}"
         | 
| 127 | 
            +
                end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                def supports_partitions?
         | 
| 130 | 
            +
                  postgresql_version >= 100000
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require "pg_party/model_decorator"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module PgParty
         | 
| 4 | 
            +
              module Model
         | 
| 5 | 
            +
                module ListMethods
         | 
| 6 | 
            +
                  def create_partition(*args)
         | 
| 7 | 
            +
                    PgParty::ModelDecorator.new(self).create_list_partition(*args)
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def in_partition(*args)
         | 
| 11 | 
            +
                    PgParty::ModelDecorator.new(self).in_partition(*args)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def partition_key_in(*args)
         | 
| 15 | 
            +
                    PgParty::ModelDecorator.new(self).list_partition_key_in(*args)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def partition_key_eq(*args)
         | 
| 19 | 
            +
                    PgParty::ModelDecorator.new(self).partition_key_eq(*args)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            require "pg_party/model_injector"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module PgParty
         | 
| 4 | 
            +
              module Model
         | 
| 5 | 
            +
                module Methods
         | 
| 6 | 
            +
                  def range_partition_by(key)
         | 
| 7 | 
            +
                    PgParty::ModelInjector.new(self, key).inject_range_methods
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def list_partition_by(key)
         | 
| 11 | 
            +
                    PgParty::ModelInjector.new(self, key).inject_list_methods
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def partitioned?
         | 
| 15 | 
            +
                    try(:partition_key).present?
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require "pg_party/model_decorator"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module PgParty
         | 
| 4 | 
            +
              module Model
         | 
| 5 | 
            +
                module RangeMethods
         | 
| 6 | 
            +
                  def create_partition(*args)
         | 
| 7 | 
            +
                    PgParty::ModelDecorator.new(self).create_range_partition(*args)
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def in_partition(*args)
         | 
| 11 | 
            +
                    PgParty::ModelDecorator.new(self).in_partition(*args)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def partition_key_in(*args)
         | 
| 15 | 
            +
                    PgParty::ModelDecorator.new(self).range_partition_key_in(*args)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def partition_key_eq(*args)
         | 
| 19 | 
            +
                    PgParty::ModelDecorator.new(self).partition_key_eq(*args)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            module PgParty
         | 
| 2 | 
            +
              class ModelDecorator < SimpleDelegator
         | 
| 3 | 
            +
                def in_partition(table_name)
         | 
| 4 | 
            +
                  child_class(table_name).all
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def partition_key_eq(value)
         | 
| 8 | 
            +
                  where(partition_key_as_arel.eq(value))
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def range_partition_key_in(start_range, end_range)
         | 
| 12 | 
            +
                  node = partition_key_as_arel
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  where(node.gteq(start_range).and(node.lt(end_range)))
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def list_partition_key_in(*values)
         | 
| 18 | 
            +
                  where(partition_key_as_arel.in(values.flatten))
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def create_range_partition(start_range:, end_range:, **options)
         | 
| 22 | 
            +
                  modified_options = options.merge(
         | 
| 23 | 
            +
                    start_range: start_range,
         | 
| 24 | 
            +
                    end_range: end_range,
         | 
| 25 | 
            +
                    primary_key: primary_key,
         | 
| 26 | 
            +
                    partition_key: partition_key
         | 
| 27 | 
            +
                  )
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  connection.create_range_partition_of(table_name, **modified_options)
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def create_list_partition(values:, **options)
         | 
| 33 | 
            +
                  modified_options = options.merge(
         | 
| 34 | 
            +
                    values: values,
         | 
| 35 | 
            +
                    primary_key: primary_key,
         | 
| 36 | 
            +
                    partition_key: partition_key
         | 
| 37 | 
            +
                  )
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  connection.create_list_partition_of(table_name, **modified_options)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                private
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def child_class(table_name)
         | 
| 45 | 
            +
                  Class.new(__getobj__) do
         | 
| 46 | 
            +
                    self.table_name = table_name
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def partition_key_as_arel
         | 
| 51 | 
            +
                  arel_column = arel_table[partition_column]
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  if partition_cast
         | 
| 54 | 
            +
                    quoted_cast = connection.quote_column_name(partition_cast)
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    Arel::Nodes::NamedFunction.new("CAST", [arel_column.as(quoted_cast)])
         | 
| 57 | 
            +
                  else
         | 
| 58 | 
            +
                    arel_column
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            module PgParty
         | 
| 2 | 
            +
              class ModelInjector
         | 
| 3 | 
            +
                def initialize(model, key)
         | 
| 4 | 
            +
                  @model = model
         | 
| 5 | 
            +
                  @key = key
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  @column, @cast = key.to_s.split("::")
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def inject_range_methods
         | 
| 11 | 
            +
                  create_class_attributes
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  require "pg_party/model/range_methods"
         | 
| 14 | 
            +
                  @model.extend(PgParty::Model::RangeMethods)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def inject_list_methods
         | 
| 18 | 
            +
                  create_class_attributes
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  require "pg_party/model/list_methods"
         | 
| 21 | 
            +
                  @model.extend(PgParty::Model::ListMethods)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                private
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def create_class_attributes
         | 
| 27 | 
            +
                  @model.class_attribute(
         | 
| 28 | 
            +
                    :partition_key,
         | 
| 29 | 
            +
                    :partition_column,
         | 
| 30 | 
            +
                    :partition_cast,
         | 
| 31 | 
            +
                    instance_accessor: false
         | 
| 32 | 
            +
                  )
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  @model.partition_key = @key
         | 
| 35 | 
            +
                  @model.partition_column = @column
         | 
| 36 | 
            +
                  @model.partition_cast = @cast
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
            end
         | 
    
        data/lib/pg_party/version.rb
    CHANGED
    
    
    
        data/lib/pg_party.rb
    CHANGED
    
    | @@ -2,15 +2,20 @@ require "pg_party/version" | |
| 2 2 | 
             
            require "active_support"
         | 
| 3 3 |  | 
| 4 4 | 
             
            ActiveSupport.on_load(:active_record) do
         | 
| 5 | 
            -
              require "pg_party/ | 
| 6 | 
            -
              require "pg_party/model_methods"
         | 
| 5 | 
            +
              require "pg_party/model/methods"
         | 
| 7 6 |  | 
| 8 | 
            -
              extend PgParty:: | 
| 9 | 
            -
              extend PgParty::ModelMethods
         | 
| 7 | 
            +
              extend PgParty::Model::Methods
         | 
| 10 8 |  | 
| 11 | 
            -
              require "pg_party/ | 
| 9 | 
            +
              require "pg_party/adapter/abstract_methods"
         | 
| 12 10 |  | 
| 13 11 | 
             
              ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
         | 
| 14 | 
            -
                include PgParty:: | 
| 12 | 
            +
                include PgParty::Adapter::AbstractMethods
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              require "pg_party/adapter/postgresql_methods"
         | 
| 16 | 
            +
              require "active_record/connection_adapters/postgresql_adapter"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
         | 
| 19 | 
            +
                include PgParty::Adapter::PostgreSQLMethods
         | 
| 15 20 | 
             
              end
         | 
| 16 21 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: pg_party
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Ryan Krage
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2017-09- | 
| 11 | 
            +
            date: 2017-09-29 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activerecord
         | 
| @@ -189,13 +189,14 @@ files: | |
| 189 189 | 
             
            - LICENSE.txt
         | 
| 190 190 | 
             
            - README.md
         | 
| 191 191 | 
             
            - lib/pg_party.rb
         | 
| 192 | 
            -
            - lib/pg_party/ | 
| 193 | 
            -
            - lib/pg_party/ | 
| 194 | 
            -
            - lib/pg_party/ | 
| 195 | 
            -
            - lib/pg_party/ | 
| 196 | 
            -
            - lib/pg_party/ | 
| 197 | 
            -
            - lib/pg_party/ | 
| 198 | 
            -
            - lib/pg_party/ | 
| 192 | 
            +
            - lib/pg_party/adapter/abstract_methods.rb
         | 
| 193 | 
            +
            - lib/pg_party/adapter/postgresql_methods.rb
         | 
| 194 | 
            +
            - lib/pg_party/adapter_decorator.rb
         | 
| 195 | 
            +
            - lib/pg_party/model/list_methods.rb
         | 
| 196 | 
            +
            - lib/pg_party/model/methods.rb
         | 
| 197 | 
            +
            - lib/pg_party/model/range_methods.rb
         | 
| 198 | 
            +
            - lib/pg_party/model_decorator.rb
         | 
| 199 | 
            +
            - lib/pg_party/model_injector.rb
         | 
| 199 200 | 
             
            - lib/pg_party/version.rb
         | 
| 200 201 | 
             
            homepage: https://github.com/rkrage/pg_party
         | 
| 201 202 | 
             
            licenses:
         | 
| @@ -217,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 217 218 | 
             
                  version: 1.8.11
         | 
| 218 219 | 
             
            requirements: []
         | 
| 219 220 | 
             
            rubyforge_project: 
         | 
| 220 | 
            -
            rubygems_version: 2. | 
| 221 | 
            +
            rubygems_version: 2.6.11
         | 
| 221 222 | 
             
            signing_key: 
         | 
| 222 223 | 
             
            specification_version: 4
         | 
| 223 224 | 
             
            summary: ActiveRecord PostgreSQL Partitioning
         | 
| @@ -1,125 +0,0 @@ | |
| 1 | 
            -
            require "digest"
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module PgParty
         | 
| 4 | 
            -
              module ConnectionAdapters
         | 
| 5 | 
            -
                module PostgreSQLAdapter
         | 
| 6 | 
            -
                  def create_range_partition(table_name, partition_key:, **options, &blk)
         | 
| 7 | 
            -
                    create_partition(table_name, :range, partition_key, **options, &blk)
         | 
| 8 | 
            -
                  end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                  def create_list_partition(table_name, partition_key:, **options, &blk)
         | 
| 11 | 
            -
                    create_partition(table_name, :list, partition_key, **options, &blk)
         | 
| 12 | 
            -
                  end
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                  def create_range_partition_of(table_name, start_range:, end_range:, **options)
         | 
| 15 | 
            -
                    if options[:name]
         | 
| 16 | 
            -
                      child_table_name = options[:name]
         | 
| 17 | 
            -
                    else
         | 
| 18 | 
            -
                      child_table_name = hashed_table_name(table_name, "#{start_range}#{end_range}")
         | 
| 19 | 
            -
                    end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                    constraint_clause = "FROM (#{quote(start_range)}) TO (#{quote(end_range)})"
         | 
| 22 | 
            -
             | 
| 23 | 
            -
                    create_partition_of(table_name, child_table_name, constraint_clause, **options)
         | 
| 24 | 
            -
                  end
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                  def create_list_partition_of(table_name, values:, **options)
         | 
| 27 | 
            -
                    if options[:name]
         | 
| 28 | 
            -
                      child_table_name = options[:name]
         | 
| 29 | 
            -
                    else
         | 
| 30 | 
            -
                      child_table_name = hashed_table_name(table_name, values.to_s)
         | 
| 31 | 
            -
                    end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                    constraint_clause = "IN (#{Array.wrap(values).map(&method(:quote)).join(",")})"
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                    create_partition_of(table_name, child_table_name, constraint_clause, **options)
         | 
| 36 | 
            -
                  end
         | 
| 37 | 
            -
             | 
| 38 | 
            -
                  def attach_range_partition(parent_table_name, child_table_name, start_range:, end_range:)
         | 
| 39 | 
            -
                    execute(<<-SQL)
         | 
| 40 | 
            -
                      ALTER TABLE #{quote_table_name(parent_table_name)}
         | 
| 41 | 
            -
                      ATTACH PARTITION #{quote_table_name(child_table_name)}
         | 
| 42 | 
            -
                      FOR VALUES FROM (#{quote(start_range)}) TO (#{quote(end_range)})
         | 
| 43 | 
            -
                    SQL
         | 
| 44 | 
            -
                  end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                  def attach_list_partition(parent_table_name, child_table_name, values:)
         | 
| 47 | 
            -
                    execute(<<-SQL)
         | 
| 48 | 
            -
                      ALTER TABLE #{quote_table_name(parent_table_name)}
         | 
| 49 | 
            -
                      ATTACH PARTITION #{quote_table_name(child_table_name)}
         | 
| 50 | 
            -
                      FOR VALUES IN (#{Array.wrap(values).map(&method(:quote)).join(",")})
         | 
| 51 | 
            -
                    SQL
         | 
| 52 | 
            -
                  end
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                  def detach_partition(parent_table_name, child_table_name)
         | 
| 55 | 
            -
                    execute(<<-SQL)
         | 
| 56 | 
            -
                      ALTER TABLE #{quote_table_name(parent_table_name)}
         | 
| 57 | 
            -
                      DETACH PARTITION #{quote_table_name(child_table_name)}
         | 
| 58 | 
            -
                    SQL
         | 
| 59 | 
            -
                  end
         | 
| 60 | 
            -
             | 
| 61 | 
            -
                  private
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                  def create_partition(table_name, type, partition_key, **options)
         | 
| 64 | 
            -
                    modified_options = options.except(:id, :primary_key)
         | 
| 65 | 
            -
                    id               = options.fetch(:id, :bigserial)
         | 
| 66 | 
            -
                    primary_key      = options.fetch(:primary_key, :id)
         | 
| 67 | 
            -
             | 
| 68 | 
            -
                    raise ArgumentError, "composite primary key not supported" if primary_key.is_a?(Array)
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                    modified_options[:id]      = false
         | 
| 71 | 
            -
                    modified_options[:options] = "PARTITION BY #{type.to_s.upcase} ((#{quote_partition_key(partition_key)}))"
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                    create_table(table_name, modified_options) do |td|
         | 
| 74 | 
            -
                      if id == :uuid
         | 
| 75 | 
            -
                        td.send(id, primary_key, null: false, default: uuid_function)
         | 
| 76 | 
            -
                      elsif id
         | 
| 77 | 
            -
                        td.send(id, primary_key, null: false)
         | 
| 78 | 
            -
                      end
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                      yield td if block_given?
         | 
| 81 | 
            -
                    end
         | 
| 82 | 
            -
                  end
         | 
| 83 | 
            -
             | 
| 84 | 
            -
                  def create_partition_of(table_name, child_table_name, constraint_clause, **options)
         | 
| 85 | 
            -
                    primary_key   = options.fetch(:primary_key, :id)
         | 
| 86 | 
            -
                    index         = options.fetch(:index, true)
         | 
| 87 | 
            -
                    partition_key = options[:partition_key]
         | 
| 88 | 
            -
             | 
| 89 | 
            -
                    raise ArgumentError, "composite primary key not supported" if primary_key.is_a?(Array)
         | 
| 90 | 
            -
             | 
| 91 | 
            -
                    partition_clause = <<-SQL
         | 
| 92 | 
            -
                      PARTITION OF #{quote_table_name(table_name)}
         | 
| 93 | 
            -
                      FOR VALUES #{constraint_clause}
         | 
| 94 | 
            -
                    SQL
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                    create_table(child_table_name, id: false, options: partition_clause)
         | 
| 97 | 
            -
             | 
| 98 | 
            -
                    if primary_key
         | 
| 99 | 
            -
                      execute(<<-SQL)
         | 
| 100 | 
            -
                        ALTER TABLE #{quote_table_name(child_table_name)}
         | 
| 101 | 
            -
                        ADD PRIMARY KEY (#{quote_column_name(primary_key)})
         | 
| 102 | 
            -
                      SQL
         | 
| 103 | 
            -
                    end
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                    if index && partition_key && primary_key != partition_key
         | 
| 106 | 
            -
                      add_index(child_table_name, "((#{quote_partition_key(partition_key)}))")
         | 
| 107 | 
            -
                    end
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                    child_table_name
         | 
| 110 | 
            -
                  end
         | 
| 111 | 
            -
             | 
| 112 | 
            -
                  def quote_partition_key(key)
         | 
| 113 | 
            -
                    key.to_s.split("::").map(&method(:quote_column_name)).join("::")
         | 
| 114 | 
            -
                  end
         | 
| 115 | 
            -
             | 
| 116 | 
            -
                  def uuid_function
         | 
| 117 | 
            -
                    try(:supports_pgcrypto_uuid?) ? "gen_random_uuid()" : "uuid_generate_v4()"
         | 
| 118 | 
            -
                  end
         | 
| 119 | 
            -
             | 
| 120 | 
            -
                  def hashed_table_name(table_name, key)
         | 
| 121 | 
            -
                    "#{table_name}_#{Digest::MD5.hexdigest(key)[0..6]}"
         | 
| 122 | 
            -
                  end
         | 
| 123 | 
            -
                end
         | 
| 124 | 
            -
              end
         | 
| 125 | 
            -
            end
         | 
| @@ -1,15 +0,0 @@ | |
| 1 | 
            -
            module PgParty
         | 
| 2 | 
            -
              module ConnectionHandling
         | 
| 3 | 
            -
                def establish_connection(*args)
         | 
| 4 | 
            -
                  super.tap do
         | 
| 5 | 
            -
                    if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
         | 
| 6 | 
            -
                      require "pg_party/connection_adapters/postgresql_adapter"
         | 
| 7 | 
            -
             | 
| 8 | 
            -
                      ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
         | 
| 9 | 
            -
                        include PgParty::ConnectionAdapters::PostgreSQLAdapter
         | 
| 10 | 
            -
                      end
         | 
| 11 | 
            -
                    end
         | 
| 12 | 
            -
                  end
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
              end
         | 
| 15 | 
            -
            end
         | 
| @@ -1,21 +0,0 @@ | |
| 1 | 
            -
            require "pg_party/injected_model_methods"
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module PgParty
         | 
| 4 | 
            -
              module InjectedListModelMethods
         | 
| 5 | 
            -
                include InjectedModelMethods
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                def create_partition(values:, **options)
         | 
| 8 | 
            -
                  modified_options = options.merge(
         | 
| 9 | 
            -
                    values: values,
         | 
| 10 | 
            -
                    primary_key: primary_key,
         | 
| 11 | 
            -
                    partition_key: partition_key
         | 
| 12 | 
            -
                  )
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                  connection.create_list_partition_of(table_name, **modified_options)
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                def partition_key_in(*values)
         | 
| 18 | 
            -
                  where(partition_key_as_arel.in(values.flatten))
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
              end
         | 
| 21 | 
            -
            end
         | 
| @@ -1,23 +0,0 @@ | |
| 1 | 
            -
            module PgParty
         | 
| 2 | 
            -
              module InjectedModelMethods
         | 
| 3 | 
            -
                attr_reader :partition_key, :partition_column, :partition_cast
         | 
| 4 | 
            -
             | 
| 5 | 
            -
                def partition_key_matching(value)
         | 
| 6 | 
            -
                  where(partition_key_as_arel.eq(value))
         | 
| 7 | 
            -
                end
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                private
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                def partition_key_as_arel
         | 
| 12 | 
            -
                  arel_column = arel_table[partition_column]
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                  if partition_cast
         | 
| 15 | 
            -
                    quoted_cast = connection.quote_column_name(partition_cast)
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                    Arel::Nodes::NamedFunction.new("CAST", [arel_column.as(quoted_cast)])
         | 
| 18 | 
            -
                  else
         | 
| 19 | 
            -
                    arel_column
         | 
| 20 | 
            -
                  end
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
              end
         | 
| 23 | 
            -
            end
         | 
| @@ -1,24 +0,0 @@ | |
| 1 | 
            -
            require "pg_party/injected_model_methods"
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module PgParty
         | 
| 4 | 
            -
              module InjectedRangeModelMethods
         | 
| 5 | 
            -
                include InjectedModelMethods
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                def create_partition(start_range:, end_range:, **options)
         | 
| 8 | 
            -
                  modified_options = options.merge(
         | 
| 9 | 
            -
                    start_range: start_range,
         | 
| 10 | 
            -
                    end_range: end_range,
         | 
| 11 | 
            -
                    primary_key: primary_key,
         | 
| 12 | 
            -
                    partition_key: partition_key
         | 
| 13 | 
            -
                  )
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  connection.create_range_partition_of(table_name, **modified_options)
         | 
| 16 | 
            -
                end
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                def partition_key_in(start_range, end_range)
         | 
| 19 | 
            -
                  node = partition_key_as_arel
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                  where(node.gteq(start_range).and(node.lt(end_range)))
         | 
| 22 | 
            -
                end
         | 
| 23 | 
            -
              end
         | 
| 24 | 
            -
            end
         | 
| @@ -1,23 +0,0 @@ | |
| 1 | 
            -
            module PgParty
         | 
| 2 | 
            -
              module ModelMethods
         | 
| 3 | 
            -
                def range_partition_by(key)
         | 
| 4 | 
            -
                  @partition_key = key
         | 
| 5 | 
            -
                  @partition_column, @partition_cast = key.to_s.split("::")
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                  require "pg_party/injected_range_model_methods"
         | 
| 8 | 
            -
                  extend InjectedRangeModelMethods
         | 
| 9 | 
            -
                end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                def list_partition_by(key)
         | 
| 12 | 
            -
                  @partition_key = key
         | 
| 13 | 
            -
                  @partition_column, @partition_cast = key.to_s.split("::")
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  require "pg_party/injected_list_model_methods"
         | 
| 16 | 
            -
                  extend InjectedListModelMethods
         | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                def partitioned?
         | 
| 20 | 
            -
                  @partition_key.present?
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
              end
         | 
| 23 | 
            -
            end
         |