{"id":29117738,"url":"https://github.com/kakserpom/php-sqlx-rs","last_synced_at":"2025-06-29T12:05:06.447Z","repository":{"id":298011430,"uuid":"998557765","full_name":"kakserpom/php-sqlx-rs","owner":"kakserpom","description":"A modern feature-rich SQL driver for PHP.","archived":false,"fork":false,"pushed_at":"2025-06-27T07:35:09.000Z","size":675,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-27T08:36:05.198Z","etag":null,"topics":["mssql","mysql","php","php-extension","postgresql","sql"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kakserpom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2025-06-08T21:31:42.000Z","updated_at":"2025-06-27T07:35:12.000Z","dependencies_parsed_at":"2025-06-08T23:25:46.034Z","dependency_job_id":"4a8c5895-e4c2-4d7b-998f-7d82004d3d4d","html_url":"https://github.com/kakserpom/php-sqlx-rs","commit_stats":null,"previous_names":["kakserpom/php-sqlx-rs"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kakserpom/php-sqlx-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kakserpom%2Fphp-sqlx-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kakserpom%2Fphp-sqlx-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kakserpom%2Fphp-sqlx-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kakserpom%2Fphp-sqlx-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kakserpom","download_url":"https://codeload.github.com/kakserpom/php-sqlx-rs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kakserpom%2Fphp-sqlx-rs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262589877,"owners_count":23333254,"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":["mssql","mysql","php","php-extension","postgresql","sql"],"created_at":"2025-06-29T12:05:01.540Z","updated_at":"2025-06-29T12:05:06.444Z","avatar_url":"https://github.com/kakserpom.png","language":"Rust","readme":"# php-sqlx-rs\n\nA PHP extension powered by Rust 🦀 and [SQLx](https://github.com/launchbadge/sqlx), enabling safe, fast, and expressive\ndatabase access with additional SQL syntax. It's built using\nthe [ext-php-rs](https://github.com/davidcole1340/ext-php-rs) crate.\n\n**Postgres**, **MySQL** and **Mssql** are supported.\n\nThe project's goals are centered on providing a **secure** and **ergonomic** way to interact with SQL-based DBM systems\nwithout any compromise on performance. The author's not big on PHP, but as a security researcher he understood the\nnecessity of modernizing the toolkit of great many PHP developers. The idea came up, and bish bash bosh, a couple of\nweekends later the project was all but done. More to come.\n\nThe project is still kind of experimental, so any feedback/ideas will be greatly appreciated!\n\n## Features\n\n- AST-based SQL augmentation (e.g., conditional blocks)\n- Named parameters with `$param`, `:param`, or positional `:1` syntax\n- Automatic result conversion to PHP arrays or objects\n- Painless `IN (?)` / `NOT IN (?)` clauses expansion and collapse\n- Safe and robust `ORDER BY` / `GROUP BY` clauses\n- Pagination with `PAGINATE`\n- Safe and robust `SELECT`\n- SQL transactions are supported in full\n- Native JSON and bigint support\n- Optional persistent connections (with connection pooling)\n\n---\n\n## Augmented SQL Syntax\n\nThis extension introduces a powerful SQL preprocessor that supports conditional blocks, optional fragments, and named\nparameters.\n\n---\n\n### Conditional Blocks\n\nWrap parts of your query with double braces `{{ ... }}` to make them conditional:\n\n```\nSELECT *\nFROM users\nWHERE TRUE\n  {{ AND name = $name }}\n  {{ AND status = $status }}\n```\n\nIf a named parameter used inside the block is not provided, the entire block is omitted from the final query.\n\nNested conditional blocks are supported:\n\n```\nSELECT *\nFROM logs\nWHERE TRUE {{ AND date \u003e $since {{ AND level = $level }} }}\n```\n\nIn the above example the `level` condition will only be rendered when both `$level` and `$since` are set.\n\n```\nSELECT *\nFROM logs\nWHERE date \u003e $since {{ AND level = $level }}\n```\n\nThe above example will throw an exception if `$since` is not set.\n\n---\n\n### Painless `IN (?)` / `NOT IN (?)` clauses expansion and collapse\n\nPassing an array as a parameter to a single placeholder automatically expands it:\n\n```php\n// Expands to: SELECT * FROM people WHERE name IN (?, ?, ?)\n// with values ['Peter', 'John', 'Jane']\n$rows = $driver-\u003equeryAll(\n  'SELECT * FROM people WHERE name IN :names', [\n    'names' =\u003e ['Peter', 'John', 'Jane']\n  ]\n);\n```\n\nOmitting the parameter or passing an empty array will make `IN` collapse into boolean `FALSE`.\n\n```php\nvar_dump($driver-\u003edry(\n  'SELECT * FROM people WHERE name IN :names', [\n    'names' =\u003e []\n  ]\n));\n```\n\n```\narray(2) {\n  [0]=\u003e\n  string(53) \"SELECT * FROM people WHERE FALSE /* name IN :names */\"\n  [1]=\u003e\n  array(0) {\n  }\n}\n```\n\nSame goes for `NOT IN`, except it will collapse into boolean `TRUE`.\n\n```php\nvar_dump($driver-\u003edry(\n  'SELECT * FROM people WHERE name NOT IN :names', [\n    'names' =\u003e []\n  ]\n));\n```\n\n```\narray(2) {\n  [0]=\u003e\n  string(56) \"SELECT * FROM people WHERE TRUE /* name NOT IN :names */\"\n  [1]=\u003e\n  array(0) {\n  }\n}\n```\n\n\u003e Makes sense, right? Given that `x IN (1, 2, 3)` is sugar for `(x = 1 OR x = 2 OR x = 3)`\n\u003e and `x NOT IN (1, 2, 3)` is sugar for `(x != 1 AND x != 2 AND x != 3)`.\n\nKeep in mind that you can not only use it in `WHERE`, but also in `ON` clauses when joining.\n\n\u003e It is true that in simpler cases of `IN :empty` like the above example you could just\n\u003e immediately return an empty result set without sending it to DBMS, but there could be a `JOIN`\n\u003e or a `UNION`.\n---\n\n### Safe and robust `ORDER BY` / `GROUP BY` clauses\n\n`Sql\\ByClause` helper class for safe `ORDER BY` / `GROUP BY` clauses from user input.\n\n\u003e __SAFETY CONCERNS__\n\u003e - 🟢 You can safely pass any user input as sorting settings.\n\u003e - 🔴 Do NOT pass unsanitized user input into `ByClause` constructor to avoid SQL injection vulnerabilities. If you\n    absolutely have to, then apply `array_values()` to the argument to avoid SQL injections.\n\n**Examples**:\n\n```php\n// Let's define allowed columns\n$orderBy = new Sqlx\\ByClause([\n    'name',\n    'created_at',\n    'random' =\u003e 'RANDOM()'\n]);\n\n// Equivalent to: SELECT * FROM users ORDER BY `name` ASC, RANDOM()\n$driver-\u003equeryAll('SELECT * FROM users ORDER BY :order_by', [\n  'order_by' =\u003e $orderBy([\n    ['name', Sqlx\\ByClause::ASC],\n    'random'\n  ])\n]);\n\n```\n\nField names are case-sensitive, but they get trimmed.\n\n---\n\nPagination with `PAGINATE`\n---\n`Sql\\PaginateClause` helper class for safe pagination based on user input.\n\n```php\n// Let's define pagination rules\n$pagination = new Sqlx\\PaginateClause;\n$pagination-\u003eperPage(5);\n$pagination-\u003emaxPerPage(20);\n\n// Equivalent to: SELECT * FROM people ORDER by id LIMIT 5 OFFSET 500\n$rows = $driver-\u003equeryAll(\n  'SELECT * FROM people ORDER by id PAGINATE :pagination', [\n    'pagination' =\u003e $pagination(100)\n  ]\n);\n\n\n// Equivalent to: SELECT * FROM people ORDER by id LIMIT 10 OFFSET 1000\n$rows = $driver-\u003equeryAll(\n  'SELECT * FROM people ORDER by id PAGINATE :pagination', [\n    'pagination' =\u003e $pagination(100, 10)\n  ]\n);\n\n// Equivalent to: SELECT * FROM people ORDER by id LIMIT 5 OFFSET 0\n$rows = $driver-\u003equeryAll(\n  'SELECT * FROM people ORDER by id PAGINATE :pagination', [\n    'pagination' =\u003e $pagination()\n  ]\n);\n```\n\nYou can safely pass any unsanitized values as arguments, but keep in mind that `perPage()`/`maxPerPage()`/\n`defaultPerPage()`\nfunctions take a positive integer and throw an exception otherwise.\n\n---\n\n### Safe and robust `SELECT`\n\nA helper class for safe `SELECT` clauses from user input.\n\n\u003e __SAFETY CONCERNS__\n\u003e - 🟢 You can safely pass any user input as invocation argument.\n\u003e - 🔴 Do NOT pass unsanitized user input into `SelectClause` constructor to avoid SQL injection vulnerabilities. If you\n    absolutely have to, then apply `array_values()` to the argument to avoid SQL injections.\n\n**Examples**:\n\n```php\n$select = new Sqlx\\SelectClause([\n    'id',\n    'created_at',\n    'name' =\u003e ,\n    'num_posts' =\u003e 'COUNT(posts.*)'\n]);\n\n// Equivalent to: SELECT `id`, `name`, COUNT(posts.*) AS `num_posts` FROM users\n$rows = $driver-\u003equeryAll('SELECT :select FROM users', [\n  'select' =\u003e $select(['id','name', 'num_posts])\n]);\n```\n\nNote that column names are case-sensitive, but they get trimmed.\n\n--- \n\n## Transactions\n\n```php\n$driver-\u003ebegin(function($driver) {\n    // All queries inside this function will be wrapped in a transaction.\n    // You can use all driver functions here.\n    \n    $driver-\u003einsert('users', ['name' =\u003e 'John', 'age' =\u003e 25]);\n    $driver-\u003einsert('users', ['name' =\u003e 'Mary', 'age' =\u003e 20]);\n    \n    // return false; \n});\n```\n\nA `ROLLBACK` happens if the closure returns `false` or throws an exception.\nOtherwise, a `COMMIT` gets sent when functions finishes normally.\n\nAdditional supported methods to be called from inside a closure:\n\n- `savepoint(name: String)`\n- `rollbackToSavepoint(name: String)`\n- `releaseSavepoint(name: String)`\n\n---\n\n## JSON Support\n\nPostgreSQL/MySQL JSON types are automatically decoded into PHP arrays or objects.\n\n```php\nvar_dump($driver-\u003equeryValue(\n    'SELECT $1::json',\n    ['{\"foo\": [\"bar\", \"baz\"]}']\n));\n/* Output:\nobject(stdClass)#2 (1) {\n  [\"foo\"]=\u003e\n  array(2) {\n    [0]=\u003e\n    string(3) \"bar\"\n    [1]=\u003e\n    string(3) \"baz\"\n  }\n}*/\n\nvar_dump($driver-\u003equeryRow(\n    'SELECT $1::json AS col',\n    ['{\"foo\": [\"bar\", \"baz\"]}']\n)-\u003ecol-\u003efoo[0]);\n// Output: string(3) \"bar\"\n```\n\n## Installation\n\nInstall with [`cargo-php`](https://github.com/davidcole1340/ext-php-rs):\n\n```bash\ncargo install cargo-php --locked\ncd php-sqlx-cdylib\n```\n\nFor macOS:\n\n```bash\nexport MACOSX_DEPLOYMENT_TARGET=$(sw_vers -productVersion | tr -d '\\n')\nexport RUSTFLAGS=\"-C link-arg=-undefined -C link-arg=dynamic_lookup\"\n#export RUSTFLAGS=\"-Zmacro-backtrace -Zproc-macro-backtrace -Clink-arg=-undefined -Clink-arg=dynamic_lookup\"\ncargo install cargo-php --locked\ncd php-sqlx-cdylib\ncargo php install --release --yes\n```\n\n---\n\n## API\n\n### `Sqlx\\PgDriver` \\| `Sqlx\\MySqlDriver` \\| `Sqlx\\MssqlDriver`\n\n```php\n$driver = new Sqlx\\PgDriver(\"postgres://user:pass@localhost/db\");\n```\n\nOr with options:\n\n```php\n$driver = new Sqlx\\PgDriver([\n    Sqlx\\DriverOptions::OPT_URL =\u003e 'postgres://user:pass@localhost/db',\n    Sqlx\\DriverOptions::OPT_ASSOC_ARRAYS =\u003e true,   // return arrays instead of objects\n    Sqlx\\DriverOptions::OPT_PERSISTENT_NAME =\u003e 'main_db'\n    Sqlx\\DriverOptions::OPT_MAX_CONNECTIONS =\u003e 5,\n    Sqlx\\DriverOptions::OPT_MIN_CONNECTIONS =\u003e 0,\n    //Sqlx\\DriverOptions::OPT_MAX_LIFETIME =\u003e \"30 min\",\n    Sqlx\\DriverOptions::OPT_IDLE_TIMEOUT =\u003e 120,\n]);\n```\n\n#### Basics\n\n- `assocArrays(): bool` – returns **true** if the driver is currently set to produce associative arrays instead of\n  objects.\n- `prepare(string $query): Sqlx\\PreparedQuery` – returns a reusable prepared query object bound to the same driver.\n\n#### Row helpers\n\n| Method                 | Returns                             | Notes                         |\n|------------------------|-------------------------------------|-------------------------------|\n| `queryRow()`           | first row (array \\| object)         | exception if no rows returned |\n| `queryRowAssoc()`      | first row (array)                   | ∟ enforces array mode         |\n| `queryRowObj()`        | first row (object)                  | ∟ enforces object mode        |\n| `queryMaybeRow()`      | first row (array \\| object \\| null) | null if no rows returned      |\n| `queryMaybeRowAssoc()` | first row (array \\| null)           | ∟ enforces array mode         |\n| `queryMaybeRowObj()`   | first row (object \\| null)          | ∟ enforces object mode        |\n\n#### Column helpers (single-row)\n\n| Method                   | Returns                        | Notes                                   |\n|--------------------------|--------------------------------|-----------------------------------------|\n| `queryValue()`           | first row column value         | exception if no rows returned           |\n| `queryValueAssoc()`      | ↑                              | ∟ enforces array mode for JSON objects  |\n| `queryValueObj()`        | ↑                              | ∟ enforces object mode for JSON objects |\n| `queryMaybeValue()`      | first row column value or null | null if no rows returned                |\n| `queryMaybeValueAssoc()` | ↑                              | ∟ enforces array mode for JSON objects  |\n| `queryMaybeValueObj()`   | ↑                              | ∟ enforces object mode for JSON objects |\n\n#### Column helpers (multi-row)\n\n| Method               | Returns                                | Notes                                   |\n|----------------------|----------------------------------------|-----------------------------------------|\n| `queryColumn()`      | array of column's values from each row | exception if no rows returned           |\n| `queryColumnAssoc()` | ↑                                      | ∟ enforces array mode for JSON objects  |\n| `queryColumnObj()`   | ↑                                      | ∟ enforces object mode for JSON objects |\n\n#### List helpers (all rows)\n\n| Method            | Returns               |\n|-------------------|-----------------------|\n| `queryAll()`      | array of rows         |\n| `queryAllAssoc()` | array of assoc arrays |\n| `queryAllObj()`   | array of objects      |\n\n#### Mutation helpers\n\n- `execute(string $query, array $parameters = null): int` – run **INSERT/UPDATE/DELETE** and return affected count.\n- `insert(string $table, array $row): int` – convenience wrapper around `INSERT`.\n\n#### Utilities\n\n- `dry(string $query, array $parameters = null): array` – render final SQL + bound parameters without executing. Handy\n  for\n  debugging.\n\n---\n\n### Sqlx\\PreparedQuery\n\nPrepared queries expose exactly the same surface as the driver, but without the SQL argument:\n\n```php\n$query = $driver-\u003eprepare(\"SELECT * FROM logs WHERE level = $level\");\n$rows  = $query-\u003equeryAll(['level' =\u003e 'warn']);\n```\n\nAll helpers listed above have their prepared-query counterparts:\n\n- `execute()`\n- `queryRow()` / `queryRowAssoc()` / `queryRowObj()`\n- `queryAll()` / `queryAllAssoc()` / `queryAllObj()`\n- `queryDictionary()` / `queryDictionaryAssoc()` / `queryDictionaryObj()`\n- `queryGroupedDictionary()` / `queryGroupedDictionaryAssoc()` / `queryGroupedDictionaryObj()`\n- `queryColumnDictionary()` / `queryColumnDictionaryAssoc()` / `queryColumnDictionaryObj()`\n\n---\n\n### Dictionary helpers (first column as key, row as value)\n\n| Method                   | Returns                                 | Notes                                  |\n|--------------------------|-----------------------------------------|----------------------------------------|\n| `queryDictionary()`      | `array\u003cstring \\| int, array \\| object\u003e` | key = first column, value = entire row |\n| `queryDictionaryAssoc()` | `array\u003cstring \\| int, array\u003e`           | ∟ forces associative arrays            |\n| `queryDictionaryObj()`   | `array\u003cstring \\| int, object\u003e`          | ∟ forces objects                       |\n\n\u003e - ⚠️ First column **must** be scalar, otherwise an exception will be thrown.\n\u003e - 🔀 The iteration order is preserved.\n\n```php\nvar_dump($driver-\u003equeryGroupedColumnDictionary(\n    'SELECT department, name FROM employees WHERE department IN (?)',\n    [['IT', 'HR']]\n));\n/* Output:\narray(2) {\n  [\"IT\"]=\u003e array(\"Alice\", \"Bob\")\n  [\"HR\"]=\u003e array(\"Eve\")\n}\n*/\n```\n\n---\n\n### Column Dictionary helpers (first column as key, second as value)\n\n| Method                         | Returns                       | Notes                                                   |\n|--------------------------------|-------------------------------|---------------------------------------------------------|\n| `queryColumnDictionary()`      | `array\u003cstring \\| int, mixed\u003e` | key = first column, value = second column               |\n| `queryColumnDictionaryAssoc()` | ↑                             | ∟ enforces array mode for second column if it's a JSON  |\n| `queryColumnDictionaryObj()`   | ↑                             | ∟ enforces object mode for second column if it's a JSON |\n\n```php\nvar_dump($driver-\u003equeryColumnDictionary(\n    'SELECT name, age FROM people WHERE name IN (?)',\n    [[\"Peter\", \"John\", \"Jane\"]]\n));\n/* Output:\narray(1) {\n  [\"John\"]=\u003e\n  int(22)\n}\n*/\n```\n\n---\n\n### Grouped Dictionary helpers (first column as key, many rows per key)\n\n| Method                          | Returns                                 | Notes                                             |\n|---------------------------------|-----------------------------------------|---------------------------------------------------|\n| `queryGroupedDictionary()`      | `array\u003cstring, array\u003carray \\| object\u003e\u003e` | key = first column, value = list of matching rows |\n| `queryGroupedDictionaryAssoc()` | `array\u003cstring, array\u003carray\u003e`            | ∟ forces associative arrays                       |\n| `queryGroupedDictionaryObj()`   | `array\u003cstring, array\u003cobject\u003e\u003e`          | ∟ forces objects                                  |\n\n```php\nvar_dump($driver-\u003equeryGroupedDictionary(\n    'SELECT department, name FROM employees WHERE department IN (?)',\n    [['IT', 'HR']]\n));\n/* Output:\narray(1) {\n  [\"IT\"]=\u003e\n  array(2) {\n    [0]=\u003e\n    object(stdClass)#2 (2) {\n      [\"department\"]=\u003e\n      string(2) \"IT\"\n      [\"name\"]=\u003e\n      string(5) \"Alice\"\n    }\n    [1]=\u003e\n    object(stdClass)#3 (2) {\n      [\"department\"]=\u003e\n      string(2) \"IT\"\n      [\"name\"]=\u003e\n      string(3) \"Bob\"\n    }\n  }\n}\n*/\n```\n\n---\n\n## Data Binding\n\nSupported parameter types:\n\n```php\n\"text\"\n123\n3.14\ntrue\n[1, 2, 3]\n```\n\nNested arrays are automatically flattened and bound in order.\n\n---\n\n## BigInt Support\n\nPostgreSQL `BIGINT` values are safely mapped to PHP integers:\n\n```php\nvar_dump($driver-\u003equeryValue('SELECT ((1::BIGINT \u003c\u003c 62) - 1) * 2 + 1');\n// Output: int(9223372036854775807)\n```\n\n---\n\n## Notes\n\n- The AST cache reduces repeated parsing overhead and speeds up query rendering.\n- Supports both positional `?`, `$1`, `:1` and named `$param`, `:param` placeholders automatically.\n\n---\n\n## Performance\n\n### Rust benchmarks\n\nBenchmarking pure Rust performance is more useful for optimizing the backend.\n\nCommand:\n\n```shell\ncargo bench\n```\n\nHere are M1 Max results for parsing and rendering a hefty query. No caching involved.\n\n```\n     Running benches/benchmark.rs (target/release/deps/benchmark-eaed67cfaa034b35)\nGnuplot not found, using plotters backend\nAst::parse_small        time:   [2.5877 µs 2.5928 µs 2.5981 µs]\n                        change: [−0.4151% −0.0902% +0.2146%] (p = 0.57 \u003e 0.05)\n                        No change in performance detected.\nFound 3 outliers among 100 measurements (3.00%)\n  1 (1.00%) low mild\n  1 (1.00%) high mild\n  1 (1.00%) high severe\n\nAst::parse_big          time:   [7.2626 µs 7.2785 µs 7.2958 µs]\n                        change: [+0.1364% +0.4485% +0.7694%] (p = 0.00 \u003c 0.05)\n                        Change within noise threshold.\nFound 3 outliers among 100 measurements (3.00%)\n  2 (2.00%) high mild\n  1 (1.00%) high severe\n\nAst::render_big         time:   [1.9188 µs 1.9215 µs 1.9243 µs]\nFound 5 outliers among 100 measurements (5.00%)\n  5 (5.00%) high mild\n\n```\n\n### PHP benchmarks\n\nCommand:\n\n```shell\ncd benches\ncurl -s https://raw.githubusercontent.com/composer/getcomposer.org/f3108f64b4e1c1ce6eb462b159956461592b3e3e/web/installer | php -- --quiet\n./composer.phar require phpbench/phpbench --dev\n./vendor/bin/phpbench run benchmark.php\n```\n\nOr use Docker:\n\n```shell\ndocker build . -t php-sqlx-benches\ndocker run php-sqlx-benches\n```\n\nM1 Max results:\n\n```\n    benchDrySmall...........................I0 - Mo2.009μs (±0.00%)\n    benchDryBig.............................I0 - Mo5.105μs (±0.00%)\n    benchSelect1kRows.......................I0 - Mo927.888μs (±0.00%)\n```\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkakserpom%2Fphp-sqlx-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkakserpom%2Fphp-sqlx-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkakserpom%2Fphp-sqlx-rs/lists"}