{"id":15464913,"url":"https://github.com/blocknotes/database_recorder","last_synced_at":"2026-05-02T13:33:18.722Z","repository":{"id":42019271,"uuid":"479415144","full_name":"blocknotes/database_recorder","owner":"blocknotes","description":"Record application queries, verify them against stored queries, and replay them","archived":false,"fork":false,"pushed_at":"2022-04-18T06:41:16.000Z","size":218,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-15T06:22:17.788Z","etag":null,"topics":["rspec","ruby","sql"],"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/blocknotes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["blocknotes"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2022-04-08T14:07:53.000Z","updated_at":"2022-04-08T14:24:49.000Z","dependencies_parsed_at":"2022-07-24T23:32:03.003Z","dependency_job_id":null,"html_url":"https://github.com/blocknotes/database_recorder","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/blocknotes/database_recorder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fdatabase_recorder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fdatabase_recorder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fdatabase_recorder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fdatabase_recorder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blocknotes","download_url":"https://codeload.github.com/blocknotes/database_recorder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fdatabase_recorder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32536577,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-02T12:25:33.646Z","status":"ssl_error","status_checked_at":"2026-05-02T12:24:51.733Z","response_time":132,"last_error":"SSL_read: 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":["rspec","ruby","sql"],"created_at":"2024-10-02T00:43:48.460Z","updated_at":"2026-05-02T13:33:18.687Z","avatar_url":"https://github.com/blocknotes.png","language":"Ruby","funding_links":["https://github.com/sponsors/blocknotes"],"categories":[],"sub_categories":[],"readme":"# Database Recorder\n[![Gem Version](https://badge.fury.io/rb/database_recorder.svg)](https://badge.fury.io/rb/database_recorder)\n[![Linters](https://github.com/blocknotes/database_recorder/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/database_recorder/actions/workflows/linters.yml)\n[![Specs ActiveRecord](https://github.com/blocknotes/database_recorder/actions/workflows/specs_active_record.yml/badge.svg)](https://github.com/blocknotes/database_recorder/actions/workflows/specs_active_record.yml)\n[![Specs MySQL](https://github.com/blocknotes/database_recorder/actions/workflows/specs_mysql.yml/badge.svg)](https://github.com/blocknotes/database_recorder/actions/workflows/specs_mysql.yml)\n[![Specs PostgreSQL](https://github.com/blocknotes/database_recorder/actions/workflows/specs_postgres.yml/badge.svg)](https://github.com/blocknotes/database_recorder/actions/workflows/specs_postgres.yml)\n\nRecord database queries for testing and development purposes.\nStore queries information on files or Redis.\n\nMain features:\n- store the history of the queries of a test when it run (for monitoring);\n- eventually check if the current queries match the recorded ones (to prevent regressions);\n- [EXPERIMENTAL] optionally replay the recorded queries replacing the original requests.\n\nSample output: [test.yml](extra/sample.yml)\n\nCreating an environment variable to enable it with RSpec:\n\n![image1](extra/image1.png)\n\n## Install\n\n### With RSpec\n\n- Add to your Gemfile: `gem 'database_recorder', require: false` (:development, :test groups recommended)\n- Add in **rails_helper.rb**:\n\n```rb\nrequire 'database_recorder'\nDatabaseRecorder::RSpec.setup\n```\n\n- In the tests add `:dbr` metadata, examples:\n\n```rb\n  # Activate DatabaseRecorder with the default options\n  it 'returns 3 posts', :dbr do\n    # ...\n  end\n\n  # Verify queries comparing with the stored ones:\n  it 'returns more posts', dbr: { verify_queries: true } do\n    # ...\n  end\n```\n\nOr eventually apply the metadata per path:\n\n```rb\nRSpec.configure do |config|\n  config.define_derived_metadata(file_path: %r{/spec/models/}) do |metadata|\n    metadata[:dbr] = true\n  end\nend\n```\n\n### With plain Ruby\n\n```rb\nDatabaseRecorder::Config.db_driver = :pg\nDatabaseRecorder::Core.setup\npp DatabaseRecorder::Recording.new(options: { name: 'pg_file' }).start do\n  PG.connect(DB_CONFIG).exec(\"INSERT INTO tags(name, created_at, updated_at) VALUES('tag1', NOW(), NOW())\")\n  PG.connect(DB_CONFIG).exec(\"SELECT * FROM tags\")\nend\n```\n\nFor more examples check [here](examples).\n\n## Config options\n\nThese options are available, they must be set before calling `DatabaseRecorder::Core.setup`:\n\n```rb\n# Database driver to use: :active_record | :mysql2 | :pg\nDatabaseRecorder::Config.db_driver = :pg\n\n# Log queries format (default: '[DB] %sql [%name]')\nDatabaseRecorder::Config.log_format = '\u003e\u003e\u003e %name -- %sql'\n\n# To print/log the queries while executing the specs: false | true | :color\nDatabaseRecorder::Config.print_queries = true\n\n# Replay the recordings intercepting the queries\nDatabaseRecorder::Config.replay_recordings = true\n\n# To store the queries: :file | :redis | nil\nDatabaseRecorder::Config.storage = :redis\n# nil to avoid storing the queries\n\n# File storage options\nDatabaseRecorder::Config.storage_options = { recordings_path: '/some/path' }\n\n# Redis storage options\nDatabaseRecorder::Config.storage_options = { connection: Redis.new }\n```\n\n## History of the queries\n\nUsing the `print_queries` config option is possible to see the executed queries while running the specs. It can be used to identify easily what is going on in a specific example without having to analyze the log files.\n\nUsing the `:file` storage, the history is also recorded to files (default path: **spec/dbr**) in YAML format. This is useful for checking what's happening with more details, it includes the query results and some extra data.\n\n## Test queries' changes\n\nThis feature can be used to prevent queries regressions.\nIt requires to have previously stored the history of the queries (which could be versioned if using file storage).\nIt can be activated using `dbr: { verify_queries: true }` metadata.\n\nTo work correctly in requires `prepared_statements: true` option in the **database.yml** config file, in the connection block options (available for both Postgres and MySQL).\n\n## Replay the recorded queries\n\nThis feature is not stable (at this stage), so use it carefully and supports only deterministic tests (so it doesn't work with Faker, random data or random order specs) and only Postgres is supported for now.\nIt requires to have previously stored the history of the queries.\nUsing this feature can improve the test suite performances (especially using redis storage).\nIt can be activated using `replay_recordings` config option.\n\nSome workarounds to make it works:\n- With RSpec, run the tests with `bin/rspec --order defined`\n- Set a specific seed for Faker (optionally with an ENV var): `Faker::Config.random = Random.new(42)`\n- Set a specific Ruby seed (optionally with an ENV var): `srand(42)`\n\n## Do you like it? Star it!\n\nIf you use this component just star it. A developer is more motivated to improve a project when there is some interest.\n\nOr consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).\n\n## Contributors\n\n- [Mattia Roccoberton](https://blocknot.es): author\n\n## License\n\nThe gem is available as open-source under the terms of the [MIT](MIT-LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblocknotes%2Fdatabase_recorder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblocknotes%2Fdatabase_recorder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblocknotes%2Fdatabase_recorder/lists"}