{"id":13468679,"url":"https://github.com/mixxorz/DSLR","last_synced_at":"2025-03-26T05:31:15.368Z","repository":{"id":50658588,"uuid":"519444525","full_name":"mixxorz/DSLR","owner":"mixxorz","description":"Take lightning fast snapshots of your local Postgres databases.","archived":false,"fork":false,"pushed_at":"2024-01-09T19:44:52.000Z","size":92,"stargazers_count":140,"open_issues_count":14,"forks_count":14,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-22T08:44:47.071Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","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/mixxorz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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-07-30T07:01:54.000Z","updated_at":"2025-03-16T20:54:21.000Z","dependencies_parsed_at":"2024-05-29T12:12:40.144Z","dependency_job_id":"f585384d-4f25-40c5-bacb-1e67345c3b55","html_url":"https://github.com/mixxorz/DSLR","commit_stats":{"total_commits":72,"total_committers":2,"mean_commits":36.0,"dds":0.02777777777777779,"last_synced_commit":"111f1ec93c7358bddaae0915c1a5efa2bd96eba5"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixxorz%2FDSLR","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixxorz%2FDSLR/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixxorz%2FDSLR/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mixxorz%2FDSLR/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mixxorz","download_url":"https://codeload.github.com/mixxorz/DSLR/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245597270,"owners_count":20641863,"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":[],"created_at":"2024-07-31T15:01:16.607Z","updated_at":"2025-03-26T05:31:14.147Z","avatar_url":"https://github.com/mixxorz.png","language":"Python","funding_links":[],"categories":["Python","[🧑‍💻 dev](https://github.com/stars/ketsapiwiq/lists/dev)"],"sub_categories":[],"readme":"\u003cbr /\u003e\n\u003cbr /\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/mixxorz/DSLR\"\u003e\n    \u003cimg width=\"281\" height=\"84\" src=\"https://user-images.githubusercontent.com/3102758/181914025-44bff27e-aac1-4d1b-a037-9fa98f9fed65.png\" alt=\"The DSLR logo\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\u003cbr /\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"\"\u003e\u003cimg src=\"\" alt=\"\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://badge.fury.io/py/dslr\"\u003e\u003cimg src=\"https://badge.fury.io/py/dslr.svg\" alt=\"PyPI version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pypi.python.org/pypi/dslr/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/pyversions/dslr.svg\" alt=\"PyPI Supported Python Versions\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/mixxorz/dslr\"\u003e\u003cimg src=\"https://github.com/mixxorz/dslr/actions/workflows/tests.yml/badge.svg\" alt=\"GitHub Actions (Code quality and tests)\"\u003e\u003c/a\u003e\n\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/3102758/190845105-dd2ec4e6-286b-431d-a33d-490805852b68.png\" alt=\"A terminal showing DSLR's command line interface.\"\u003e\n\u003c/p\u003e\n\n---\n\nDatabase Snapshot, List, and Restore\n\nTake lightning fast snapshots of your local Postgres databases.\n\n## What is this?\n\nDSLR is a tool that allows you to quickly take and restore database snapshots\nwhen you're writing database migrations, switching branches, or messing with\nSQL.\n\nIt's meant to be a spiritual successor to\n[Stellar](https://github.com/fastmonkeys/stellar).\n\n**Important:** DSLR is intended for development use only. It is not advisable to\nuse DSLR on production databases.\n\n## Performance\n\nDSLR is much faster than the standard `pg_dump`/`pg_restore` approach to snapshots.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/3102758/182014327-1b13da6e-63ad-4bbe-817e-7d6c66befc98.png\" alt=\"A chart comparing the execution time between DSLR and pg_dump/pg_restore. For snapshot and restore, DSLR took 4.125 seconds and 4.431 seconds respectively. pg_dump/pg_restore took 36.602 seconds and 13.257 seconds respectively.\"\u003e\n\u003c/p\u003e\n\nDSLR is 8x faster at taking snapshots and 3x faster at restoring snapshots compared to the `pg_dump`/`pg_restore` approach.\n\n\u003cdetails\u003e\n  \u003csummary\u003eTesting methodology\u003c/summary\u003e\n  \n  I spun up Postgres 12.3 using Docker, created a test database, and filled it with 1GB of random data using this script:\n  \n  ```SQL\n  CREATE TABLE large_test (num1 bigint, num2 double precision, num3 double precision);\n\nINSERT INTO large*test (num1, num2, num3)\nSELECT round(random() * 10), random(), random() \\_ 142\nFROM generate_series(1, 20000000) s(i);\n\n```\n\nI used the following commands to measure the execution time:\n\n```\n\ntime dslr snapshot my-snapshot\ntime dslr restore my-snapshot\ntime pg_dump -Fc -f export.dump\ntime pg_restore --no-acl --no-owner export.dump\n\n```\n\nI ran each command three times and plotted the mean in the chart.\n\nHere's the raw data:\n\n| Command       | Run | Execution time (seconds) |\n| ------------- | --- | ------------------------ |\n| dslr snapshot | 1   | 4.797                    |\n|               | 2   | 4.650                    |\n|               | 3   | 2.927                    |\n| dslr restore  | 1   | 5.840                    |\n|               | 2   | 4.122                    |\n|               | 3   | 3.331                    |\n| pg_dump       | 1   | 37.345                   |\n|               | 2   | 36.227                   |\n|               | 3   | 36.233                   |\n| pg_restore    | 1   | 13.304                   |\n|               | 2   | 13.148                   |\n|               | 3   | 13.320                   |\n\u003c/details\u003e\n\n## Install\n\n```\n\npip install DSLR psycopg2 # or psycopg2-binary\n\n```\n\n**Install using pipx**\n\n```\n\npipx install DSLR[psycopg2] # or psycopg2-binary\n\n````\n\nNote: The DSLR `export` and `import` snapshot commands require `pg_dump` and\n`pg_restore` to be present in your `PATH`, so you will need the Postgres CLI\nutilities if you want to use those commands.\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eShell completion\u003c/strong\u003e\u003c/summary\u003e\n\n**Bash**\n\nAdd this to `~/.bashrc`:\n\n```\neval \"$(_DSLR_COMPLETE=bash_source dslr)\"\n```\n\n**Zsh**\n\nAdd this to `~/.zshrc`:\n\n```\neval \"$(_DSLR_COMPLETE=zsh_source dslr)\"\n```\n\n**Fish**\n\nAdd this to `~/.config/fish/completions/dslr.fish`:\n\n```\neval (env _DSLR_COMPLETE=fish_source dslr)\n```\n\nThis is the same file used for the activation script method below. For Fish it’s probably always easier to use that method.\n\nUsing eval means that the command is invoked and evaluated every time a shell is started, which can delay shell responsiveness. To speed it up, write the generated script to a file, then source that.\n\n**Bash**\n\nSave the script somewhere.\n\n```\n_DSLR_COMPLETE=bash_source dslr \u003e ~/.dslr-complete.bash\n```\n\nSource the file in ~/.bashrc.\n\n```\n. ~/.dslr-complete.bash\n```\n\n**Zsh**\n\nSave the script somewhere.\n\n```\n_DSLR_COMPLETE=zsh_source dslr \u003e ~/.dslr-complete.zsh\n```\n\nSource the file in ~/.zshrc.\n\n```\n. ~/.dslr-complete.zsh\n```\n\n**Fish**\n\nSave the script to ~/.config/fish/completions/foo-bar.fish:\n\n```\n_DSLR_COMPLETE=fish_source dslr \u003e ~/.config/fish/completions/dslr.fish\n```\n\n\u003c/details\u003e\n\n\n\n## Configuration\n\nYou can tell DSLR which database to take snapshots of in a few ways:\n\n**DATABASE_URL**\n\nIf the `DATABASE_URL` environment variable is set, DSLR will use this to connect\nto your target database.\n\n```bash\nexport DATABASE_URL=postgres://username:password@host:port/database_name\n````\n\n**dslr.toml**\n\nIf a `dslr.toml` file exists in the current directory, DSLR will read its\nsettings from there. DSLR will prefer this over the environment variable.\n\n```toml\nurl = 'postgres://username:password@host:port/database_name'\n```\n\n**`--url` option**\n\nFinally, you can explicitly pass the connection string via the `--url` option.\nThis will override any of the above settings.\n\n## Usage\n\n```\n$ dslr snapshot my-first-snapshot\nCreated new snapshot my-first-snapshot\n\n$ dslr restore my-first-snapshot\nRestored database from snapshot my-first-snapshot\n\n$ dslr list\n\n  Name                Created            Size\n ─────────────────────────────────────────────\n  my-first-snapshot   2 minutes ago   3253 kB\n\n$ dslr rename my-first-snapshot fresh-db\nRenamed snapshot my-first-snapshot to fresh-db\n\n$ dslr delete some-old-snapshot\nDeleted some-old-snapshot\n\n$ dslr export my-feature-test\nExported snapshot my-feature-test to my-feature-test_20220730-075650.dump\n\n$ dslr import snapshot-from-a-friend_20220730-080632.dump friend-snapshot\nImported snapshot friend-snapshot from snapshot-from-a-friend_20220730-080632.dump\n```\n\nTo force overwriting an existing snapshot in non-interactive shell use the flag `-y`:\n\n```\n$ dslr snapshot my-first-snapshot -y\nUpdated snapshot my-first-snapshot\n```\n\n## How does it work?\n\nDSLR takes snapshots by cloning databases using Postgres' [Template\nDatabases](https://www.postgresql.org/docs/current/manage-ag-templatedbs.html)\nfunctionality. This is the main source of DSLR's speed.\n\nThis means that taking a snapshot is just creating a new database using the main\ndatabase as the template. Restoring a snapshot is just deleting the main\ndatabase and creating a new database using the snapshot database as the\ntemplate. So on and so forth.\n\n## Contributors\n\n[![Contributors](https://contrib.rocks/image?repo=mixxorz/DSLR)](https://github.com/mixxorz/DSLR/graphs/contributors)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmixxorz%2FDSLR","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmixxorz%2FDSLR","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmixxorz%2FDSLR/lists"}