{"id":50493480,"url":"https://github.com/excelano/spsql","last_synced_at":"2026-06-02T05:00:49.351Z","repository":{"id":357440849,"uuid":"1236927143","full_name":"excelano/spsql","owner":"excelano","description":"SQL REPL for SharePoint Lists via Microsoft Graph","archived":false,"fork":false,"pushed_at":"2026-06-02T03:43:13.000Z","size":139,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-02T04:23:28.348Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","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/excelano.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-12T17:53:26.000Z","updated_at":"2026-06-02T03:43:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/excelano/spsql","commit_stats":null,"previous_names":["excelano/spsql"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/excelano/spsql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/excelano%2Fspsql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/excelano%2Fspsql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/excelano%2Fspsql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/excelano%2Fspsql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/excelano","download_url":"https://codeload.github.com/excelano/spsql/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/excelano%2Fspsql/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33806987,"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-02T02:00:07.132Z","response_time":109,"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":"2026-06-02T05:00:45.133Z","updated_at":"2026-06-02T05:00:49.345Z","avatar_url":"https://github.com/excelano.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# spsql\n\nA SQL REPL for SharePoint Lists. Bind to a single list at startup, then run SELECT, UPDATE, DELETE, and INSERT against it through the Microsoft Graph API.\n\n## Example\n\n```\n$ spsql --list https://contoso.sharepoint.com/sites/team/Lists/Tasks\nAuthenticated as: alice@contoso.com\nConnected to: Tasks (12 columns)\nspsql REPL — type \"help\" for commands, \"quit\" to exit.\n\nspsql\u003e SELECT Title, Status WHERE Priority \u003e 2\n| Title              | Status      |\n| ------------------ | ----------- |\n| Migrate auth layer | Open        |\n| Backfill activity  | In Progress |\n(2 rows)\n\nspsql\u003e SELECT DISTINCT Status\n| Status      |\n| ----------- |\n| Open        |\n| In Progress |\n| Done        |\n(3 rows)\n\nspsql\u003e SELECT Title, Modified ORDER BY Modified DESC LIMIT 3\n| Title              | Modified             |\n| ------------------ | -------------------- |\n| Migrate auth layer | 2024-03-12T09:14:00Z |\n| Backfill activity  | 2024-03-09T17:02:00Z |\n| Q3 invoice cleanup | 2024-02-28T11:48:00Z |\n(3 rows)\n\nspsql\u003e UPDATE SET Status = 'Done' WHERE Modified \u003c '2024-01-01'\nWould update 8 rows in Tasks:\n  SET Status = \"Done\"\nSample:\n| id | Title              |\n| -- | ------------------ |\n| 41 | Q3 invoice cleanup |\n| 47 | Audit log purge    |\n  ... 6 more\nApply? [y/N]: y\nUpdated 8 of 8 rows.\n```\n\n## Why\n\nSharePoint list management at scale is painful. The web UI gives up past a handful of rows, OData `$filter` gives you query but not mutation, and Power Automate flows for bulk updates are slow to build and slower to run. spsql is the smallest tool that solves the bulk mutation problem: write one SQL statement, see what it would affect, commit if it is right.\n\n## Install\n\nOn Debian or Ubuntu, install from the [Excelano apt repository](https://excelano.com/apt/) — add the repo once, then `apt upgrade` keeps it current:\n\n```sh\ncurl -fsSL https://excelano.com/apt/setup.sh | sudo sh\nsudo apt install spsql\n```\n\nFrom source (Go 1.24 or later):\n\n```\ngo install github.com/excelano/spsql@latest\n```\n\n## Usage\n\n### Interactive REPL\n\n```\nspsql --list \u003cSharePoint list URL\u003e\n```\n\nOpens a prompt bound to the list. Arrow keys recall history, Ctrl-R searches it, Ctrl-D exits. History persists at `~/.config/spsql/history` across sessions.\n\nThe REPL accepts SQL statements one per line plus a few meta-commands as plain words (case-insensitive): `help` or `?` shows command help, `describe` prints the column schema, `refresh` re-fetches the schema, and `quit` or `exit` leaves the REPL.\n\nWrites (INSERT, UPDATE, DELETE) preview by default. spsql prints the affected count, a sample of the rows that match, and then prompts `Apply? [y/N]:`. Anything but `y` cancels. Append `!` to skip the prompt and commit immediately:\n\n```sql\nUPDATE SET Status = 'Done' WHERE Modified \u003c '2024-01-01' !\n```\n\n### One-shot mode\n\n```\nspsql --list \u003cURL\u003e --exec \"\u003csql\u003e\"\n```\n\nRuns one statement and exits. Writes need `--commit`; a bare DELETE (no WHERE clause) additionally needs `--confirm-destructive`. Output auto-detects to ASCII table on an interactive terminal and TSV when piped. Override with `--format=json` for JSON, useful for scripts that consume the results.\n\n`SELECT *` returns visible user-defined columns by default. Pass `--all-fields` at startup to include hidden and system fields in `*` expansions; the flag works in both REPL and one-shot modes.\n\n## Authentication\n\nspsql signs in via OAuth device code flow against a multi-tenant public client Azure App Registration. By default it uses Excelano's published registration. On first run you will see a prompt to visit `https://microsoft.com/devicelogin` and enter a code, then sign in with the work account that has access to the list. The token is cached at `~/.config/spsql/token.json` and refreshed silently after that.\n\nIf you would rather use your own Azure App Registration (for audit log attribution or tenant policy), see [SELF-HOSTING.md](SELF-HOSTING.md). The override path is fork-and-build: clone, change one constant, `go build`. There is no runtime override flag, by design.\n\n## SQL subset\n\nspsql implements a deliberately small SQL grammar focused on what works against a single SharePoint list through Graph: SELECT and DML with literal values, simple WHERE predicates, no JOINs, no subqueries. See [GRAMMAR.md](GRAMMAR.md) for the full specification.\n\n## Security\n\nspsql is a CLI that runs locally and asks for delegated `Sites.ReadWrite.All`, scoped to what the signing user already has access to. Tokens stay on the machine; there is no telemetry. See [SECURITY.md](SECURITY.md) for the full policy and the vulnerability reporting process.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexcelano%2Fspsql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexcelano%2Fspsql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexcelano%2Fspsql/lists"}