{"id":16371105,"url":"https://github.com/jodersky/simplesql","last_synced_at":"2025-03-16T15:33:08.244Z","repository":{"id":44546715,"uuid":"312883195","full_name":"jodersky/simplesql","owner":"jodersky","description":"A no-frills SQL library for Scala 3","archived":false,"fork":false,"pushed_at":"2024-10-10T08:11:19.000Z","size":65,"stargazers_count":29,"open_issues_count":0,"forks_count":2,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-10-18T06:21:12.137Z","etag":null,"topics":["jdbc","scala3","sql"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jodersky.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":"2020-11-14T19:03:28.000Z","updated_at":"2024-10-10T08:11:23.000Z","dependencies_parsed_at":"2024-08-11T11:00:24.368Z","dependency_job_id":null,"html_url":"https://github.com/jodersky/simplesql","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jodersky%2Fsimplesql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jodersky%2Fsimplesql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jodersky%2Fsimplesql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jodersky%2Fsimplesql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jodersky","download_url":"https://codeload.github.com/jodersky/simplesql/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221665593,"owners_count":16860286,"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":["jdbc","scala3","sql"],"created_at":"2024-10-11T03:07:01.029Z","updated_at":"2024-10-27T10:51:38.997Z","avatar_url":"https://github.com/jodersky.png","language":"Scala","readme":"# Simple SQL\n\nA no-frills SQL library for Scala 3.\n\nSimpleSQL is a very thin wrapper around JDBC, which allows you to take full\nadvantage of *full SQL* and *any database* with a JDBC driver.\n\nSimpleSQL is not a functional DSL to build SQL queriesq, but it does offer safe\nstring interpolation and utilities to work with product types, wich are the\nnatural representation of relational data sets.\n\nSimpleSQL only uses Hikari for database connection pooling, but has no\ndependencies otherwise (and even that can easily be removed). It is published to\nmaven central, under `io.crashbox:simplesql_3:0.4.0`, but **it can also be embedded by\ncopying the file\n[simplesql/src/simplesql.scala](https://raw.githubusercontent.com/jodersky/simplesql/master/simplesql/src/simplesql.scala)\ninto your application**!\n\n## Example\n\n```scala\nimport simplesql as sq\n\n// a plain DataSource is needed, this example uses a connection pool implemented\n// by HicariCP\nval ds = sq.DataSource.pooled(\"jdbc:sqlite::memory:\")\n\n// all queries must be run within the context of a connection, use either\n// `\u003cds\u003e.run` or `\u003cds\u003e.transaction` blocks\nds.transaction:\n  sql\"\"\"\n    create table user (\n      id integer primary key,\n      name text not null,\n      email text not null\n    )\n  \"\"\".write()\n\n  sql\"select * from user\".read[(Int, String, String)]\n  sql\"\"\"insert into user values (1, 'admin', 'admin@example.org')\"\"\".write()\n\n  case class User(id: Int, name: String, email: String) derives sq.Reader\n  sql\"select * from user\".read[User]\n\n  sql\"select name, id from user where id = ${1}\".read[(String, Int)]\n```\n\n## Explanation\n\n### Database connection\n\nAll queries must be run on a connection to a database. SimpleSQL models this\nthrough a `Connection` class, which is just a simple wrapper around\n`java.sql.Connection`.\n\nA connection may be obtained as a [context\nfunction](https://dotty.epfl.ch/docs/reference/contextual/context-functions.html)\nthrough either `\u003cdatasource\u003e.run` or `\u003cdatasource\u003e.transaction`. Both functions\nprovide a connection, however the latter will automatically roll back any\nchanges, should an exception be thrown in its body.\n\nAn in-scope connection also gives access to the `sql` string interpolator. This\ninterpolator is a utility to build `simplesql.Query`s, which are builders for\n`java.sql.PreparedStatements`. In other words, it can be used to build\ninjection-safe queries with interpolated parameters. Interpolated parameters\nmust be primitve types (supported by JDBC).\n\n### Read Queries\n\nRead queries (e.g. selects) must be run in a `read` call. A read must have its\nresult type specified. The result type may be any primitive type supported by\nJDBC `ResultSet`s or a product thereof (including named products, i.e. `case\nclass`es).\n\nFields of case classes are converted to `snake_case` in the database. You can\noverride this by annotating them with `simplesql.col(\"name\")`.\n\n### Write Queries\n\nWrite queries (e.g. insertions, updates, deletes and table alterations) must be\nrun in a `write` call.\n\n## Migrations\n\nSimplesql also has an experimental module to manage database migrations. This is\nincluded if simplesql is consumed via maven, otherwise it must be added by\ncopying the file in `simplesql/src/simplesql/migrations.scala`.\n\nEssentially, the module works by looking for `.sql` files in a folder on the\nclasspath (typically packaged in your final application jar) and applying them\n\"in order\" to reach a specific version (see below). The module also adds a\nspecial table to your datasource to keep track of which migrations have been\nalready applied.\n\n### Defining a migration\n\nA migration is an sql file which consists of:\n\n- a unique name\n- a reference to the version which precedes it (or \"base\" if nothing should precede it)\n- upgrade sql statements\n- downgrade sql statements\n\nthis information apart from the file name is encoded in the following way:\n\n```sql\n-- prev: \u003cprev version\u003e\n\n  -- upgrade statements\n\n-- down:\n\n  -- downgrade statements\n```\n\nThe upgrade and downgrade statements are placeholders for actual SQL. The `--\nprev` and `-- down` comments have special meaning for migrations however and\nmust appear literally.\n\nSee simplesql/test/resources/migrations/ for some example files.\n\n### Applying a migration\n\n```scala\nval mdb = simplesql.migrations.MigrationTool.fromClasspath(\n  simplesql.DataSource.pooled(\"jdbc:sqlite::memory:\")\n)\n\nmdb.applyUp(\"0001_data.sql\") // migrate upwards to explicit version\nmdb.applyUp(\"head\") // \"head\" means the \"newest\" version, it will fail if there are multiple newest versions\nmdb.applyDown(\"base\") // \"base\" is a special version which means the initial version before any migration was ever applied\n```\n\nNote: we recommend only ever downgrading for development purposes. In\nproduction, any mistakes should always be corrected with upgrading migrations.\n\n### Order of migrations\n\nEach migration must have a pointer to a previous migration file. When applying a\nmigration, the system will first do a topological sort from the target\nmigration, and then apply migrations that are necessary.\n\nUsing explicit pointers instead of relying on filename order has a couple of\nbenefits:\n\n- It allows branching during development.\n- Since and error will occur if attempting to migrate to the head version when\n  there are multiple heads, it eliminates a source of data corruption if multiple\n  migrations are devloped simultanously and merged together without rebasing\n  them into a linear sequence.\n\n### Acknowledgements\n\nThe idea of branching in the migration library has been inspired from\n[Alembic](https://alembic.sqlalchemy.org/en/latest/). However, instead of\nallowing migration merges, we explicitly require rebases to a linear history.\nAlso, migration versions correspond 1-1 with file names instead of synthetic\nversion identifiers that are part of the file names. We believe that this allows\ndevelopers to benefit from lexicographically sorted migrations (e.g. by calling\nyour migrations `0000-init.sql`, `0001-foo.sql`, `0002-bar.sql` etc), but still\nprevent accidental non-determinism when developing concurrently with others. It\nalso makes it easy to write migrations by hand without the need of a separate\ntoo to manage them for us.\n\n## Changelog\n\n### 0.4.0\n\n- Rework migrations module to a graph-based system.\n\n### 0.3.0\n\n- Make `run` and `transaction` methods of `DataSource` instead of top-level\n  functions. Also make `read` and `write()` methods on the type returned by `sql`.\n  This removes an argument list in syntax. E.g. instead of\n\n  ```scala\n  sq.transaction(ds):\n    sq.read[A](sql\"\"\"...\"\"\")\n  ```\n\n  the syntax is now\n\n  ```scala\n  ds.transaction:\n    sql\"\"\"...\"\"\".read[A]\n  ```\n\n- Include HikariCP as a dependency for convenience\n\n- Separate the reader hierarchy in two:\n\n  - primitive \"simple\" readers read database columns and typically map to\n    primitive database types\n  - normal readers user tuples of simple readers to read rows and map them to\n    more complex scala types\n\n- Readers of case classes use column names instead of positions.\n\n### 0.2.0\n\nSee git history\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjodersky%2Fsimplesql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjodersky%2Fsimplesql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjodersky%2Fsimplesql/lists"}