{"id":19123811,"url":"https://github.com/mauricioszabo/relational-scala","last_synced_at":"2026-06-22T11:31:49.011Z","repository":{"id":10021531,"uuid":"12061259","full_name":"mauricioszabo/relational-scala","owner":"mauricioszabo","description":"Scala's ORM. Tries to fit nicely into the language, but not aims for type-safety.","archived":false,"fork":false,"pushed_at":"2014-10-14T20:07:57.000Z","size":476,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-22T13:43:41.204Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Scala","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/mauricioszabo.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}},"created_at":"2013-08-12T16:56:36.000Z","updated_at":"2018-10-03T09:47:33.000Z","dependencies_parsed_at":"2022-08-28T14:00:45.443Z","dependency_job_id":null,"html_url":"https://github.com/mauricioszabo/relational-scala","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mauricioszabo/relational-scala","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mauricioszabo%2Frelational-scala","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mauricioszabo%2Frelational-scala/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mauricioszabo%2Frelational-scala/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mauricioszabo%2Frelational-scala/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mauricioszabo","download_url":"https://codeload.github.com/mauricioszabo/relational-scala/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mauricioszabo%2Frelational-scala/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34647747,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"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-09T05:27:14.247Z","updated_at":"2026-06-22T11:31:48.996Z","avatar_url":"https://github.com/mauricioszabo.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"Relational Scala\n================\n\nAn API to query databases.\n\n## Motivation\nORMs are quite interesting pieces of software: they can generate SQL in such a\nway that it is secure and simple. But the simple truth is that they do not\nsolve every problem, and in most ways we need to generate SQL by hand.\n\nThe problem is the \"gap\"\n\nWhen we generate SQL by hand, we lost most of the advantages that ORMs give us.\nOn the other hand, when we use the ORM, things \"just work\" but we lost all the\nfine-tuning queries we can use.\n\n## Enter Relational Scala\nUsing the power of Scala and flexibility of SQL, we can create a fine-tunned\nquery without losing power on the SQL way. Some tradeoffs need to be taken-we\nnever write SQL in string way, but we can do quite close using Scala's operator\noverloading.\n\nWe don't ever use SQL Strings in Relational because we never really lose information\nabout where every part of SQL came from. For example, let's see the following\nquery (in SQL):\n\n```sql\nSELECT \"users\".*, \"a\".\"road\" FROM \"users\" INNER JOIN \"addresses\" \"a\" ON \"a\".\"user_id\" = \"users\".\"id\" WHERE \"users\".\"name\" LIKE 'Adam%' OR \"users\".\"age\" \u003e 20\n```\n\nIn Relational, this query is basically the following list of classes:\n\n```scala\nimport relational._\n\nval users = tables.Table(\"users\")\nval aliased = tables.Alias(\"a\", tables.Table(\"users\"))\n\nval query = Selector(\n  select=clauses.Select.select(attributes.AllInTable(users), attributes.Attribute(aliased, \"road\")),\n  from=Seq(users),\n  join=Seq(\n    joins.InnerJoin(\n      aliased, \n      comparissions.Equality(\n        comparission.Equality.Equals, \n        attributes.Attribute(aliased, \"user_id\"), \n        attributes.Attribute(users, \"id\")\n      )\n    )\n  ),\n  where=comparissions.Or( Vector(\n    comparissions.Equality(\n      comparission.Equality.Like, \n      attributes.Attribute(users, \"name\"), \n      attributes.Literal(\"Adam%\")\n    ),\n    comparissions.Equality(\n      comparission.Equality.Gt, \n      attributes.Attribute(users, \"age\"), \n      attributes.Literal(20)\n    )\n))\n)\n```\n\nOf course, the above way is far too verbose to be usable, but it presents a very interesting\nconcept: queries are formed by \"fragments\", or in Relational's terms, `Partial`s. A `Partial`\nis a function that takes an `Adapter` and returns a `(String, Seq[Any])`. The  advantage\nof this approach is that we never really lose SQL information: we know that **WHERE** clause\ncame from an `Or`, and inside this `Or` we have two `Equality` - one like, and one equal.\n\nThis advantage permits us to negate whole bunch of queries, or join them, with ease. Even\nmore, it makes it easy to identify malformed queries, or similar queries, and even to create\na query incrementally: we can just \"add\" more conditions into a where, or \"add\" more joins,\nwith ease.\n\n##Simple Queries\n\nSupose we want to find a list of people:\n\n```scala\nimport relational._\n\nobject People extends Query {\n}\n\nPeople.where { p =\u003e p('name) like \"Foo\" }\nPeople.where { p =\u003e p('id) \u003c 10 || p('id) \u003e 20 }\n\n```\n\nWe can construct our queries using `select`, `group`, `having`, `where`,\n`order`, `leftJoin`, `innerJoin` (or just `join`), `rightJoin`, `from`, etc.\n\n```scala\n//Finds all people that has someone with the same name in this table\nPeople.\n  select { p =\u003e p('name), p('name).count.as(\"number\") }.\n  where { p =\u003e p('age) \u003e 18 }.\n  group { p =\u003e p('name) }.\n  having { p =\u003e p('name).count \u003e 1 }\n```\n\nBut this is tedious to do (all these blocks), so there is a better way:\n\n```scala\nPeople.query { p =\u003e\n  p.select (p('name), p('name).count.as(\"number\") ).\n  where (p('age) \u003e 18).\n  group (p('name)).\n  having (p('name).count \u003e 1)\n}\n```\n\nCombining these two techiques, we can even use \"implicits\" to be more concise:\n\n```scala\nPeople.query { implicit p =\u003e\n  p.select ('name, 'name.count.as(\"number\") ).\n  where ('age \u003e 18).\n  group ('name).\n  having ('name.count \u003e 1)\n}\n```\n\n## Joins\nIt is possible to make joins (even the most complex ones) using a simple\nsyntax: there are the methods `leftJoin`, `rightJoin`, and `join` (inner join).\nEach of these perform a simple join and return a \"JoinHelper\" object, where you\ncall the `on` method and return the join condition.\n\n```scala\nPeople join 'addresses on { (p, a) =\u003e p('id) == a('person_id) }\n//Constructs a query: SELECT * FROM people INNER JOIN addresses ON people.id = addresses.person_id\n```\n\n## Results\nBy default, each command prepares the query but never really tries to find\nanything on database. So, you should call \"results\" to fetch the results of the\nquery. These will give you a List of Attributes, so you can convert these to\nany format you desire:\n\n```scala\nval people = People query { implicit p =\u003e\n  p select ('name, 'name.count.as(\"number\")) group 'number\n}\n\npeople.foreach { p =\u003e\n  val name = p get 'name\n  val count = p attribute 'number as Int\n  println(\"There are \" + count + \" names '\" + name \"' on database\")\n}\n```\n\nNote that \"count\" is an `Int`, because of `as Int` part of the code.\n\nRelational Scala doesn't tries to be \"type-safe\": indeed, SQL itself is not\n\"static typed\": you can, for instance, cast \"name\" to an INTEGER on SQL, and\nthere is no way to catch this on Scala (or any other language).\n\n## For Comprehensions\n\nThere is another way that we can create queries, which is using \"for compreehensions\".\nIt works for simple queries, and for more complex ones too. The idea is simple: in\nRelational, we *know* when we're using a group-by condition, or a simple condition, or\nwhat are tables, aliases, and such. So, we can create Inner Joins and Having conditions\nusing only for comprehensions:\n\n```scala\nimport relational.queries._\nimport relational.functions._\n\nfor {\n  user \u003c- Table('users)\n  if user.name == \"Foo\"\n  address \u003c- Table('addresses)\n  if address.user_id == user.id\n  child \u003c- Table('children)\n  if child.user_id == user.id \u0026\u0026 Count(child.id) \u003e 1\n} yield (user.get[String]('name), address.get[String], child.get[Int]('age))\n```\n\nThe above code is able to generate a query for the following SQL:\n\n```sql\nSELECT \"children\".\"age\", \"addresses\".\"road\", \"users\".\"name\" \nFROM \"users\" \nINNER JOIN \"children\" ON \"children\".\"user_id\" = \"users\".\"id\" \nINNER JOIN \"addresses\" ON \"addresses\".\"user_id\" = \"users\".\"id\" \nWHERE \"users\".\"name\" = 'Foo' \nHAVING COUNT(\"children\".\"id\") \u003e 1\n```\n\nAnd, when run, will produce a `Stream[(String, String, Int)]` with the results from\nthe database.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmauricioszabo%2Frelational-scala","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmauricioszabo%2Frelational-scala","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmauricioszabo%2Frelational-scala/lists"}