{"id":21816280,"url":"https://github.com/crunchloop/timescaledb-rails","last_synced_at":"2026-03-07T03:31:21.288Z","repository":{"id":64507377,"uuid":"453168718","full_name":"crunchloop/timescaledb-rails","owner":"crunchloop","description":"Ruby on Rails helpers for TimescaleDB","archived":false,"fork":false,"pushed_at":"2024-02-10T19:18:28.000Z","size":163,"stargazers_count":20,"open_issues_count":7,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-03-06T22:36:29.724Z","etag":null,"topics":["rails","ruby","timescaledb"],"latest_commit_sha":null,"homepage":"","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/crunchloop.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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":"2022-01-28T18:06:29.000Z","updated_at":"2025-12-31T22:18:05.000Z","dependencies_parsed_at":"2024-11-16T02:53:34.202Z","dependency_job_id":"dcf61a71-8044-45f4-9064-04854adfb1ce","html_url":"https://github.com/crunchloop/timescaledb-rails","commit_stats":{"total_commits":49,"total_committers":5,"mean_commits":9.8,"dds":"0.26530612244897955","last_synced_commit":"f2add16263ff4cc995d8cd82384eff33f6126066"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/crunchloop/timescaledb-rails","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crunchloop%2Ftimescaledb-rails","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crunchloop%2Ftimescaledb-rails/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crunchloop%2Ftimescaledb-rails/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crunchloop%2Ftimescaledb-rails/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crunchloop","download_url":"https://codeload.github.com/crunchloop/timescaledb-rails/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crunchloop%2Ftimescaledb-rails/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30206564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T03:24:23.086Z","status":"ssl_error","status_checked_at":"2026-03-07T03:23:11.444Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["rails","ruby","timescaledb"],"created_at":"2024-11-27T15:33:09.106Z","updated_at":"2026-03-07T03:31:21.270Z","avatar_url":"https://github.com/crunchloop.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TimescaleDB extension for Rails [![Gem Version](https://badge.fury.io/rb/timescaledb-rails.svg)](https://badge.fury.io/rb/timescaledb-rails) [![Actions Status](https://github.com/crunchloop/timescaledb-rails/workflows/CI/badge.svg?branch=main)](https://github.com/crunchloop/timescaledb-rails/actions?query=workflow%3ACI)\n\n`timescaledb-rails` extends ActiveRecord PostgreSQL adapter and provides features from [TimescaleDB](https://www.timescale.com). It provides support for hypertables and other features added by TimescaleDB PostgreSQL extension.\n\n## Installation\n\nInstall `timescaledb-rails` from RubyGems:\n\n``` sh\n$ gem install timescaledb-rails\n```\n\nOr include it in your project's `Gemfile` with Bundler:\n\n``` ruby\ngem 'timescaledb-rails', '~\u003e 0.1'\n```\n\n## Usage\n\n### Migrations\n\nCreate a hypertable from a PostgreSQL table\n\n```ruby\nclass CreateEvent \u003c ActiveRecord::Migration[7.0]\n  def change\n    create_table :events, id: false do |t|\n      t.string :name, null: false\n      t.time :occurred_at, null: false\n\n      t.timestamps\n    end\n\n    create_hypertable :events, :created_at, chunk_time_interval: '2 days'\n  end\nend\n```\n\nCreate a hypertable without a PostgreSQL table\n\n```ruby\nclass CreatePayloadHypertable \u003c ActiveRecord::Migration[7.0]\n  def change\n    create_hypertable :payloads, :created_at, chunk_time_interval: '5 days' do |t|\n      t.string :ip, null: false\n\n      t.timestamps\n    end\n  end\nend\n```\n\nAdd hypertable compression policy\n\n```ruby\nclass AddEventCompressionPolicy \u003c ActiveRecord::Migration[7.0]\n  def up\n    enable_hypertable_compression :events, segment_by: :name, order_by: 'occurred_at DESC'\n\n    add_hypertable_compression_policy :events, 20.days\n  end\n\n  def down\n    remove_hypertable_compression_policy :events\n\n    disable_hypertable_compression :events\n  end\nend\n```\n\nAdd hypertable retention policy\n\n```ruby\nclass AddEventRetentionPolicy \u003c ActiveRecord::Migration[7.0]\n  def up\n    add_hypertable_retention_policy :events, 1.year\n  end\n\n  def down\n    remove_hypertable_retention_policy :events\n  end\nend\n```\n\nAdd hypertable reorder policy\n\n```ruby\nclass AddEventReorderPolicy \u003c ActiveRecord::Migration[7.0]\n  def up\n    add_hypertable_reorder_policy :events, :index_events_on_created_at_and_name\n  end\n\n  def down\n    remove_hypertable_reorder_policy :events\n  end\nend\n```\n\nCreate continuous aggregate\n\n```ruby\nclass CreateTemperatureEventAggregate \u003c ActiveRecord::Migration[7.0]\n  disable_ddl_transaction!\n\n  def up\n    create_continuous_aggregate(\n      :temperature_events,\n      Event.time_bucket(1.day).avg(:value).temperature.to_sql\n    )\n\n    add_continuous_aggregate_policy(:temperature_events, 1.month, 1.day, 1.hour)\n  end\n\n  def down\n    drop_continuous_aggregate(:temperature_events)\n\n    remove_continuous_aggregate_policy(:temperature_events)\n  end\nend\n```\n\n\u003e **Reversible Migrations:**\n\u003e\n\u003e Above examples implement `up`/`down` methods to better document all the different APIs. Feel free to use `change` method, timescaledb-rails defines all the reverse calls for each API method so Active Record can automatically figure out how to reverse your migration.\n\n### Models\n\nIf one of your models need TimescaleDB support, just include `Timescaledb::Rails::Model`\n\n```ruby\nclass Payload \u003c ActiveRecord::Base\n  include Timescaledb::Rails::Model\n\n  self.primary_key = 'id'\nend\n```\n\nWhen hypertable belongs to a non default schema, don't forget to override `table_name`\n\n```ruby\nclass Event \u003c ActiveRecord::Base\n  include Timescaledb::Rails::Model\n\n  self.table_name = 'tdb.events'\nend\n```\n\nUsing `.find` is not recommended, to achieve more performant results, use these other find methods\n\n```ruby\n# When you know the exact time value\nPayload.find_at_time(111, Time.new(2022, 01, 01, 10, 15, 30))\n\n# If you know that the record occurred after a given time\nPayload.find_after(222, 11.days.ago)\n\n# Lastly, if you want to scope the search by a time range\nPayload.find_between(333, 1.week.ago, 1.day.ago)\n```\n\nIf you need to query data for a specific time period, `Timescaledb::Rails::Model` includes useful scopes\n\n```ruby\n# If you want to get all records from last year\nEvent.last_year #=\u003e [#\u003cEvent name...\u003e, ...]\n\n# Or if you want to get records from this year\nEvent.this_year #=\u003e [#\u003cEvent name...\u003e, ...]\n\n# Or even getting records from today\nEvent.today #=\u003e [#\u003cEvent name...\u003e, ...]\n```\n\nHere the list of all available scopes\n\n* last_year\n* last_month\n* last_week\n* this_year\n* this_month\n* this_week\n* yesterday\n* today\n\nIf you still need to query data by other time periods, take a look at these other scopes\n\n```ruby\n# If you want to get all records that occurred in the last 30 minutes\nEvent.after(30.minutes.ago) #=\u003e [#\u003cEvent name...\u003e, ...]\n\n# If you want to get records that occurred in the last 4 days, excluding today\nEvent.between(4.days.ago, 1.day.ago) #=\u003e [#\u003cEvent name...\u003e, ...]\n\n# If you want to get records that occurred at a specific time\nEvent.at_time(Time.new(2023, 01, 04, 10, 20, 30)) #=\u003e [#\u003cEvent name...\u003e, ...]\n```\n\nIf you need information about your hypertable, use the following helper methods to get useful information\n\n```ruby\n# Hypertable metadata\nEvent.hypertable #=\u003e #\u003cTimescaledb::Rails::Hypertable ...\u003e\n\n# Hypertable chunks metadata\nEvent.hypertable_chunks #=\u003e [#\u003cTimescaledb::Rails::Chunk ...\u003e, ...]\n\n# Hypertable jobs, it includes jobs like compression, retention or reorder policies, etc.\nEvent.hypertable_jobs #=\u003e [#\u003cTimescaledb::Rails::Job ...\u003e, ...]\n\n# Hypertable dimensions, like time or space dimensions\nEvent.hypertable_dimensions #=\u003e [#\u003cTimescaledb::Rails::Dimension ...\u003e, ...]\n\n# Hypertable compression settings\nEvent.hypertable_compression_settings #=\u003e [#\u003cTimescaledb::Rails::CompressionSetting ...\u003e, ...]\n```\n\nIf you need to compress or decompress a specific chunk\n\n```ruby\nchunk = Event.hypertable_chunks.first\n\nchunk.compress! unless chunk.is_compressed?\n\nchunk.decompress! if chunk.is_compressed?\n```\n\nIf you need to reorder a specific chunk\n\n```ruby\nchunk = Event.hypertable_chunks.first\n\n# If an index is not specified, it will use the one from the reorder policy\n# In case there is no reorder policy index it will raise an ArgumentError\nchunk.reorder!\n\n# If an index is specified it will use that index\nchunk.reorder!(index)\n```\n\nIf you need to manually refresh a continuous aggregate\n\n```ruby\naggregate = Event.hypertable.continuous_aggregates.first\n\naggregate.refresh!(5.days.ago, 1.day.ago)\n```\n\n### Hyperfunctions\n\n#### Time bucket\n\nYou can call the time bucket function with an interval (note that leaving the target column blank will use the default time column of the hypertable)\n\n```ruby\nEvent.time_bucket(1.day)\n\nEvent.time_bucket('1 day')\n\nEvent.time_bucket(1.day, :created_at)\n\nEvent.time_bucket(1.day, 'occurred_at')\n```\n\nYou may add aggregation like so:\n\n```ruby\nEvent.time_bucket(1.day).avg(:column)\nEvent.time_bucket(1.day).sum(:column)\nEvent.time_bucket(1.day).min(:column)\nEvent.time_bucket(1.day).max(:column)\nEvent.time_bucket(1.day).count\n```\n\n## Contributing\n\nPlease read [CONTRIBUTING.md](./CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests.\n\n## Supported Ruby/Rails versions\n\nSupported Ruby/Rails versions are listed in [`.github/workflows/ci.yaml`](./.github/workflows/ci.yaml)\n\n## License\n\nReleased under the MIT License.  See the [LICENSE][] file for further details.\n\n[license]: LICENSE\n\n## About Crunchloop\n\n![crunchloop](https://s3.amazonaws.com/crunchloop.io/logo-blue.png)\n\n`timescaledb-rails` is supported with :heart: by [Crunchloop](https://crunchloop.io). We strongly believe in giving back :rocket:. Let's work together [`Get in touch`](https://crunchloop.io/#contact).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrunchloop%2Ftimescaledb-rails","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrunchloop%2Ftimescaledb-rails","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrunchloop%2Ftimescaledb-rails/lists"}