{"id":18382609,"url":"https://github.com/stefanov-sm/sqlmethods","last_synced_at":"2025-04-11T21:26:12.578Z","repository":{"id":146063687,"uuid":"211714071","full_name":"stefanov-sm/SQLMethods","owner":"stefanov-sm","description":"Define PHP methods as SQL queries","archived":false,"fork":false,"pushed_at":"2020-02-18T10:20:23.000Z","size":155,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-15T23:42:24.731Z","etag":null,"topics":["php","postgresql","sql"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stefanov-sm.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":"2019-09-29T19:20:53.000Z","updated_at":"2020-02-18T10:20:25.000Z","dependencies_parsed_at":"2023-04-08T02:17:00.579Z","dependency_job_id":null,"html_url":"https://github.com/stefanov-sm/SQLMethods","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stefanov-sm%2FSQLMethods","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stefanov-sm%2FSQLMethods/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stefanov-sm%2FSQLMethods/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stefanov-sm%2FSQLMethods/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stefanov-sm","download_url":"https://codeload.github.com/stefanov-sm/SQLMethods/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248481886,"owners_count":21111234,"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":["php","postgresql","sql"],"created_at":"2024-11-06T01:07:02.085Z","updated_at":"2025-04-11T21:26:12.551Z","avatar_url":"https://github.com/stefanov-sm.png","language":"PHP","readme":"# SQLMethods\nLightweight PHP class with no dependencies to dynamically define methods as queries in SQL files.\u003cbr/\u003e\nClean separation of concerns inspired by [this](https://www.youtube.com/watch?v=q9IXCdy_mtY) talk and **YeSQL**.\nAll that matters is there in the PHP CLI example.\n\n### File _example.sql_ - the queries that become methods\nIndividual queries have names (Ruffus, Buster, Gracie, ISOTime in the example below) that become methods' names.\n\n```SQL\n-- SQLMethods example SQL file\n\n-- Query definition header format:\n-- Single line starts with --! followed by metadata in JSON\n-- Metadata JSON format: {\"name\":\u003cquery name\u003e, \"param_mode\":\u003cparameters mode\u003e [,\"returns_value\":\u003creturn mode\u003e]}\n-- \u003cquery name\u003e is a valid K\u0026R indentifier string that becomes a method name;\n-- \u003cparameters mode\u003e is one of \"NONE\", \"NAMED\" or \"POSITIONAL\"\n-- \u003creturn mode\u003e (optional) is true or false (default)\n-- See the example below\n\n-- No parameters\n--! {\"name\":\"RUFFUS\", \"param_mode\":\"NONE\"}\nSELECT v, to_char(123 + v, 'FMRN')\n FROM generate_series (10, 12, 1) t(v);\n\n-- Named parameters\n--! {\"name\":\"Buster\", \"param_mode\":\"NAMED\"}\nSELECT v, to_char(234 + v, 'FMRN')\n FROM generate_series (:lo, :hi, 1) t(v);\n\n-- Positional parameters\n--! {\"name\":\"Gracie\", \"param_mode\":\"POSITIONAL\"}\nSELECT v, to_char(345 + v, 'FMRN')\n FROM generate_series (?, ?, 1) t(v);\n \n-- Positional parameters, returns a single value\n--! {\"name\":\"ISOTime\", \"param_mode\":\"POSITIONAL\", \"returns_value\": true}\nSELECT to_char(now() - ?::interval, 'YYYY-MM-DD\"T\"HH24:MI:SS');\n```\n- Note these query definition header lines that provide a name and parameters' mode value to each query:  \n```\n--! {\"name\":\"RUFFUS\", \"param_mode\":\"NONE\"}  \n--! {\"name\":\"Buster\", \"param_mode\":\"NAMED\"}  \n--! {\"name\":\"Gracie\", \"param_mode\":\"POSITIONAL\"}\n--! {\"name\":\"ISOTime\", \"param_mode\":\"POSITIONAL\", \"returns_value\": true}\n```\n\n- Each query definition header consists of a single line that starts with `--!` prefix followed by a JSON expression with these mandatory attributes: `\"name\"`, `\"param_mode\"` and an optional one `\"returns_value\"`.\n- The value of \"param_mode\" must be one of `\"NONE\"`, `\"NAMED\"` or `\"POSITIONAL\"`. The semantics of those are best seen in the example.\n- The value of \"name\" must be a valid K\u0026R-style identifier.\n- The value of \"returns_value\" must be `true` or `false` (default).\n- Real-life queries may be of any size and complexity.\n- Block comments are not supported.\n- If \"returns_value\" is missing or false then the methods return a [PDOStatement](https://www.php.net/manual/en/class.pdostatement.php) object (resultset).  \n- If \"returns_value\" is true then the methods retun a single value by invoking `fetchColumn()` on the resultset.\n- [This](https://github.com/stefanov-sm/SQLMethods/blob/master/query.header.schema.json) JSON schema contains a strict definition. \n### SQLMethods constructor\n\nA SQLMethods object is created by instantiating the SQLMethods class.  \n`SQLMethods::__construct(optional \u003csql file name\u003e, optional \u003cPDO connection\u003e)`\n - `\u003csql file name\u003e` - name of the SQL file (as the one above)\n - `\u003cPDO connection\u003e` - existing PDO connection object\n\n### SQLMethods instance factory\n\nStatic method. Creates and returns a SQLMethods instance object that can be chained.   \n`SQLMethods::createInstance(optional \u003cPDO connection\u003e)`\n - `\u003cPDO connection\u003e` - existing PDO connection object\n\n### Connection setter\n\nSets the PDO connection  \n`SQLMethods::connection(\u003cPDO connection\u003e)`\n - `\u003cPDO connection\u003e` - existing PDO connection object\n - returns the object instance that can be chained\n\n### SQL file importer\n\nParses and imports SQL method definitions.   \n`SQLMethods::import(\u003cfilename\u003e)`\n - `\u003cfilename\u003e` - existing SQL file\n - returns the object instance that can be chained\n\n\n### Usage example (PHP CLI) in file _example.php_  \nThis particular example uses [PostgreSQL](https://www.postgresql.org/) PDO connection.\n```PHP\n\u003c?php\n// SQLMethods example/unit test\n\n// Use your preferred class loading mechanism\nrequire ('SQLMethods.class.php');\n\n// Obtain a PDO connection in your preferred way\n$conn = new PDO (\n    'pgsql:host=\u003chost\u003e;port=\u003cport\u003e;dbname=\u003cdatabase name\u003e',\n    '\u003cuser\u003e', '\u003cpassword\u003e',\n    [PDO::ATTR_ERRMODE =\u003e PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES =\u003e FALSE]\n);\n\n/* There are different ways to build SQLMethod instances and inport SQL files \n\n// Use a single SQL file\n$dbgw = new SQLMethods('sql/example.sql', $conn);\n\n// Use many SQL files\n$dbgw = new SQLMethods;\n$dbgw -\u003e connection($conn);\n$dbgw -\u003e import('sql/none.sql');\n$dbgw -\u003e import('sql/named.sql');\n$dbgw -\u003e import('sql/positional.sql');\n$dbgw -\u003e import('sql/value.sql');\n*/\n\n// Use many SQL files w/ method chaining\n$dbgw = SQLMethods::createInstance($conn)\n -\u003e import('sql/none.sql')\n -\u003e import('sql/named.sql')\n -\u003e import('sql/positional.sql')\n -\u003e import('sql/value.sql');\n \n// call a method with no arguments\n$result = $dbgw -\u003e Ruffus();\necho SQLMethods::dump_rs($result);\necho PHP_EOL.PHP_EOL;\n\n// call a method with named arguments\n$result = $dbgw -\u003e Buster([':hi' =\u003e 17, ':lo' =\u003e 15]);\necho SQLMethods::dump_rs($result);\necho PHP_EOL.PHP_EOL;\n\n// call a method with positional arguments\n$result = $dbgw -\u003e Gracie(18, 20);\necho SQLMethods::dump_rs($result);\necho PHP_EOL.PHP_EOL;\n\n// call a method with positional arguments that returns a single value\n$result = $dbgw -\u003e ISOTime('2 days');\necho $result;\necho PHP_EOL.PHP_EOL;\n```\nQuery names have become method names.  \nQuery/method names and `param_mode` values are case-insensitive as it is common in SQL.\n```PHP\n$result = $dbgw -\u003e Ruffus();\n$result = $dbgw -\u003e Buster([':hi' =\u003e 17, ':lo' =\u003e 15]);\n$result = $dbgw -\u003e Gracie(18, 20);\n$result = $dbgw -\u003e ISOTime('2 days');\n```\nAnd here is the modest result.  \n```\nC:\\ ... \\SQLMethods\u003ephp example.php\nv: 10\nrn: CXXXIII\nv: 11\nrn: CXXXIV\nv: 12\nrn: CXXXV\n\nv: 15\nrn: CCXLIX\nv: 16\nrn: CCL\nv: 17\nrn: CCLI\n\nv: 18\nrn: CCCLXIII\nv: 19\nrn: CCCLXIV\nv: 20\nrn: CCCLXV\n\n2019-12-21T23:42:54\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstefanov-sm%2Fsqlmethods","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstefanov-sm%2Fsqlmethods","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstefanov-sm%2Fsqlmethods/lists"}