{"id":15041115,"url":"https://github.com/geirolz/fly4s","last_synced_at":"2025-04-11T17:43:30.648Z","repository":{"id":39859549,"uuid":"388502752","full_name":"geirolz/fly4s","owner":"geirolz","description":"A lightweight, simple and functional wrapper of Flyway using cats effect.","archived":false,"fork":false,"pushed_at":"2024-04-20T09:48:02.000Z","size":502,"stargazers_count":58,"open_issues_count":3,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-04-20T10:46:02.786Z","etag":null,"topics":["cats","cats-effect","data","database","database-migrations","db","flyway","flyway-migrations","flywaydb","functional-programming","persistence","scala"],"latest_commit_sha":null,"homepage":"https://geirolz.github.io/fly4s/","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/geirolz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"patreon":"geirolz"}},"created_at":"2021-07-22T15:03:38.000Z","updated_at":"2024-06-09T14:40:46.734Z","dependencies_parsed_at":"2023-09-29T00:13:17.821Z","dependency_job_id":"20831cb3-115e-44ba-bcae-8160b876b4a2","html_url":"https://github.com/geirolz/fly4s","commit_stats":{"total_commits":373,"total_committers":6,"mean_commits":"62.166666666666664","dds":0.6836461126005362,"last_synced_commit":"f1332558525244d78b0f596c9955b686a4d8e5fb"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geirolz%2Ffly4s","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geirolz%2Ffly4s/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geirolz%2Ffly4s/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geirolz%2Ffly4s/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/geirolz","download_url":"https://codeload.github.com/geirolz/fly4s/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248451928,"owners_count":21105974,"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":["cats","cats-effect","data","database","database-migrations","db","flyway","flyway-migrations","flywaydb","functional-programming","persistence","scala"],"created_at":"2024-09-24T20:45:36.773Z","updated_at":"2025-04-11T17:43:30.629Z","avatar_url":"https://github.com/geirolz.png","language":"Scala","funding_links":["https://patreon.com/geirolz"],"categories":[],"sub_categories":[],"readme":"# Fly4s\n[![Build Status](https://github.com/geirolz/fly4s/actions/workflows/cicd.yml/badge.svg)](https://github.com/geirolz/fly4s/actions)\n[![codecov](https://img.shields.io/codecov/c/github/geirolz/fly4s)](https://codecov.io/gh/geirolz/fly4s)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/32b85d22894d479491bed9bbf64a2651)](https://app.codacy.com/gh/geirolz/fly4s/dashboard?utm_source=gh\u0026utm_medium=referral\u0026utm_content=\u0026utm_campaign=Badge_grade)\n[![Sonatype Nexus (Releases)](https://img.shields.io/nexus/r/com.github.geirolz/fly4s_2.13?server=https%3A%2F%2Foss.sonatype.org)](https://mvnrepository.com/artifact/com.github.geirolz/fly4s)\n[![Scala Steward badge](https://img.shields.io/badge/Scala_Steward-helping-blue.svg?style=flat\u0026logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org)\n[![Mergify Status](https://img.shields.io/endpoint.svg?url=https://api.mergify.com/v1/badges/geirolz/fly4s\u0026style=flat)](https://mergify.io)\n[![GitHub license](https://img.shields.io/github/license/geirolz/fly4s)](https://github.com/geirolz/fly4s/blob/main/LICENSE)\n\n\u003cdiv align=\"center\"\u003e\n \u003cimg src=\"images/logo.png\" alt=\"logo\" width=\"50%\"/\u003e\n\u003c/div\u003e\n\nA lightweight, simple and functional wrapper for Flyway using cats-effect.\n\n### Compatibility matrix\n\n|                               **Fly4s**                               | **Flyway** |                        **Branch**                        |\n|:---------------------------------------------------------------------:|:----------:|:--------------------------------------------------------:|\n| [0.x](https://github.com/geirolz/fly4s/releases?q=v0.\u0026expanded=false) |    9.x     | [0.x-9.x](https://github.com/geirolz/fly4s/tree/0.x-9.x) |\n| [1.x](https://github.com/geirolz/fly4s/releases?q=v1.\u0026expanded=false) |    10.x    |    [main](https://github.com/geirolz/fly4s/tree/main)    |\n\n\nThe most famous library to handle database migrations in Java is for sure Flyway.\nIt works very well and the community edition has a lot of features as well.\nBut Flyway APIs are written in the standard OOP paradigm, so throwing exceptions, manually managing resources, etc...\n\n`Fly4s` is a lightweight, simple and functional wrapper for Flyway.\nThe aim of `Fly4s` is straightforward, wrapping the `Flyway` APIs to guarantee\nreferential transparency, pureness, resource handling and type safety.\nTo achieve this goal, `Fly4s` use the typelevel libraries `cats` and `cats-effect`.\n\n- [Getting started](#getting-started)\n- [Migrations files](#migrations-files)\n- [Defining database configuration](#defining-database-configuration)\n- [Instantiating Fly4s](#instantiating-fly4s)\n- [Using Fly4s](#using-fly4s)\n- [Conclusions](#conclusions)\n- [Useful links](#useful-links)\n---\n\n### Adopters\nIf you are using Fly4s in your company, please let me know and I'll add it to the list! It means a lot to me.\n\n\u003ca href=\"https://www.codacy.com/\"\u003e\n \u003cpicture\u003e\n   \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://www.codacy.com/hubfs/Codacy_2023/Images/logo_codacy_white.svg\"\u003e\n   \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://www.codacy.com/hubfs/Codacy_2023/Images/logo_codacy.svg\"\u003e\n   \u003cimg alt=\"Codacy Logo\" height=55 \u003e\n \u003c/picture\u003e\n\u003c/a\u003e\n\n### Getting started\nFly4s supports Scala 2.13 and 3.\nThe first step, import the `Fly4s` library in our SBT project.\nSo, add the dependency in your `build.sbt` file.\nFly4s depends on Flyway, so we'll have access to Flyway as well\n\n```sbt\nlibraryDependencies += \"com.github.geirolz\" %% \"fly4s\" % \"1.0.8\"\n```\n\nRemember to also import the specific database module from Flyway\n\nhttps://documentation.red-gate.com/flyway/flyway-cli-and-api/supported-databases\n\n### Migrations files\nAs the plain Flyway, we have to create a folder that will contain our migrations scripts, often in `resources/db`.\n\nIn this folder, we have to put all our migration. We can have:\n- [Baseline migrations](https://flywaydb.org/documentation/tutorials/baselineMigrations)\n- [Repeatable migrations](https://flywaydb.org/documentation/tutorials/repeatable)\n- [Undo migrations](https://flywaydb.org/documentation/tutorials/undo)\n\nFor this example, we are going to use a simple `baseline migration` to add a table to our database schema.\n\nBaseline migrations are versioned and executed only when needed. The version is retrieved from the script file name.\n\nSo in this case, `V001__create_user_table.sql`, the version will be `001`(remember the double underscore after `V`).\n\nHere we have our first migration(for MySQL database)\n\n`resources/db/V001__create_user_table.sql`\n```sql\nCREATE TABLE `user` (\n    `id` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,\n    `name` varchar(30) NOT NULL,\n    `surname` varchar(30) NOT NULL\n);\n```\n\n### Defining database configuration\nA good practice is to create a case class to handle the database configuration(this combined with PureConfig \nor others\nconfig libraries make your app very robust from the configuration point of view)\n\nLet's create a simple case class to achieve this.\n```scala\ncase class DatabaseConfig(\n  url: String,\n  user: Option[String],\n  password: Option[Array[Char]],\n  migrationsTable: String,\n  migrationsLocations: List[String]\n)\n``` \n\nN.B. apart from the common fields such `url`, `user` and `password` we'll use: `migrationsTable` to define the\nFlyway table name(used to store the migration status) and `migrationsLocations` to specify a list\nof the folders that contain our migration scripts.\n\n### Instantiating Fly4s\nOk so, now we have all our migration scripts in our folder(`resources/db`), we have `Fly4s` as a dependency \nof our project,\nand we have a case class that will contain the database configuration.\n\nTo instantiate `Fly4s` we can use `make` to create a new DataSource(under the hood) starting from the parameters\nor `makeFor` in order to create it for an already existent `DataSource`(for example from Doobie HikariDataSource).\n`make` and `makeFor` method returns a [`Resource`](https://typelevel.org/cats-effect/docs/std/resource) type class\nthat when released/interrupted safely close the `DataSource` connection.\n\nIn both `make` and `makeFor` methods, we can specify the parameter `config`. `Fly4sConfig` is a trivial wrapper for\nflyway `Configuration` but instead of having a builder we have a case class.\n\n```scala\nimport fly4s.*\nimport fly4s.data.*\nimport cats.effect.*\n\nval dbConfig: DatabaseConfig = DatabaseConfig(\n  url                 = \"url\",\n  user                = Some(\"user\"),\n  password            = None,\n  migrationsTable     = \"flyway\",\n  migrationsLocations = List(\"db\")\n)\n// dbConfig: DatabaseConfig = DatabaseConfig(\n//   url = \"url\",\n//   user = Some(value = \"user\"),\n//   password = None,\n//   migrationsTable = \"flyway\",\n//   migrationsLocations = List(\"db\")\n// )\n\nval fly4sRes: Resource[IO, Fly4s[IO]] = Fly4s.make[IO](\n  url                 = dbConfig.url,\n  user                = dbConfig.user,\n  password            = dbConfig.password,\n  config = Fly4sConfig(\n    table     = dbConfig.migrationsTable,\n    locations = Locations(dbConfig.migrationsLocations)\n  )\n)\n// fly4sRes: Resource[IO, Fly4s[IO]] = Allocate(\n//   resource = cats.effect.kernel.Resource$$$Lambda/0x00000007030bf0c0@1950092a\n// )\n```\n\n### Using Fly4s\nOk, we have done with the configuration!\nWe are ready to migrate our database schema with the power of Flyway and the safety of Functional Programming!\n\nWe can use `use` or `evalMap` from `Resource` to safely access to the Fly4s instance. In case we have\nmultiple `Resource`s in our application probably `evalMap` allow us to better combine them using and releasing\nthem all together at the same time.\n\nWe can create a simple util method to do this\n\n```scala\nimport fly4s.implicits.*\n\ndef migrateDb(dbConfig: DatabaseConfig): Resource[IO, MigrateResult] =\n  Fly4s.make[IO](\n    url                 = dbConfig.url,\n    user                = dbConfig.user,\n    password            = dbConfig.password,\n    config = Fly4sConfig(\n      table     = dbConfig.migrationsTable,\n      locations = Locations(dbConfig.migrationsLocations)\n    )\n  ).evalMap(_.validateAndMigrate.result)\n```\n\n### Conclusions\nWe have done it! So, to recap, we have:\n1. Created a folder under `resources` to put our migrations(`db`)\n2. Imported `Fly4s` as a dependency in our project\n3. Created a configuration case class to describe our database configuration\n4. Instantiated a `Fly4s` instance creating a new `DataSource`\n5. Migrated our database using `validateAndMigrate`\n6. At the application shutdown/interruption `Resource`(from cats-effect) will safely release the `DataSource`\n\nWith a few lines, we have migrated our database safely handling the connection and the configuration.\n\nAs flyway, Fly4s provides multiple methods such as:\n- validateAndMigrate\n- migrate\n- undo\n- validate\n- clean\n- info\n- baseline\n- repair\n\n\n##### Useful links\n- https://flywaydb.org/documentation\n- https://typelevel.org/cats/\n- https://typelevel.org/cats-effect/\n- https://pureconfig.github.io/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeirolz%2Ffly4s","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeirolz%2Ffly4s","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeirolz%2Ffly4s/lists"}