{"id":13903118,"url":"https://github.com/Kitura/Swift-Kuery","last_synced_at":"2025-07-18T00:33:26.471Z","repository":{"id":47612694,"uuid":"65377218","full_name":"Kitura/Swift-Kuery","owner":"Kitura","description":"SQL database abstraction layer","archived":false,"fork":false,"pushed_at":"2021-08-21T21:20:00.000Z","size":11563,"stargazers_count":426,"open_issues_count":30,"forks_count":41,"subscribers_count":32,"default_branch":"master","last_synced_at":"2024-10-30T17:15:03.891Z","etag":null,"topics":["linux","macos","relational-databases","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/Kitura.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-10T11:29:48.000Z","updated_at":"2024-08-22T23:54:22.000Z","dependencies_parsed_at":"2022-09-23T13:52:50.013Z","dependency_job_id":null,"html_url":"https://github.com/Kitura/Swift-Kuery","commit_stats":null,"previous_names":[],"tags_count":64,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kitura%2FSwift-Kuery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kitura%2FSwift-Kuery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kitura%2FSwift-Kuery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kitura%2FSwift-Kuery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kitura","download_url":"https://codeload.github.com/Kitura/Swift-Kuery/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226320901,"owners_count":17606375,"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":["linux","macos","relational-databases","swift"],"created_at":"2024-08-06T22:01:37.843Z","updated_at":"2024-11-25T11:31:18.348Z","avatar_url":"https://github.com/Kitura.png","language":"Swift","funding_links":[],"categories":["Swift"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003ca href=\"http://kitura.io/\"\u003e\n        \u003cimg src=\"https://raw.githubusercontent.com/Kitura/Kitura/master/Sources/Kitura/resources/kitura-bird.svg?sanitize=true\" height=\"100\" alt=\"Kitura\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://kitura.github.io/Swift-Kuery/index.html\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/apidoc-SwiftKuery-1FBCE4.svg?style=flat\" alt=\"APIDoc\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://travis-ci.org/Kitura/Swift-Kuery\"\u003e\n    \u003cimg src=\"https://travis-ci.org/Kitura/Swift-Kuery.svg?branch=master\" alt=\"Build Status - Master\"\u003e\n    \u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/os-macOS-green.svg?style=flat\" alt=\"macOS\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/os-linux-green.svg?style=flat\" alt=\"Linux\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/license-Apache2-blue.svg?style=flat\" alt=\"Apache 2\"\u003e\n    \u003ca href=\"http://swift-at-ibm-slack.mybluemix.net/\"\u003e\n    \u003cimg src=\"http://swift-at-ibm-slack.mybluemix.net/badge.svg\" alt=\"Slack Status\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n# Swift-Kuery\n\n`Swift-Kuery` is a pluggable SQL database driver/SDK abstraction layer. Its main idea is to unify the APIs to the various relational databases, providing a Swifty yet SQL-like API. This allows easy switching between databases and forms the basis for an Object-Relational Mapping (ORM) framework.\n\n[Swift-Kuery-ORM](https://github.com/Kitura/Swift-Kuery-ORM) is an ORM, built on top of Swift-Kuery, which allows you to simplify the persistence of model objects with your server.\n\n`Swift-Kuery` is an easy to learn, consumable framework that comes with a set of [implemented plugins](#list-of-plugins).\n\n## Table of Contents\n* [Swift version](#swift-version)\n* [Usage](#usage)\n* [SQL Injection Prevention using Parameterization](#sql-injection-prevention-using-parameterization)\n* [Prepared Statements](#prepared-statements)\n* [Schema Management](#schema-management)\n* [Query Examples](#query-examples)\n* [List of plugins](#list-of-plugins)\n* [API Reference](#api-reference)\n* [Community](#community)\n* [License](#license)\n\n## Swift version\nThe latest version of Swift-Kuery requires **Swift 4.0** or newer. You can download this version of the Swift binaries by following this [link](https://swift.org/download/). Compatibility with other Swift versions is not guaranteed.\n\n## Usage\nThis example demonstrates how to execute an SQL query using `Swift-Kuery` with the [Swift-Kuery-PostgreSQL](https://github.com/Kitura/Swift-Kuery-PostgreSQL) plugin.\n\nThe starting point for this example is an existing Swift package. If you don't have one already, create and enter a directory named e.g. `SwiftKueryExample`. Now run the swift package's init command, to create an executable type, by running `swift package init --type executable`.\n\n### Creating A PostgreSQL Database\n\n1. Install PostgreSQL\n#### Mac\n`brew install postgresql`\n#### Ubuntu Linux\n`sudo apt-get install postgresql postgresql-contrib`\n\n2. Create a `school` database\n    ```\n    createdb school\n    psql school\n    ```\n\n3. Create a `grades` table\n    ```\n    CREATE TABLE \"Grades\" (\n        id varchar(100) PRIMARY KEY,\n        course text NOT NULL,\n        grade integer\n    );  \n    ```\n\n### Update your Package.swift file\nAdd Swift-Kuery and your Kuery plugin, in this case Swift-Kuery-PostgreSQL, to the dependencies within your application's `Package.swift` file. Substitute `\"x.x.x\"` with the latest `Swift-Kuery` [release](https://github.com/Kitura/Swift-Kuery/releases) and `\"y.y.y\"` with the latest plugin [release](https://github.com/Kitura/Swift-Kuery-PostgreSQL/releases).\n\n```swift\ndependencies: [\n    ...\n    // Add this line\n    .package(url: \"https://github.com/Kitura/Swift-Kuery.git\", from: \"x.x.x\"),\n    .package(url: \"https://github.com/Kitura/Swift-Kuery-PostgreSQL.git\", from: \"y.y.y\"),\n  ],\n  targets: [\n    .target(\n      name: ...\n      // Add the module to your target(s)\n      dependencies: [..., \"SwiftKuery\", \"SwiftKueryPostgreSQL\"]),\n  ]\n```\n\n### Executing SQL queries\nInside the `main.swift` file:\n\n1. Add SwiftKuery and SwiftKueryPostgreSQL to your import statements:\n```swift\nimport SwiftKuery\nimport SwiftKueryPostgreSQL\n```\n\n2. Create a `Table` class, which matches the `grades` table you created in the database:\n```swift\nclass Grades: Table {\n    let tableName = \"Grades\"\n    let id = Column(\"id\", Int32.self, primaryKey: true)\n    let course = Column(\"course\", String.self)\n    let grade = Column(\"grade\", Int32.self)\n}\nlet grades = Grades()\n```\n\n3. Create a pool of connections to PostgreSQL:\n```swift\nlet pool = PostgreSQLConnection.createPool(host: \"localhost\", port: 5432, options: [.databaseName(\"school\")], poolOptions: ConnectionPoolOptions(initialCapacity: 10, maxCapacity: 50))\n```\n\n4. Create some example students:\n```swift\nlet students: [[Any]] = [[0, \"computing\", 92], [1, \"physics\", 75], [2, \"history\", 83]]\n```\n\n5. Connect to database and perform an SQL query:\n```swift\npool.getConnection() { connection, error in\n    guard let connection = connection else {\n        guard let error = error else {\n            return print(\"Unknown error\")\n        }\n        return print(\"Error when getting connection from pool: \\(error.localizedDescription)\")\n    }\n    let insertQuery = Insert(into: grades, rows: students)\n    connection.execute(query: insertQuery) { insertResult in\n        connection.execute(query: Select(from: grades)) { selectResult in\n            guard let resultSet = selectResult.asResultSet else {\n                return print(\"No result set returned from query\")\n            }\n            resultSet.forEach() { row, error in\n                guard let row = row else {\n                    guard let error = error else {\n                        // Processed all results\n                        return\n                    }\n                    // Handle error\n                    return\n                }\n                guard row.count == 3 else {\n                    // Expecting three elements per row\n                    return print(\"Row has wrong number of elements. Expecting 3, returned: \\(row.count)\")\n                }\n                print(\"Student \\(row[0] ?? \"\"), studying \\(row[1] ?? \"\"), scored \\(row[2] ?? \"\")\")\n            }\n        }\n    }\n}\n```\n6. If you were to run the application at this point it would execute immediately because the SwiftKuery API behaves asynchronously. In the case of this simple executable you can add a Dispatch Semaphore to force the application to wait for the asynchronous callbacks to complete:\n```swift\n// Add the following after the existing imports:\nimport Dispatch\nlet waitSemaphore = DispatchSemaphore(value: 0)\n\n// Update the forEach callback to look like:\nresultSet.forEach() { row, error in\n    guard let row = row else {\n        // Processed all results\n        waitSemaphore.signal()\n        return\n    }\n    print(\"Student \\(row[0] ?? \"\"), studying \\(row[1] ?? \"\"), scored \\(row[2] ?? \"\")\")\n}\n\n// Add the following line at the end of the main.swift file\nwaitSemaphore.wait()\n```\n            \n7. Save the `main.swift` file. Run `swift build` to build the executable.\n8. Run the executable `.build/debug/\u003cyourPackageName\u003e.`\n\nThis will print the `id`, `course` and `grade` for each student, which are queried from the database:\n```\nStudent 0, studying computing, scored 92\nStudent 1, studying physics, scored 75\nStudent 2, studying history, scored 83\n```\nIf you go to your database with `psql school` and enter `TABLE grades;` you can see that the table has been populated with the student data.\n\n## SQL Injection Prevention using Parameterization\n\nUnsanitized data that is used in dynamic queries is one of the most common causes of SQL injection vulnerabilities. Parameterizing queries can help to prevent SQL injection attacks.\n\nThe following code is vulnerable to SQL injection if `supplied_key1` or `supplied_key2` contain untrusted data (that is, data which has not been validated):\n```swift\nlet query = Select(from: confidential)\n  .where(confidential.key1 == supplied_key1 || confidential.key2 == supplied_key2)\n\nconnection.execute(query: query) { queryResult in\n  ...\n}\n```\n\nTo guard against SQL Injection attacks, use the following parameterized version of the code:\n```swift\nlet query = Select(from: confidential)\n  .where(confidential.key1 == Parameter() || confidential.key2 == Parameter())\n\nconnection.execute(query: query, parameters: supplied_key1, supplied_key2) { queryResult in\n  ...\n}\n```\n\n## Prepared Statements\n\nIf your application executes the same (or similar) SQL statements repeatedly with different parameters you may improve the performance of the application by using a prepared statement. Prepared statements can reduce parsing time as the database parses and compiles the statement template only once and then stores the result but doesn’t execute it. Later, the application supplies values for the parameters of the statement template and the database executes the statement.\n\nFor example, suppose our application needs to retrieve the average grade for courses with an average above a given value; a value which we want to vary. Let’s change our query to use a parameter instead of a predefined value:\n\n```swift\nlet query = Select(grades.course, round(avg(grades.grade), to: 1).as(\"average\"), from: grades)\n            .group(by: grades.course)\n            .having(avg(grades.grade) \u003e Parameter())\n            .order(by: .ASC(avg(grades.grade)))\n```\n\nNow, prepare the statement and execute as many times as required with different parameter values. Use the `release` function to free the prepared statement:\n\n```swift\nconnection.prepareStatement(query) { result in\n    guard let statement = result.asPreparedStatement else {\n        // Handle error\n        return\n    }\n    // Execute the statement\n    connection.execute(preparedStatement: preparedStatement, parameters: [70]) { result in\n        ...\n        connection.execute(preparedStatement: preparedStatement, parameters: [25]) { result in\n            ...\n            connection.release(preparedStatement: preparedStatement) { result in\n                ...\n            }\n        }\n    }\n}\n```\n\n**Note**: `preparedStatement` is a plugin-specific handle for the prepared statement.\n\n## Schema Management\n\n### Table creation\nSwift-Kuery enables you to create tables on the database server.\n\nLet's revisit the Grades table, which we used in our Example above:\n\n```swift\nclass Grades: Table {\n    let tableName = \"Grades\"\n    let id = Column(\"id\", Int32.self, primaryKey: true)\n    let course = Column(\"course\", String.self)\n    let grade = Column(\"grade\", Int32.self)\n}\n```\n\nWe will add a second table called `courses`:\n```swift\nclass Courses: Table {\n    let tableName = \"Courses\"\n    let name = Column(\"name\", String.self, primaryKey: true)\n    let credit = Column(\"credit\", Int32.self)\n    let teacher = Column(\"teacher\", String.self)\n}\nlet courses = Courses()\n```\n\nWe can add a foreign key to `Grades` that references a column in another table:\n\n```swift\nlet grades = Grades().foreignKey(grades.course, references: courses.name)\n```\n\nCreate a multi-column primary key (if not set in the column as for `Grades.id`)\n\n```swift\ngrades.primaryKey(grades.id, grades.course)\n```\n\nCreate the table in the database:\n\n```swift\n\ncourses.create(connection: connection) { result in\n     guard result.success else {\n        print(\"Failed to create table: \\(result.asError?)\")\n     }\n    ...\n}\n```\n\n### Indices\n\nYou can manage indices with Swift-Kuery in the following way:\n\n```swift\nlet index = Index(\"index\", on: grades, columns: [grades.id, desc(grades.grade)])\nindex.create(connection: connection) { result in ... }\n...\nindex.drop(connection: connection) { result in ... }\n```\n\n### Migration\nSwift-Kuery has a class `Migration` to help with migrations between two versions of a table.\n\nSuppose we have a table `MyTable` in our application. The suggested usage is to keep versions of the table classes somewhere in the application code:\n\n```swift\npublic class MyTable_v0: Table {\n    let a = Column(\"a\", ...)\n    let b = Column(\"b\", ...)\n    let tableName = \"MyTable\"\n}\n\npublic class MyTable_v1: Table {\n    let b = Column(\"b\", ...)\n    let c = Column(\"c\", ...)\n    let tableName = \"MyTable\"\n}\n```\n\nUse a typealias to refer to the current version of the table class in the application:\n\n```swift\ntypealias MyTable = MyTable_v0\nlet t = MyTable()\nlet q = Select(from t)\n...\n```\n\nThe migration code from v0 to v1 should be something like this:\n\n```swift\nlet t0 = MyTable_v0()\nlet t1 = MyTable_v1()\nlet migration0 = Migration(from: t0, to: t1, using: connection)\nmigration0.alterTableAdd(column: t1.c) { result in ... }\n```\n\nYou can also execute raw alterations, if needed:\n\n```swift\nlet dropColumnQuery = \"ALTER TABLE \" + t1.tableName + \" DROP COLUMN \" + t0.a.name\nconnection.execute(dropColumnQuery) { result in ... }\n```\n\n## Query Examples\nIn the following section, we will provide an example SQL query and show you how to build and execute the same query in Swift using Swift-Kuery.\n\n#### Classes used in the examples:\nThese examples we will use the following two tables:\n\n```swift\nclass T1 {\n  let tableName = \"t1\"\n  let a = Column(\"a\")\n  let b = Column(\"b\")\n}\n\nclass T2 {\n  let tableName = \"t2\"\n  let c = Column(\"c\")\n  let b = Column(\"b\")\n}\n```\n\n\u0026nbsp;\n\n__SELECT * FROM t1;__\n\nThis query will select all results from the table. The example below shows how to execute this query including the boilerplate code:\n\n```swift\nlet t1 = T1()\n\nlet query = Select(from: t1)\n\npool.getConnection() { connection, error in\n    guard let connection = connection else {\n        // Handle error\n        return\n    }\n    query.execute(connection) { queryResult in\n        guard let resultSet = queryResult.asResultSet else {\n            // Handle error\n            return\n        }\n        resultSet.getColumnTitles() { titles, error in\n            guard let titles = titles else {\n                // Handle error\n                return\n            }\n            //Process titles\n            resultSet.forEach() { row, error in\n                guard let row = row else {\n                    // Processed all results\n                    return\n                }\n                // Process row\n            }\n        }\n    }\n}\n\n\n```\n\nThe following examples show more complex queries, which can be substituted into the the above boilerplate.\n\u0026nbsp;\n\n__SELECT a, b FROM t1      \n   WHERE (a LIKE '%b' OR a = 'apple') AND b \u003e 5  \n   ORDER BY b ASC, a DESC       \n   OFFSET 5;__\n\n```swift\nlet query = Select(t1.a, t1.b, from: t1)\n  .where((t1.a.like(\"b%\") || t1.a == \"apple\") \u0026\u0026 t1.b \u003e 5)\n  .order(by: .ASC(t1.b), .DESC(t1.a))\n  .offset(5)\n```\n\n\u0026nbsp;\n\n__SELECT UCASE(a) AS name FROM t1    \n WHERE b \u003e= 0         \n GROUP BY a         \n HAVING SUM(b) \u003e 3        \n ORDER BY a DESC;__\n\n```swift\nlet query = Select(ucase(t1.a).as(\"name\"), from: t1)\n  .where(t1.b \u003e= 0)\n  .group(by: t1.a)\n  .having(sum(t1.b) \u003e 3)\n  .order(by: .DESC(t1.a))\n```\n\n\u0026nbsp;\n\n__INSERT INTO t1             \nVALUES ('apple', 10), ('apricot', 3), ('banana', 17);__\n\n```swift\nlet query = Insert(into: t1, rows: [[\"apple\", 10], [\"apricot\", 3], [\"banana\", 17]])\n```\n\n\u0026nbsp;\n\n__INSERT INTO t1             \nVALUES ('apple', 10);__\n\n```swift\nlet query = Insert(into: t1, values: \"apple\", 10)\n```\n\n\u0026nbsp;\n\n\n__INSERT INTO t1 (a, b)              \nVALUES ('apricot', '3');__\n\n```swift\nlet query = Insert(into: t1, valueTuples: (t1.a, \"apricot\"), (t1.b, \"3\"))\n```\n\n\u0026nbsp;\n\n__INSERT INTO t1 (a, b)              \nVALUES ('apricot', '3');__\n\n```swift\nlet query = Insert(into: t1, columns: [t1.a, t1.b], values: [\"apricot\", 3])\n```\n\n\u0026nbsp;\n\n__UPDATE t1 SET a = 'peach', b = 2            \nWHERE a = 'banana';__\n\n```swift\nlet query = Update(t1, set: [(t1.a, \"peach\"), (t1.b, 2)])\n  .where(t1.a == \"banana\")\n```\n\n\u0026nbsp;\n\n__SELECT * FROM t1 AS left            \nLEFT JOIN t2 AS right           \nON left.b = right.b;__\n\n```swift\nlet t1 = T1()\nlet t2 = T2()\n\nlet leftTable = t1.as(\"left\")\nlet rightTable = t2.as(\"right\")\nlet query = Select(from: leftTable)\n  .leftJoin(rightTable)\n  .on(leftTable.b == rightTable.b)\n```\n\n\u0026nbsp;\n\n__SELECT * FROM t1           \nJOIN t2           \nUSING (b);__\n\n```swift\nlet query = Select(from: t1)\n  .join(t2)\n  .using(t1.b)\n```\n\n\u0026nbsp;\n\n#### Queries with parameters:                         \n**Note**: Named parameters are supported for all databases, even for those that do not support named parameters (e.g. PostgreSQL).\n\n\n__INSERT INTO t1             \nVALUES (@0,@1);__\n\n```swift\nlet query = Insert(into: t1, values: Parameter(), Parameter())\n\nconnection.execute(query: query, parameters: \"banana\", 28) { queryResult in\n  // Process result\n}\n```\n\n\u0026nbsp;\n\n__INSERT INTO t1             \nVALUES (@fruit,@number);__\n\n```swift\nlet query = Insert(into: t1, values: Parameter(\"fruit\"), Parameter(\"number\"))\n\nconnection.execute(query: query, parameters: [\"number\" : 28, \"fruit\" : \"banana\"]) { queryResult in\n  // Process result\n}\n```\n\n\u0026nbsp;\n\nIt is possible to insert NULL values using parameters:\n\u0026nbsp;\n\n```swift\nconnection.execute(query: query, parameters: [\"number\" : 28, \"fruit\" : nil]) { queryResult in\n  // Process result\n}\n```\n\n\u0026nbsp;\n\n__Raw query:__\n\n```swift\nconnection.execute(\"CREATE TABLE myTable (a varchar(40), b integer)\") {  queryResult in\n  // Process result\n}\n```\n\n\u0026nbsp;\n\n__SELECT LEFT(a, 2) as raw FROM t1     \n WHERE b \u003e= 0\n GROUP BY a         \n HAVING sum(b) \u003e 3               \n ORDER BY a DESC;__\n\n```swift\nlet query = Select(RawField(\"LEFT(a, 2) as raw\"), from: t1)\n  .where(\"b \u003e= 0\")\n  .group(by: t1.a)\n  .having(\"sum(b) \u003e 3\")\n  .order(by: .DESC(t1.a))\n```\n\n\u0026nbsp;\n\n__SELECT * FROM t1     \nWHERE b \u003e= ANY (SELECT b FROM t2);__\n\n```swift\nlet query = Select(from: t1)\n  .where(t1.b \u003e= any(Select(t2.b, from: t2)))\n```\n\n\u0026nbsp;\n\n__SELECT * FROM t1     \nWHERE NOT EXISTS (SELECT * FROM t2 WHERE b \u003c 8);__\n\n```swift\nlet query = Select(from: t1)\n  .where(notExists(Select(from: t2).where(t2.b \u003c 8)))\n```\n\n\u0026nbsp;\n\n__SELECT c FROM t2\nGROUP BY c     \nHAVING SUM(b) NOT IN (SELECT b FROM t1 WHERE a = 'apple');__\n\n```swift\nlet query = Select(t2.c, from: t2)\n    .group(by: t2.c)\n    .having(sum(t2.b).notIn(Select(t1.b, from: t1).where(t1.a == \"apple\")))\n```\n\n## List of plugins\n\n* [PostgreSQL](https://github.com/Kitura/Swift-Kuery-PostgreSQL)\n\n* [SQLite](https://github.com/Kitura/Swift-Kuery-SQLite)\n\n* [MySQL](https://github.com/Kitura/SwiftKueryMySQL)\n\n## API Documentation\nFor more information visit our [API reference](https://kitura.github.io/Swift-Kuery/index.html).\n\n## Community\n\nWe love to talk server-side Swift, and Kitura. Join our [Slack](http://swift-at-ibm-slack.mybluemix.net/) to meet the team!\n\n## License\nThis library is licensed under Apache 2.0. Full license text is available in [LICENSE](https://github.com/Kitura/Swift-Kuery/blob/master/LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKitura%2FSwift-Kuery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FKitura%2FSwift-Kuery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKitura%2FSwift-Kuery/lists"}