{"id":20461002,"url":"https://github.com/ericgj/wineskins","last_synced_at":"2026-04-18T05:31:36.353Z","repository":{"id":4527326,"uuid":"5667419","full_name":"ericgj/wineskins","owner":"ericgj","description":"A database transfer utility built on Sequel","archived":false,"fork":false,"pushed_at":"2012-09-06T16:21:33.000Z","size":160,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-09T18:52:01.014Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ericgj.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-09-04T04:20:14.000Z","updated_at":"2013-12-18T20:50:39.000Z","dependencies_parsed_at":"2022-09-25T02:40:13.738Z","dependency_job_id":null,"html_url":"https://github.com/ericgj/wineskins","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ericgj/wineskins","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fwineskins","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fwineskins/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fwineskins/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fwineskins/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ericgj","download_url":"https://codeload.github.com/ericgj/wineskins/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fwineskins/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31957546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T00:39:45.007Z","status":"online","status_checked_at":"2026-04-18T02:00:07.018Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-11-15T12:22:48.453Z","updated_at":"2026-04-18T05:31:36.335Z","avatar_url":"https://github.com/ericgj.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# Wineskins\n\nA Ruby database transfer utility built on [Sequel](http://sequel.rubyforge.org/).\n\nSometimes your old wine needs to be poured into new skins too.\n\n## Basic usage\n\nFrom the command line, the utility runs __transfer instructions__ for a specified\n__source__ and __destination__ database. By default, it looks for these instructions\nin the file `./transfer.rb`. (The syntax of these instructions will be \ndescribed in a moment.) So the easiest way to execute the utility is:\n\n    wskins some-db://source/url some-other-db://dest/url\n    \nThis will run the instructions in ./transfer.rb to transfer the schema and/or \ndata from the specified source database (as a URL recognized by \n`Sequel.connect`), to the specified destination database.\n\nYou can specify another transfer instructions file via `--config`:\n\n    wskins --config path/to/transfer.rb some-db://source/url some-other-db://dest/url\n    \nIf your databases can't be opened easily via a URL, instead you can manually set\nthe constants `SOURCE_DB` and `DEST_DB` to your Sequel databases within a ruby \nscript, and require that script from the command line like this:\n\n    wskins --require path/to/db/setup.rb\n\n(This is necessary for instance if you are using ADO adapters.)\n\nRun `wskins --help` to see complete usage options.\n\n## How to install\n\n[Get Ruby](http://www.ruby-lang.org/en/downloads/) if you don't have it.\n\nThen\n  \n    gem install wineskins\n    \nThis will also install the sequel gem. If Sequel needs native drivers for your \ndatabase(s), install them separately. Consult the \n[Sequel docs](http://sequel.rubyforge.org/) for more info.\n\n## Transfer instructions syntax\n    \n### A very simple case:\n\n    tables :students, :classes, :enrollments\n    \nThis will copy the tables, indexes, and foreign key constraints, and then insert \nall the records, for the three listed tables.\n\n### To rename tables:\n\n    tables :students, [:classes, :courses], :enrollments\n    \nThe `classes` table in the source will be renamed `courses` in the destination. \nAll foreign keys referencing `classes` (in e.g. the `enrollments` table) will be \nchanged accordingly.\n\nIf you are copying records, be careful in the order you list the tables -- this\nis the order that the records will be inserted. If you have foreign key\nconstraints between two tables, you must list the target (primary key) table \nfirst to ensure that the keys exist before inserting the foreign key table\nrecords. \n\nSo in this example, the `:students` and `:classes` tables are transferred _before_\nthe `:enrollments` table, which presumably has foreign keys to `:students` and\n`:classes`.\n\n### To rename fields:\n\n    table :classes, :rename =\u003e {:class_id =\u003e :id}\n    \nPrimary keys, indexes, foreign keys will be changed accordingly in the \ndestination database.\n\n### Want to copy the schema, but not import data yet?\n\n    tables :students, :classes, :enrollments, :schema_only =\u003e true\n    \n### Have the schema in place, just need to import data?\n\n    tables :students, :classes, :enrollments, :records_only =\u003e true\n    \nYou have finer-grained control as well:\n\n    table :students, :create_tables =\u003e true, \n                     :create_indexes =\u003e false,\n                     :create_fk_constraints =\u003e false,\n                     :insert_records =\u003e true\n\n### Adjusting column definitions\n\nSometimes you need to manually adjust column types or other options in the\ndestination: for example due to different conventions between databases. You can \npass through column definitions to Sequel's schema generator, and they will be \nused _instead of_ the source database table:\n\n    table :classes do\n      column :slots, :integer, :null =\u003e false, :default =\u003e 25\n    end\n    \nNote that in this example, all of the column definitions _except `slots`_ will \nbe copied from the source table, while `slots` will be defined as specified.\n\n### Excluding and including columns\n\n(_Note: not yet implemented._)\nYou can also exclude specific columns entirely, or include only specified columns:\n\n    table :enrollments, :exclude =\u003e [:final_grade, :status]\n    table :students, :include =\u003e [:id, :name, :grad_year]\n\nAlthough it's nearly as easy to do this manually in a hook (see below).\n\n### Limiting the imported data\n\n(_Note: not yet implemented._)\nIt's also possible to specify a filter on the source records that get imported.\n\n    table :students do\n      insert_records :grad_year =\u003e (2010..2012)\n    end\n\nFilters can be anything that Sequel accepts as arguments to `Dataset#filter`.\n\n### Generating a transcript\n    \nIf you just want a script for generating the schema later, and don't actually\nwant to make database changes, do something like this:\n\n    transcript 'path/to/transfer.sql'\n    tables :schema_only =\u003e true\n\nand include the `--dry-run` option on the command line.\n\n### Hooks for manual futzing\n\nWineskins executes a given transfer in four stages:\n\n  1. All the tables are created (`:create_table`)\n  2. All the indexes are created via `alter_table` (`:create_indexes`)\n  3. All the foreign key constraints are created via `alter_table` (`:create_fk_constraints`)\n  4. The records are inserted into each table from the source database (`:insert_records`)\n  \nEach of these stages has a `before_*` and `after_*` hook where you can stick\nwhatever custom steps you need using Sequel's incredibly wide toolset, and there\nare also general `before` and `after` hooks that run before and after the entire\ntransfer. You can define as many of these as you want at each hook. For \ninstance (to turn off foreign key constraints before inserting records):\n\n    before_insert_records do\n      dest.pragma_set 'foreign_keys', 'off'\n    end\n    \nOr to take the example above of excluding columns, you could do this manually\nin a callback like:\n\n    after_create_tables do\n      dest[:enrollments].alter_table do\n        drop_column :final_grade\n        drop_column :status\n      end\n    end\n  \nWithin callbacks, the source database is referenced via `source`, the \ndestination database via `dest`.\n\n### A note on the syntax\n\nIn the examples above I've used both a 'hash-options' style and a block syntax.\nEither can be used interchangably and even in combination if you want (although\nit's ugly looking). The options set in the block always override the options\nhash. Also, note that custom `column` definitions must be done within a block.\n\n## Motivations\n\nThis tool aims to simplify transferring data between databases, and is designed \naround the canonical case where the destination database is completely empty, \nand you want to set up everything the way it is in the source and then import \nthe data. Of course, many other scenarios are possible, but the point is that \nthe only things you should need to specify are either (1) differences from this\nscenario, or (2) differences between database adapters that Sequel cannot \nhandle automatically. \n\nNote that accordingly, if schema or records already exist in your destination,\nyou are responsible for dealing with this in whatever way makes sense for your\nscenario. No tables, indexes, constraints, or records are automatically deleted\nin the destination.\n\nSo, you might want to wipe out and replace what exists (via `drop_table`,\n`dest[:table].delete`, etc. in callbacks); or you might want to keep what \nexists (omitting changes via `:schema_only`, `:records_only` options, etc.); or\nyou might want to alter what exists (via custom `alter_table`, \n`dest[:table].filter(some_filter).delete`, etc. in callbacks).\n\nThe principle is that _as much as possible, the source database should determine\nthe schema of the destination database_, thus minimizing manually-entered (and \npossibly incorrect) schema definition code. Also it helps avoid, for simple but \ntypical cases, the great pain and knashing of the teeth involved in massaging \nthe source data into the right format for for importing.\n\n## Alternatives / Similar projects\n\n- Sequel's [schema dumper extension](http://sequel.rubyforge.org/rdoc-plugins/files/lib/sequel/extensions/schema_dumper_rb.html) lets you dump and load schema using Sequel's migration DSL.\n- [DbCopier](https://github.com/santosh79/db-copier), apparently unmaintained?\n- [Linkage](https://github.com/coupler/linkage) mimics joins between tables in\ndifferent databases.\n\n## Please help\n\nThis is a young young project, don't expect it will work out of the box without\nsome futzing. It's only been formally tested on Sqlite to Sqlite transfers, and\nad-hoc tested on a 'real' MS Access to Sqlite transfer.\n\nIf you start using it and run into weird shit, at the very least let me know \nabout it. Better still if you send some informed guesses as to what's going on. \nPull requests are awesome and going the extra mile and all that... but before \nyou go to the trouble, unless it's a really minor fix, let me know about the \nissue, I might be able to save you some time and we can have a conversation \nabout it you know?\n\nThere's a TODO list in the project root if you want to see where I'm thinking \nof heading, comments welcome.\n\n\n## Requirements\n\n  - ruby \u003e= 1.8.7\n  - sequel ~\u003e 3.0 (note \u003e= 3.39 needed for MS Access source databases)\n  - progressbar (optional)\n  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericgj%2Fwineskins","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fericgj%2Fwineskins","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericgj%2Fwineskins/lists"}