{"id":31733288,"url":"https://github.com/losizm/little-sql","last_synced_at":"2026-04-19T05:33:38.342Z","repository":{"id":57721152,"uuid":"146967594","full_name":"losizm/little-sql","owner":"losizm","description":"Scala extension methods for java.sql","archived":false,"fork":false,"pushed_at":"2025-04-08T06:09:39.000Z","size":5513,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-09T08:23:36.364Z","etag":null,"topics":["java","scala","sql"],"latest_commit_sha":null,"homepage":"https://losizm.github.io/little-sql","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/losizm.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}},"created_at":"2018-09-01T04:31:45.000Z","updated_at":"2025-04-08T06:11:02.000Z","dependencies_parsed_at":"2024-04-20T08:21:58.982Z","dependency_job_id":"9ea51c27-d6e1-4e92-a52e-8799a3f18a19","html_url":"https://github.com/losizm/little-sql","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"purl":"pkg:github/losizm/little-sql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/losizm%2Flittle-sql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/losizm%2Flittle-sql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/losizm%2Flittle-sql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/losizm%2Flittle-sql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/losizm","download_url":"https://codeload.github.com/losizm/little-sql/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/losizm%2Flittle-sql/sbom","scorecard":{"id":599371,"data":{"date":"2025-08-11","repo":{"name":"github.com/losizm/little-sql","commit":"c358efa1977e6e14c3ceb9af159c13093a84468a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-20T23:59:48.232Z","repository_id":57721152,"created_at":"2025-08-20T23:59:48.233Z","updated_at":"2025-08-20T23:59:48.233Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31996441,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"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":["java","scala","sql"],"created_at":"2025-10-09T08:23:18.551Z","updated_at":"2026-04-19T05:33:38.337Z","avatar_url":"https://github.com/losizm.png","language":"Scala","readme":"# little-sql\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.losizm/little-sql_3.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.github.losizm%22%20AND%20a:%22little-sql_3%22)\n\nThe Scala library that provides extension methods for _java.sql_.\n\n## Getting Started\n\nTo get started, add **little-sql** as a dependency to your project:\n\n```scala\nlibraryDependencies += \"com.github.losizm\" %% \"little-sql\" % \"9.0.0\"\n```\n\n_**NOTE:** Starting with version 1.0, **little-sql** is written for Scala 3. See\nprevious releases for compatibility with Scala 2.12 and Scala 2.13._\n\n## A Taste of little-sql\n\nHere's a taste of what **little-sql** offers.\n\n### Getting Connection and Executing Statements\n\nThe example below uses a `Connector`, which is an implementation of\n`javax.sql.DataSource`. It obtains a database connection and executes a series\nSQL statements. After executing each statement, a subclass of `Execution` is\npassed to a supplied handler. The execution is either an `Update` providing a\ncount or a `Query` holding a `ResultSet`.\n\n```scala\nimport java.sql.{ PreparedStatement, ResultSet }\nimport little.sql.{ *, given }\nimport scala.language.implicitConversions\n\ncase class User(id: Int, name: String)\n\ndef getUser(rs: ResultSet): User = {\n  User(rs.getInt(\"id\"), rs.getString(\"name\"))\n}\n\n// Define database connector\nval connector = Connector(\"jdbc:h2:~/little-sql\", \"gza\", \"1iquid5w0rd5\", \"org.h2.Driver\")\n\n// Create connection, pass it to function, and close connection when done\nconnector.withConnection { conn =\u003e\n  val statements = Seq(\n    \"drop table if exists users\",\n    \"create table users (id int, name varchar(32))\",\n    \"insert into users (id, name) values (0, 'root'), (500, 'guest')\",\n    \"select id, name from users\",\n    \"drop table if exists passwords\",\n    \"create table passwords (id int, password varchar(32))\",\n    \"insert into passwords (id, password) values (0, 'repus'), (500, 'esuom')\"\n  )\n\n  // Loop thru statements executing each one\n  statements.foreach { sql =\u003e\n    println(s\"Executing $sql ...\")\n\n    // Execute SQL, handle result, and close statement and result set (if any)\n    conn.execute(sql) {\n      // If update was executed, print number of rows affected\n      case Update(count) =\u003e println(s\"Rows affected: $count\")\n\n      // If query was executed, print first row of result set\n      case Query(resultSet) =\u003e if resultSet.next() then println(getUser(resultSet))\n    }\n  }\n}\n```\n\n### Setting Parameters in Prepared Statement\n\nIf you're executing a statement with input parameters, you can pass the SQL\nalong with the parameter values allowing them to be set based on their value\ntypes.\n\n```scala\n// Get connection, run update with parameters, and print number of rows inserted\nconnector.withConnection { conn =\u003e\n  val sql = \"insert into users (id, name) values (?, ?)\"\n\n  conn.update(sql, Seq(501, \"ghostface\")) { count =\u003e\n    println(s\"Rows inserted: $count\")\n  }\n}\n```\n\n### Looping thru Result Set\n\n**little-sql** adds a `foreach` method to `Connection`, `Statement`, and\n`PreparedStatement`, which cuts down the boilerplate of executing a query and\nlooping through the `ResultSet`.\n\n```scala\n// Get connection, run select, and print each row in result set\nconnector.withConnection { conn =\u003e\n  conn.foreach(\"select * from users\") { rs =\u003e\n    println(getUser(rs))\n  }\n}\n```\n\n### Mapping First Row of Result Set\n\nAt times, you may want only the first row in a result set. Perhaps you're running\na query knowing it will return at most one row. With pure Java, you use a\n`Connection` to create a `Statement`, you execute the statement which returns\na `ResultSet`, and then you check the result set to see whether it has a row. If\nso, you proceed to get values from the result set. When you're done, you close\nthe result set and statement.\n\nWith **little-sql**, ditch the ceremony and get straight to the point.\n\n```scala\nval user: Option[User] = connector.withConnection { conn =\u003e\n  conn.first(\"select * from users where id = 501\")(getUser)\n}\n```\n\n### Mapping All Rows of Result Set\n\nYou can also map over an entire result set.\n\n```scala\nval users: Seq[User] = connector.withConnection { conn =\u003e\n  conn.map(\"select * from users\")(getUser)\n}\n```\n\nOr, if you're particular about which rows to map, you can `flatMap` the result\nset instead.\n\n```scala\nval regUsers: Seq[User] = connector.withConnection { conn =\u003e\n  conn.flatMap(\"select * from users\") {\n    getUser(_) match\n      case User(_, \"root\") =\u003e None\n      case user            =\u003e Some(user)\n  }\n}\n```\n\nThe above example is not necessarily the best use case. You could've instead\nwritten the query to exclude the root user \u0026ndash; but you get the point.\n\n### Getting Custom Values from Result Set\n\nYou can define an implementation of `GetValue` to retrieve custom values from a\n`ResultSet`.\n\n```scala\nimport little.sql.GetValue\n\ncase class Secret(text: String)\n\n// Get Secret from ResultSet\ngiven GetSecret: GetValue[Secret] with\n  // Get value by index\n  def apply(rs: ResultSet, index: Int): Secret =\n    decrypt(rs.getString(index))\n\n  // Get value by label\n  def apply(rs: ResultSet, label: String): Secret =\n    decrypt(rs.getString(label))\n\n  private def decrypt(text: String): Secret =\n    text == null match\n      case true  =\u003e Secret(\"\")\n      case false =\u003e Secret(text.reverse)\n\n// Get connection, run select, and print each user's password\nconnector.withConnection { conn =\u003e\n  val sql = \"\"\"\n    select u.name, p.password\n    from passwords p join users u\n    on p.id = u.id\n  \"\"\"\n\n  conn.foreach(sql) { rs =\u003e\n    val name = rs.getString(\"name\")\n    val password = rs.get[Secret](\"password\")\n\n    printf(\"%s's password is %s%n\", name, password.text)\n  }\n}\n```\n\n### Setting Custom Values in Prepared Statement\n\nTo set a parameter to a custom value, you can define an implicit conversion to\nconvert the value to an `InParam`.\n\n```scala\nimport scala.language.implicitConversions\n\nimport little.sql.InParam\n\n// Convert Secret to InParam\ngiven Conversion[Secret, InParam] with\n  def apply(value: Secret) =\n    value == null match\n      case true  =\u003e InParam.Null\n      case false =\u003e InParam(value.text.reverse)\n\n// Get connection, run update with parameters, and print number of rows inserted\nconnector.withConnection { conn =\u003e\n  val sql = \"insert into passwords (id, password) values (?, ?)\"\n\n  conn.update(sql, Seq(501, Secret(\"ironm@n\"))) { count =\u003e\n    println(s\"Rows inserted: $count\")\n  }\n}\n```\n\n### Using QueryBuilder to Build and Execute Statements\n\n`QueryBuilder` provides an interface for incrementally building SQL statements.\nAnd, for executing them, it has a familiar list of combinators, such as\n`foreach`, `map`, `flatMap`, and `fold`.\n\n```scala\nimport little.sql.QueryBuilder\n\nconnector.withConnection { implicit conn =\u003e\n  val sum = QueryBuilder(\"select * from users where id != ? and name != ?\")\n    .params(0, \"root\") // Set input parameters\n    .queryTimeout(5)   // Set query timeout to 5 seconds\n    .maxRows(10)       // Limit result set to 10 rows\n    .fetchSize(10)     // Fetch 10 rows at a time\n    // Fold over all rows summing the user IDs\n    // Executes using implicit connection\n    .fold(0) { (sum, rs) =\u003e sum + rs.getInt(\"id\") }\n\n  println(s\"Sum: $sum\")\n}\n```\n\nYou can also supply parameters as a map or a sequence of tuples. In the example\nbelow, note the parameter placeholders in SQL and how the corresponding\nparameter values are supplied.\n\n```scala\nconnector.withConnection { implicit conn =\u003e\n  QueryBuilder(\"select * from users where id != ${userId} and name != ${userName}\")\n    .params(\"userId\" -\u003e 0, \"userName\" -\u003e \"root\")\n    .foreach(rs =\u003e println(rs.getString(\"name\")))\n}\n```\n\n### Working with Data Source\n\nIf you have access to an instance of `javax.sql.DataSource`, you can use\nextension methods for automatic resource management.\n\n```scala\nimport javax.naming.InitialContext\nimport javax.sql.DataSource\nimport little.sql.DataSourceMethods\n\nval dataSource = InitialContext()\n  .lookup(\"java:module/jdbc/UserDB\")\n  .asInstanceOf[DataSource]\n\n// Get connection, run update with parameters, and print number of rows inserted\ndataSource.withConnection { conn =\u003e\n  val sql = \"insert into users (id, name) values (?, ?)\"\n  val params = Seq(502, \"raekwon\")\n\n  conn.update(sql, params) { count =\u003e\n    println(s\"Rows inserted: $count\")\n  }\n}\n\n// Or if you need to provide user and password\ndataSource.withConnection(\"gza\", \"1iquid5w0rd5\") { conn =\u003e\n  conn.foreach(\"select name from users\") { rs =\u003e\n    println(rs.getString(\"name\"))\n  }\n}\n```\n\n## API Documentation\n\nSee [scaladoc](https://losizm.github.io/little-sql/latest/api/little/sql.html)\nfor additional details.\n\n## License\n**little-sql** is licensed under the Apache License, Version 2. See [LICENSE](LICENSE)\nfor more information.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flosizm%2Flittle-sql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flosizm%2Flittle-sql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flosizm%2Flittle-sql/lists"}