{"id":13879811,"url":"https://github.com/rkrage/pg_party","last_synced_at":"2025-04-10T22:29:33.009Z","repository":{"id":40589338,"uuid":"97073011","full_name":"rkrage/pg_party","owner":"rkrage","description":"ActiveRecord PostgreSQL Partitioning","archived":false,"fork":false,"pushed_at":"2024-11-30T01:35:42.000Z","size":222,"stargazers_count":497,"open_issues_count":8,"forks_count":31,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-03T13:46:20.858Z","etag":null,"topics":["activerecord","partition","partitioning","postgres","postgresql","rails","ruby"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rkrage.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-13T02:47:24.000Z","updated_at":"2025-04-02T06:36:20.000Z","dependencies_parsed_at":"2024-06-08T16:31:10.194Z","dependency_job_id":"d982a75e-8ae3-4593-adf2-095ec8e17b46","html_url":"https://github.com/rkrage/pg_party","commit_stats":{"total_commits":105,"total_committers":18,"mean_commits":5.833333333333333,"dds":"0.32380952380952377","last_synced_commit":"43d6681bfe957a292277fcc8e16ff13015d909d1"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rkrage%2Fpg_party","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rkrage%2Fpg_party/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rkrage%2Fpg_party/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rkrage%2Fpg_party/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rkrage","download_url":"https://codeload.github.com/rkrage/pg_party/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248308673,"owners_count":21082054,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","partition","partitioning","postgres","postgresql","rails","ruby"],"created_at":"2024-08-06T08:02:34.195Z","updated_at":"2025-04-10T22:29:32.969Z","avatar_url":"https://github.com/rkrage.png","language":"Ruby","readme":"# PgParty\n\n[![Gem Version](https://badge.fury.io/rb/pg_party.svg)][rubygems]\n[![Build Status](https://circleci.com/gh/rkrage/pg_party.svg?\u0026style=shield)][circle]\n[![Maintainability](https://api.codeclimate.com/v1/badges/c409453d2283dd440227/maintainability)][cc_maintainability]\n[![Test Coverage](https://api.codeclimate.com/v1/badges/c409453d2283dd440227/test_coverage)][cc_coverage]\n\n[rubygems]:           https://rubygems.org/gems/pg_party\n[circle]:             https://circleci.com/gh/rkrage/pg_party/tree/master\n[cc_maintainability]: https://codeclimate.com/github/rkrage/pg_party/maintainability\n[cc_coverage]:        https://codeclimate.com/github/rkrage/pg_party/test_coverage\n\n[ActiveRecord](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)!\n\n## Features\n\n- Migration methods for partition specific database operations\n- Model methods for querying partitioned data, creating adhoc partitions, and retreiving partition metadata\n\n## Limitations\n\n- Partition tables are not represented correctly in `db/schema.rb` — please use the `:sql` schema format\n\n## Compatibility\n\nThis gem is tested against:\n\n- Rails: 7.0, 7.1, 7.2, 8.0\n- Ruby: 3.2, latest (currently 3.3 at the time of this commit)\n- PostgreSQL: 13, 14, 15, 16, 17\n\n## Future Work\n\nI plan to separate out the model functionality into a new gem and port the migration functionality into [pg\\_ha\\_migrations](https://github.com/braintree/pg_ha_migrations) (some of which has already been done).\nI will continue to maintain this gem (bugfixes / support for new versions of Rails) until that work is complete.\n\nI originally planned to add a feature for automatic partition creation, but I think that functionality would be better served by [pg\\_partman](https://github.com/pgpartman/pg_partman).\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'pg_party'\n```\n\nAnd then execute:\n\n```\n$ bundle\n```\n\nOr install it yourself as:\n\n```\n$ gem install pg_party\n```\n\nNote that the gemspec does not require `pg`, as some model methods _may_ work for other databases.\nMigration methods will be unavailable unless `pg` is installed.\n\n## Configuration\n\nThese values can be accessed and set via `PgParty.config` and `PgParty.configure`.\n\n- `caching`\n  - Whether to cache currently attached partitions and anonymous model classes\n  - Default: `true`\n- `caching_ttl`\n  - Length of time (in seconds) that cache entries are considered valid\n  - Default: `-1` (never expire cache entries)\n- `schema_exclude_partitions`\n  - Whether to exclude child partitions in `rake db:structure:dump`\n  - Default: `true`\n- `create_template_tables`\n  - Whether to create template tables by default. Use the `template:` option when creating partitioned tables to override this default.\n  - Default: `true`\n- `create_with_primary_key`\n  - Whether to add primary key constraints to partitioned (parent) tables by default.\n    * This behavior is disabled by default as this configuration usually requires composite primary keys to be specified\n      and ActiveRecord does not natively support composite primary keys. There are workarounds such as the\n      [composite_primary_keys gem](https://github.com/composite-primary-keys/composite_primary_keys).\n    * This is not supported for Postgres 10 (requires Postgres 11+)\n    * Primary key constraints must include all partition keys, for example: `primary_key: [:id, :created_at], partition_key: :created_at`\n    * Partition keys cannot use expressions\n    * Can be overridden via the `create_with_primary_key:` option when creating partitioned tables\n  - Default: `false`\n- `include_subpartitions_in_partition_list`\n  - Whether to include nested subpartitions in the result of `YourModelClass.partiton_list` mby default.\n    You can always pass the `include_subpartitions:` option to override this.\n  - Default: `false` (for backward compatibility)\n\nNote that caching is done in-memory for each process of an application. Attaching / detaching partitions _will_ clear the cache, but only for the process that initiated the request. For multi-process web servers, it is recommended to use a TTL or disable caching entirely.\n\n### Example\n\n```ruby\n# in a Rails initializer\nPgParty.configure do |c|\n  c.caching_ttl = 60\n  c.schema_exclude_partitions = false\n  c.include_subpartitions_in_partition_list = true\n  # Postgres 11+ users starting fresh may consider the below options to rely on Postgres' native features instead of\n  # this gem's template tables feature.\n  c.create_template_tables = false\n  c.create_with_primary_key = true\nend\n```\n\n## Usage\n\n### Migrations\n\n#### Methods\n\nThese methods are available in migrations as well as `ActiveRecord::Base#connection` objects.\n\n- `create_range_partition`\n  - Create partitioned table using the _range_ partitioning method\n  - Required args: `table_name`, `partitition_key:`\n- `create_list_partition`\n  - Create partitioned table using the _list_ partitioning method\n  - Required args: `table_name`, `partition_key:`\n- `create_hash_partition` (Postgres 11+)\n  - Create partitioned table using the _hash_ partitioning method\n  - Required args: `table_name`, `partition_key:`\n- `create_range_partition_of`\n  - Create partition in _range_ partitioned table with partition key between _range_ of values\n  - Required args: `table_name`, `start_range:`, `end_range:`\n  - Create a subpartition by specifying a `partition_type:` of `:range`, `:list`, or `:hash` and a `partition_key:`\n- `create_list_partition_of`\n  - Create partition in _list_ partitioned table with partition key in _list_ of values\n  - Required args: `table_name`, `values:`\n  - Create a subpartition by specifying a `partition_type:` of `:range`, `:list`, or `:hash` and a `partition_key:`\n- `create_hash_partition_of` (Postgres 11+)\n  - Create partition in _hash_ partitioned table for partition keys with hashed values having a specific remainder\n  - Required args: `table_name`, `modulus:`, `remainder`\n  - Create a subpartition by specifying a `partition_type:` of `:range`, `:list`, or `:hash` and a `partition_key:`\n  - Note that all partitions in a _hash_ partitioned table should have the same modulus. See [Examples](#examples) for more info.\n- `create_default_partition_of` (Postgres 11+)\n  - Create a default partition for values not falling in the range or list constraints of any other partitions\n  - Required args: `table_name`\n- `attach_range_partition`\n  - Attach existing table to _range_ partitioned table with partition key between _range_ of values\n  - Required args: `parent_table_name`, `child_table_name`, `start_range:`, `end_range:`\n- `attach_list_partition`\n  - Attach existing table to _list_ partitioned table with partition key in _list_ of values\n  - Required args: `parent_table_name`, `child_table_name`, `values:`\n- `attach_hash_partition` (Postgres 11+)\n  - Attach existing table to _hash_ partitioned table with partition key hashed values having a specific remainder\n  - Required args: `parent_table_name`, `child_table_name`, `modulus:`, `remainder`\n- `attach_default_partition` (Postgres 11+)\n  - Attach existing table as the _default_ partition\n  - Required args: `parent_table_name`, `child_table_name`\n- `detach_partition`\n  - Detach partition from both _range and list_ partitioned tables\n  - Required args: `parent_table_name`, `child_table_name`\n- `create_table_like`\n  - Clone _any_ existing table\n  - Required args: `table_name`, `new_table_name`\n- `partitions_for_table_name`\n  - List all attached partitions for a given table\n  - Required args: `table_name`, `include_subpartitions:` (true or false)\n- `parent_for_table_name`\n  - Fetch the parent table for a partition\n  - Required args: `table_name`\n  - Pass optional `traverse: true` to return the top-level table in the hierarchy (for subpartitions)\n  - Returns `nil` if the table is not a partition / has no parent\n- `table_partitioned?`\n  - Returns true if the table is partitioned (false for non-partitioned tables and partitions themselves)\n  - Required args: `table_name`\n- `add_index_on_all_partitions`\n  - Recursively add an index to all partitions and subpartitions of `table_name` using Postgres's ADD INDEX CONCURRENTLY\n    algorithm which adds the index in a non-blocking manner.\n  - Required args: `table_name`, `column_name` (all `add_index` arguments are supported)\n  - Use the `in_threads:` option to add indexes in parallel threads when there are many partitions. A value of 2 to 4\n    may be reasonable for tables with many large partitions and hosts with 4+ CPUs/cores.\n  - Use `disable_ddl_transaction!` in your migration to disable transactions when using this command with `in_threads:`\n    or `algorithm: :concurrently`.\n\n#### Examples\n\nCreate _range_ partitioned table on `created_at::date` with two partitions:\n\n```ruby\nclass CreateSomeRangeRecord \u003c ActiveRecord::Migration[5.1]\n  def up\n    # proc is used for partition keys containing expressions\n    create_range_partition :some_range_records, partition_key: -\u003e{ \"(created_at::date)\" } do |t|\n      t.text :some_value\n      t.timestamps\n    end\n\n    # optional name argument is used to specify child table name\n    create_range_partition_of \\\n      :some_range_records,\n      name: :some_range_records_a,\n      start_range: \"2019-06-07\",\n      end_range: \"2019-06-08\"\n\n    # optional name argument is used to specify child table name\n     create_range_partition_of \\\n       :some_range_records,\n       name: :some_range_records_b,\n       start_range: \"2019-06-08\",\n       end_range: \"2019-06-09\"\n  end\nend\n```\n\nCreate _list_ partitioned table on `id` with two partitions:\n\n```ruby\nclass CreateSomeListRecord \u003c ActiveRecord::Migration[5.1]\n  def up\n    # symbol is used for partition keys referring to individual columns\n    create_list_partition :some_list_records, partition_key: :id do |t|\n      t.text :some_value\n      t.timestamps\n    end\n\n    # without name argument, child partition created as \"some_list_records_\u003chash\u003e\"\n    create_list_partition_of \\\n      :some_list_records,\n      values: 1..100\n\n    # without name argument, child partition created as \"some_list_records_\u003chash\u003e\"\n     create_list_partition_of \\\n       :some_list_records,\n       values: 101..200\n\n    # default partition support is available in Postgres 11 or higher\n     create_default_partition_of \\\n       :some_list_records\n  end\nend\n```\n\nCreate _hash_ partitioned table on `account_id` with two partitions (Postgres 11+ required):\n  * A hash partition can be used to spread keys evenly(ish) across partitions\n  * `modulus:` should always equal the total number of partitions planned for the table\n  * `remainder:` is an integer which should be in the range of 0 to modulus-1\n\n```ruby\nclass CreateSomeHashRecord \u003c ActiveRecord::Migration[5.1]\n  def up\n    # symbol is used for partition keys referring to individual columns\n    # create_with_primary_key: true, template: false on Postgres 11 will rely on PostgreSQL's native partition schema\n    # management vs this gem's template tables\n    # Note composite primary keys will require a workaround in ActiveRecord, such as through the use of the composite_primary_keys gem\n    create_hash_partition :some_hash_records, partition_key: :account_id, primary_key: [:id, :account_id],\n    create_with_primary_key: true, template: false do |t|\n      t.bigserial :id, null: false\n      t.bigint :account_id, null: false\n      t.text :some_value\n      t.timestamps\n    end\n\n    # without name argument, child partition created as \"some_list_records_\u003chash\u003e\"\n    create_hash_partition_of \\\n      :some_hash_records,\n      modulus: 2,\n      remainder: 0\n\n    # without name argument, child partition created as \"some_list_records_\u003chash\u003e\"\n    create_hash_partition_of \\\n      :some_hash_records,\n      modulus: 2,\n      remainder: 1\n  end\nend\n```\n\nAdvanced example with subpartitioning: Create _list_ partitioned table on `account_id` subpartitioned by _range_ on `created_at`\nwith default partitions. This example is for a table with no primary key... perhaps for some analytics use case.\n* Default partitions are only supported in Postgres 11+\n\n```ruby\nclass CreateSomeListSubpartitionedRecord \u003c ActiveRecord::Migration[5.1]\n  def up\n    create_list_partition :some_list_subpartitioned_records, partition_key: :account_id, id: false,\n      template: false do |t|\n      t.bigint :account_id, null: false\n      t.text :some_value\n      t.created_at\n    end\n\n    create_default_partition_of \\\n      :some_list_subpartitioned_records,\n      name: :some_list_subpartitioned_records_default,\n      partition_type: :range,\n      partition_key: :created_at\n\n    create_range_partition_of \\\n      :some_list_subpartitioned_records_default,\n      name: :some_list_subpartitioned_records_default_2019,\n      start_range: '2019-01-01',\n      end_range: '2019-12-31T23:59:59'\n\n    create_default_partition_of \\\n      :some_list_subpartitioned_records_default\n\n    create_list_partition_of \\\n      :some_list_subpartitioned_records,\n      name: :some_list_subpartitioned_records_1,\n      values: 1..100,\n      partition_type: :range,\n      partition_key: :created_at\n\n    create_range_partition_of \\\n      :some_list_subpartitioned_records_1,\n      name: :some_list_subpartitioned_records_1_2019,\n      start_range: '2019-01-01',\n      end_range: '2019-12-31T23:59:59'\n\n    create_default_partition_of\n      :some_list_subpartitioned_records_1\n\n     create_list_partition_of \\\n       :some_list_subpartitioned_records,\n       name: :some_list_subpartitioned_records_2,\n       values: 101..200,\n       partition_type: :range,\n       partition_key: :created_at\n\n    create_range_partition_of \\\n      :some_list_subpartitioned_records_2,\n      name: :some_list_subpartitioned_records_2_2019,\n      start_range: '2019-01-01',\n      end_range: '2019-12-31T23:59:59'\n\n    create_default_partition_of \\\n      :some_list_subpartitioned_records_2\n  end\nend\n```\n\n#### Template Tables\nUnfortunately, PostgreSQL 10 doesn't support indexes on partitioned tables.\nHowever, individual _partitions_ can have indexes.\nTo avoid explicit index creation for _every_ new partition, we've introduced the idea of template tables.\nFor every call to `create_list_partition` and `create_range_partition`, a clone `\u003ctable_name\u003e_template` is created.\nIndexes, constraints, etc. created on the template table will propagate to new partitions in calls to `create_list_partition_of` and `create_range_partition_of`:\n* Subpartitions will correctly clone from template tables if a template table exists for the top-level ancestor\n* When using Postgres 11 or higher, you may wish to disable template tables and use the native features instead, see [Configuration](#configuration)\\\n  but this may result in you using composite primary keys, which is not natively supported by ActiveRecord.\n\n```ruby\nclass CreateSomeListRecord \u003c ActiveRecord::Migration[5.1]\n  def up\n    # template table creation is enabled by default - use \"template: false\" or the config option to opt-out\n    create_list_partition :some_list_records, partition_key: :id do |t|\n      t.integer :some_foreign_id\n      t.text :some_value\n      t.timestamps\n    end\n\n    # create index on the template table\n    add_index :some_list_records_template, :some_foreign_id\n\n    # create partition with an index on \"some_foreign_id\"\n    create_list_partition_of \\\n      :some_list_records,\n      values: 1..100\n\n    # create partition with an index on \"some_foreign_id\"\n    create_list_partition_of \\\n      :some_list_records,\n      values: 101..200\n  end\nend\n```\n\n#### Attaching Existing Tables as Partitions\n\nAttach an existing table to a _range_ partitioned table:\n\n```ruby\nclass AttachRangePartition \u003c ActiveRecord::Migration[5.1]\n  def up\n    attach_range_partition \\\n      :some_range_records,\n      :some_existing_table,\n      start_range: \"2019-06-09\",\n      end_range: \"2019-06-10\"\n  end\nend\n```\n\nAttach an existing table to a _list_ partitioned table:\n\n```ruby\nclass AttachListPartition \u003c ActiveRecord::Migration[5.1]\n  def up\n    attach_list_partition \\\n      :some_list_records,\n      :some_existing_table,\n      values: 200..300\n  end\nend\n```\n\nAttach an existing table to a _hash_ partitioned table:\n\n```ruby\nclass AttachHashPartition \u003c ActiveRecord::Migration[5.1]\n  def up\n    attach_hash_partition \\\n      :some_hash_records,\n      :some_existing_table,\n      modulus: 2,\n      remainder: 1\n  end\nend\n```\n\nDetach a partition from any partitioned table:\n\n```ruby\nclass DetachPartition \u003c ActiveRecord::Migration[5.1]\n  def up\n    detach_partition :parent_table, :child_table\n  end\nend\n```\n\n#### Safely cascading `add_index` commands\nPostgres 11+ will automatically cascade CREATE INDEX operations to partitions and subpartitions, however\nCREATE INDEX CONCURRENTLY is not supported, meaning table locks will be taken on each table while the new index is built.\nPostgres 10 provides no way to cascade index creation natively.\n* The `add_index_on_all_partitions` method solves for these limitations by recursively creating the specified\n  index on all partitions and subpartitions. Index names on individual partitions will include a hash suffix to avoid conflicts.\n* On Postgres 11+, the created indices are correctly attached to an index on the parent table\n* On Postgres 10, if you are using [Template Tables](#template-tables-for-postgres-10), you will want to add the index to the template table separately.\n* This command can also be used on subpartitions to cascade targeted indices starting at one level of the table hierarchy\n\n```ruby\nclass AddSomeValueIndexToSomeListRecord \u003c ActiveRecord::Migration[5.1]\n  # add_index_on_all_partitions with in_threads option may not be used within a transaction\n  # (also, algorithm: :concurrently cannot be used within a transaction)\n  disable_ddl_transaction!\n\n  def up\n    add_index :some_records_template, :some_value # Only if using Postgres 10 with template tables\n\n    # Pass the `in_threads:` option to create indices in parallel across multiple Postgres connections\n    add_index_on_all_partitions :some_records, :some_value, algorithm: :concurrently, in_threads: 4\n  end\nend\n```\n\nFor more examples, take a look at the Combustion schema definition and integration specs:\n\n- https://github.com/rkrage/pg_party/blob/master/spec/dummy/db/schema.rb\n- https://github.com/rkrage/pg_party/blob/master/spec/integration/migration_spec.rb\n\n### Models\n\n#### Methods\n\nClass methods available to _all_ ActiveRecord models:\n\n- `partitioned?`\n  - Check if a model is backed by either a _list or range_ partitioned table\n  - No arguments\n- `range_partition_by`\n  - Configure a model backed by a _range_ partitioned table\n  - Required arg: `key` (partition key column) or block returning partition key expression\n- `list_partition_by`\n  - Configure a model backed by a _list_ partitioned table\n  - Required arg: `key` (partition key column) or block returning partition key expression\n- `hash_partition_by`\n  - Configure a model backed by a _hash_ partitioned table\n  - Required arg: `key` (partition key column) or block returning partition key expression\n\nClass methods available to both _range and list_ partitioned models:\n\n- `partitions`\n  - Retrieve a list of currently attached partitions\n  - Optional `include_subpartitions:` argument to include all subpartitions in the returned list\n- `in_partition`\n  - Retrieve an ActiveRecord model scoped to an individual partition\n  - Required arg: `child_table_name`\n- `partition_key_eq`\n  - Query for records where partition key matches a value\n  - Required arg: `value`\n\nClass methods available to _range_ partitioned models:\n\n- `create_partition`\n  - Dynamically create new partition with partition key in _range_ of values\n  - Required args: `start_range:`, `end_range:`\n- `partition_key_in`\n  - Query for records where partition key in _range_ of values\n  - Required args: `start_range`, `end_range`\n\nClass methods available to _list_ partitioned models:\n\n- `create_partition`\n  - Dynamically create new partition with partition key in _list_ of values\n  - Required arg: `values:`\n- `partition_key_in`\n  - Query for records where partition key in _list_ of values\n  - Required arg: list of `values`\n\n\nClass methods available to _hash_ partitioned models:\n\n- `create_partition`\n  - Dynamically create new partition with hashed partition key divided by _modulus_ equals _remainder_\n  - Required arg: `modulus:`, `remainder:`\n- `partition_key_in`\n  - Query for records where partition key in _list_ of values (method operates the same as for _list_ partitions above)\n  - Required arg: list of `values`\n\n#### Examples\n\nConfigure model backed by a _range_ partitioned table to get access to the methods described above:\n\n```ruby\nclass SomeRangeRecord \u003c ApplicationRecord\n  # block is used for partition keys containing expressions\n  range_partition_by { \"(created_at::date)\" }\nend\n ```\n\nConfigure model backed by a _list_ partitioned table to get access to the methods described above:\n\n```ruby\nclass SomeListRecord \u003c ApplicationRecord\n  # symbol is used for partition keys referring to individual columns\n  list_partition_by :id\nend\n```\n\nConfigure model backed by a _hash_ partitioned table to get access to the methods described above:\n\n```ruby\nclass SomeHashRecord \u003c ApplicationRecord\n  # symbol is used for partition keys referring to individual columns\n  hash_partition_by :id\nend\n```\n\nDynamically create new partition from _range_ partitioned model:\n\n```ruby\n# additional options include: \"name:\" and \"primary_key:\"\nSomeRangeRecord.create_partition(start_range: \"2019-06-09\", end_range: \"2019-06-10\")\n```\n\nDynamically create new partition from _list_ partitioned model:\n\n```ruby\n# additional options include: \"name:\" and \"primary_key:\"\nSomeListRecord.create_partition(values: 200..300)\n```\n\nDynamically create new partition from _hash_ partitioned model:\n\n```ruby\n# additional options include: \"name:\" and \"primary_key:\"\nSomeHashRecord.create_partition(modulus: 2, remainder: 1)\n```\n\nFor _range_ partitioned model, query for records where partition key in _range_ of values:\n\n```ruby\nSomeRangeRecord.partition_key_in(\"2019-06-08\", \"2019-06-10\")\n```\n\nFor _list_ and _hash_ partitioned models, query for records where partition key in _list_ of values:\n\n```ruby\nSomeListRecord.partition_key_in(1, 2, 3, 4)\n```\n\nFor all partitioned models, query for records matching partition key:\n\n```ruby\nSomeRangeRecord.partition_key_eq(Date.current)\n\nSomeListRecord.partition_key_eq(100)\n```\n\nFor all partitioned models, retrieve currently attached partitions:\n\n```ruby\nSomeRangeRecord.partitions\n\nSomeListRecord.partitions(include_subpartitions: true) # Include nested subpartitions\n```\n\nFor both all partitioned models, retrieve ActiveRecord model scoped to individual partition:\n\n```ruby\nSomeRangeRecord.in_partition(:some_range_records_partition_name)\n\nSomeListRecord.in_partition(:some_list_records_partition_name)\n```\n\nTo create _range_ partitions by month for previous, current and next months it's possible to use this example. To automate creation of partitions, run `Log.maintenance` every day with cron:\n\n```ruby\nclass Log \u003c ApplicationRecord\n  range_partition_by { '(created_at::date)' }\n\n  def self.maintenance\n    partitions = [Date.today.prev_month, Date.today, Date.today.next_month]\n\n    partitions.each do |day|\n      name = Log.partition_name_for(day)\n      next if ActiveRecord::Base.connection.table_exists?(name)\n      Log.create_partition(\n        name: name,\n        start_range: day.beginning_of_month,\n        end_range: day.next_month.beginning_of_month\n      )\n    end\n  end\n\n  def self.partition_name_for(day)\n    \"logs_y#{day.year}_m#{day.month}\"\n  end\nend\n```\n\nFor more examples, take a look at the model integration specs:\n\n- https://github.com/rkrage/pg_party/tree/master/spec/integration/model\n\n## Development\n\nThe development / test environment relies heavily on [Docker](https://docs.docker.com).\n\nStart the containers in the background:\n\n```\n$ docker-compose up -d\n```\n\nInstall dependencies:\n\n```\n$ bin/de bundle\n$ bin/de appraisal\n```\n\nRun the tests:\n\n```\n$ bin/de appraisal rake\n```\n\nOpen a Pry console to play around with the sample Rails app:\n\n```\n$ bin/de console\n```\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/rkrage/pg_party. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the PgParty project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/rkrage/pg_party/blob/master/CODE_OF_CONDUCT.md).\n","funding_links":[],"categories":["Ruby","Gems"],"sub_categories":["Table Partitioning"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frkrage%2Fpg_party","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frkrage%2Fpg_party","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frkrage%2Fpg_party/lists"}