{"id":27294010,"url":"https://github.com/igorcoding/tarantool-spacer","last_synced_at":"2025-10-23T15:52:20.446Z","repository":{"id":19981457,"uuid":"88430077","full_name":"igorcoding/tarantool-spacer","owner":"igorcoding","description":"Tarantool Spacer. Automatic schema migrations.","archived":false,"fork":false,"pushed_at":"2024-03-13T08:06:51.000Z","size":117,"stargazers_count":40,"open_issues_count":7,"forks_count":11,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-11T22:45:46.941Z","etag":null,"topics":["database","helper","lua","migration-tool","migrations","orm","tarantool"],"latest_commit_sha":null,"homepage":"","language":"Lua","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/igorcoding.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","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}},"created_at":"2017-04-16T17:08:52.000Z","updated_at":"2024-02-21T20:59:51.000Z","dependencies_parsed_at":"2024-03-13T09:28:07.847Z","dependency_job_id":"bd63e9e8-0ab4-42f6-81e5-f2d8e9182bec","html_url":"https://github.com/igorcoding/tarantool-spacer","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/igorcoding/tarantool-spacer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorcoding%2Ftarantool-spacer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorcoding%2Ftarantool-spacer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorcoding%2Ftarantool-spacer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorcoding%2Ftarantool-spacer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/igorcoding","download_url":"https://codeload.github.com/igorcoding/tarantool-spacer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorcoding%2Ftarantool-spacer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266430671,"owners_count":23927165,"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","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"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":["database","helper","lua","migration-tool","migrations","orm","tarantool"],"created_at":"2025-04-11T22:45:35.885Z","updated_at":"2025-10-23T15:52:15.417Z","avatar_url":"https://github.com/igorcoding.png","language":"Lua","readme":"# spacer\nTarantool Spacer. Automatic models migrations.\n\n# Changes detected by spacer\n\n* Space create and drop\n* Index create and drop\n* Index options alteration\n    * `unique`\n    * `type`\n    * `sequence`\n    * `dimension` and `distance` (for RTREE indexes)\n    * `parts`\n* Format alterations\n    * New fields (only to the end of format list).\n      Setting values for existing tuples is handled by the [moonwalker](https://github.com/tarantool/moonwalker) library\n    * Field's `is_nullable` and `collation` changes\n    * **[IMPORTANT] `type` and `name` changes are prohibited**\n\n\n# Installation\n\nThe latest `spacer` release is **`3.0.1`**.\n\nUse `luarocks` to install this package by one of the following rockspec from the `rockspecs` folders:\n* `rockspecs/spacer-scm-3.rockspec` - Installs current version 3 from `master` branch\n* `rockspecs/spacer-3.0.1-1.rockspec` - Installs tagged version 3 from `v3.0.1` tag\n\nThere is also a `rockspecs/spacer-scm-1.rockspec` which installs an old **v1** version of spacer (from branch `v1`). This is left here for compatibility reasons for projects that still use spacer v1. Please do not use this version as it is not supported anymore.\n\nSpacer depends on 2 libraries:\n* `inspect` - available from rocks.moonscript.org\n* `moonwalker` - available from rocks.tarantool.org\n\nSo you shold put the following to your `~/.luarocks/config.lua` file:\n```lua\nrocks_servers = {\n    [[http://rocks.tarantool.org]],\n    [[https://rocks.moonscript.org]],\n}\n```\n\nAnd after that you can run\n\n```\nluarocks install https://raw.githubusercontent.com/igorcoding/tarantool-spacer/master/rockspecs/spacer-scm-3.rockspec\n```\n\nto install from master\n\nor\n\n```\nluarocks install https://raw.githubusercontent.com/igorcoding/tarantool-spacer/master/rockspecs/spacer-3.0.1-1.rockspec\n```\n\nto install from the tag.\n\n\n# Usage\n## Initialize\n\nInitialized spacer somewhere in the beginning of your `init.lua`:\n```lua\nrequire 'spacer'.new({\n    migrations = 'path/to/migrations/folder',\n})\n```\n\nYou can assign spacer to a some global variable for easy access:\n```lua\nbox.spacer = require 'spacer'.new({\n    migrations = 'path/to/migrations/folder',\n})\n```\n\n### Spacer options\n\n* `migrations` (required) - Path to migrations folder\n* `name` (default is `''`) - Spacer instance name. You can have multiple independent instances\n* `global_ft` (default is `true`) - Expose `F` and `T` variables to the global `_G` table (see [Fields](#Fields) and [Transformations](#Transformations) sections).\n* `keep_obsolete_spaces` (default is `false`) - do not track space removals\n* `keep_obsolete_indexes` (default is `false`) - do not track indexes removals\n* `down_migration_fail_on_impossible` (default is `true`) - Generate an `assert(false)` statement in a down migration when detecting new fields in format, so user can perform proper actions on a down migration.\n\n## Define spaces\n\nYou can easily define new spaces in a separate file (e.g. `models.lua`) and all\nyou will need to do is to `require` it from `init.lua` right after spacer initialization:\n```lua\nbox.spacer = require 'spacer'.new({\n    migrations = 'path/to/migrations/folder',\n})\nrequire 'models'\n```\n\n### `models.lua` example:\n\nNote that spacer now has methods\n\n```lua\nlocal spacer = require 'spacer'.get()\n\nspacer:space({\n    name = 'object',\n    format = {\n        { name = 'id', type = 'unsigned' },\n        { name = 'name', type = 'string', is_nullable = true },\n    },\n    indexes = {\n        { name = 'primary', type = 'tree', unique = true, parts = {'id'}, sequence = true },\n        { name = 'name', type = 'tree', unique = false, parts = {'name', 'id'} },\n    }\n})\n```\n\n`spacer:space` has 4 parameters:\n1. `name` - space name (required)\n2. `format` - space format (required)\n3. `indexes` - space indexes array (required)\n4. `opts` - any box.schema.create_space options (optional). Please refer to Tarantool documentation for details.\n\nIndexes parts must be defined using only field names.\n\n## Creating migration\n\nYou can autogenerate migration by just running the following snippet in Tarantool console:\n\n```lua\nbox.spacer:makemigration('init_object')\n```\n\nThere are 2 arguments to the `makemigration` method:\n1. Migration name (required)\n2. Options\n* `autogenerate` (`true`/`false`) - Autogenerate migration (default is `true`). If `false` then empty migration file is generated\n* `check_alter` (`true`/`false`) - Default is `true` - so spacer will check spaces and indexes for changes and create alter migrations. If `false` then spacer will assume that spaces never existed. Useful when you want to add spacer to already existing project.\n* `allow_empty` (`true`, `false`) - Default is `true`. If `false` no migration files will be created if there are no schema changes. If `true` an empty migration file will be created instead.\n\nAfter executing this command a new migrations file will be generated under name `\u003ctimestamp\u003e_\u003cmigration_name\u003e.lua` inside your `migrations` folder:\n```lua\nreturn {\n    up = function()\n        box.schema.create_space(\"object\", nil)\n        box.space.object:format({ {\n            name = \"id\",\n            type = \"unsigned\"\n          }, {\n            is_nullable = false,\n            name = \"name\",\n            type = \"string\"\n          } })\n        box.space.object:create_index(\"primary\", {\n          parts = { { 1, \"unsigned\",\n              is_nullable = false\n            } },\n          sequence = true,\n          type = \"tree\",\n          unique = true\n        })\n        box.space.object:create_index(\"name\", {\n          parts = { { 2, \"string\",\n              is_nullable = false\n            }, { 1, \"unsigned\",\n              is_nullable = false\n            } },\n          type = \"tree\",\n          unique = false\n        })\n    end,\n\n    down = function()\n        box.space.object:drop()\n    end,\n}\n```\n\nAny migration file consists of 2 exported functions (`up` and `down`).\nYou are free to edit this migration any way you want.\n\n## Applying migrations\n\nYou can apply not yet applied migrations by running:\n```lua\nbox.spacer:migrate_up(n)\n```\n\nIt accepts `n` - number of migrations to apply (by default `n` is infinity, i.e. apply till the end)\n\nCurrent migration version number is stored in the `_schema` space under `_spacer_ver` key:\n```\ntarantool\u003e box.space._schema:select{'_spacer_ver'}\n---\n- - ['_spacer_ver', 1516561029, 'init']\n...\n```\n\n## Rolling back migrations\n\nIf you want to roll back migration you need to run:\n```lua\nbox.spacer:migrate_down(n)\n```\n\nIt accepts `n` - number of migrations to rollback (by default `n` is 1, i.e. roll back obly the latest migration).\nTo rollback all migration just pass any huge number.\n\n\n## List migrations\n\n```lua\nbox.spacer:list()\n```\n\nReturns list of migrations.\n```\ntarantool\u003e box.spacer:list()\n---\n- - 1517144699_events.lua\n  - 1517228368_events_sequence.lua\n...\n\ntarantool\u003e box.spacer:list(true)\n---\n- - version: '1517144699_events'\n    filename: 1517144699_events.lua\n    path: ./migrations/1517144699_events.lua\n  - version: '1517228368_events_sequence'\n    filename: 1517228368_events_sequence.lua\n    path: ./migrations/1517228368_events_sequence.lua\n...\n\n```\n\n### Options\n* `verbose` (default is false) - return verbose information about migrations. If false returns only a list of names.\n\n\n## Get migration\n\n```lua\nbox.spacer:get(name)\n```\n\nReturns information about a migration in the following format:\n```\ntarantool\u003e box.spacer:get('1517144699_events')\n---\n- version: 1517144699_events\n  path: ./migrations/1517144699_events.lua\n  migration:\n    up: 'function: 0x40de9090'\n    down: 'function: 0x40de90b0'\n  filename: 1517144699_events.lua\n...\n```\n\n### Options\n* `name` (optional) - Can be either a filename or migration version. If not specified - the latest migration is returned\n* `compile` (default is true) - Perform migration compilation. If false returns only the text of migration.\n\n## Get current migration version\n\n```\ntarantool\u003e box.spacer:version()\n---\n- 1517144699_events\n...\n```\n\nReturns current migration's version\n\n## migrate_dummy\n\nYou can force spacer to think that the specified migration is already migrated by setting the appropriate `_schema` space key and registering in `_spacer_models` space all models, registered by calling `spacer:space(...)` function. Convinient when you are migrating an already working project to using spacer.\n\n```lua\nbox.spacer:migrate_dummy(name)\n```\n\n## automigrate\n\nAutomatically applies migrations without creating an actual migration file. Useful when changing schema a lot in development. **Highly discouraged to be used in production**.\nCall this method after all spacer:space(...) calls like this:\n\n```lua\nspacer:space({\n    name = \"object1\",\n    format = {\n        {name = \"id\", type = \"unsigned\"}\n    },\n    indexes = {\n        {name = \"primary\", type = \"tree\", unique = true, parts = {\"id\"}}\n    }\n})\n\nspacer:space({\n    name = \"object2\",\n    format = {\n        {name = \"id\", type = \"unsigned\"}\n    },\n    indexes = {\n      {name = \"primary\", type = \"tree\", unique = true, parts = {\"id\"}}\n    }\n})\n\nspacer:automigrate()\n```\n\nBut when you decide that you need to grenerate migrations - either drop your db and create \nmigrations from scratch or have a loot at [Migrating a project to using spacer](#Migrating-a-project-to-using-spacer).\n\n### Options\n* `name` (required) - Can be either a filename or version number or full migration name.\n\n# Migrating a project to using spacer\n\nIn order to use spacer in an already running project you will need to do the following:\n\n1. Initialize spacer.\n2. Define all your spaces you want to track by spacer by using `spacer:space()` function as usual.\n3. Create a non-altering migration (meaning that it will assume that spaces does not exist yet) by calling\n```\nspacer:makemigration(\u003cmigration_name\u003e, {check_alter = false})\n```\n4. Force-apply migration without actually calling it by using\n```\nspacer:migrate_dummy(\u003cmigration_name\u003e)\n```\n5. That's all\n\nAfter that you can make any changes to the spaces delcarations and track those changes my calling `spacer:makemigration()` function normally and applying migrations with `spacer:migrate_up()` as usual from now on.\n\n# Fields\n\nSpace fields can be accessed by the global variable `F`, which is set by spacer\nor in the spacer directly (`box.spacer.F`):\n\n```lua\nbox.space.space1:update(\n    {1},\n    {\n        {'=', F.object.name, 'John Watson'},\n    }\n)\n```\n\n# Transformations\n\nYou can easily transform a given tuple to a dictionary-like object and vice-a-versa.\n\nThese are the functions:\n* `T.space_name.dict` or `T.space_name.hash` - transforms a tuple to a dictionary\n* `T.space_name.tuple` - transforms a dictionary back to a tuple\n\nT can be accessed through the global variable `T` or in the spacer directly (`box.spacer.T`)\n\n```lua\nlocal john = box.space.object:get({1})\nlocal john_dict = T.object.dict(john) -- or T.object.hash(john)\n--[[\njohn_dict = {\n    id = 1,\n    name = 'John Watson',\n    ...\n}\n--]]\n\n```\n\n... or vice-a-versa:\n\n```lua\nlocal john_dict = {\n    id = 1,\n    name = 'John Watson',\n    -- ...\n}\n\nlocal john = T.object.tuple(john_dict)\n--[[\njohn = [1, 'John Watson', ...]\n--]]\n\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorcoding%2Ftarantool-spacer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figorcoding%2Ftarantool-spacer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorcoding%2Ftarantool-spacer/lists"}