{"id":40841118,"url":"https://github.com/kamusis/swissql","last_synced_at":"2026-01-21T23:03:40.111Z","repository":{"id":332137904,"uuid":"1129608996","full_name":"kamusis/swissql","owner":"kamusis","description":"SwissQL is a developer-focused, modern “database Swiss Army knife” that provides a unified CLI experience for connecting to and querying different databases through a lightweight backend service.","archived":false,"fork":false,"pushed_at":"2026-01-12T16:01:29.000Z","size":294,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-12T21:40:17.751Z","etag":null,"topics":["ai","cli","client-server","database"],"latest_commit_sha":null,"homepage":"","language":"Java","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/kamusis.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,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-07T10:28:04.000Z","updated_at":"2026-01-12T16:01:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kamusis/swissql","commit_stats":null,"previous_names":["kamusis/swissql"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/kamusis/swissql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamusis%2Fswissql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamusis%2Fswissql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamusis%2Fswissql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamusis%2Fswissql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kamusis","download_url":"https://codeload.github.com/kamusis/swissql/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamusis%2Fswissql/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28646571,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T21:29:11.980Z","status":"ssl_error","status_checked_at":"2026-01-21T21:24:31.872Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["ai","cli","client-server","database"],"created_at":"2026-01-21T23:03:38.078Z","updated_at":"2026-01-21T23:03:40.102Z","avatar_url":"https://github.com/kamusis.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SwissQL 🛠️\n\nSwissQL is a developer-focused, modern “database Swiss Army knife” that provides a unified CLI experience for connecting to and querying different databases through a lightweight backend service.\n\nThe MVP uses an **HTTP/JSON (REST)** protocol between the CLI and backend to keep local development and debugging simple, with a planned evolution path toward streaming and higher-performance protocols (e.g., gRPC).\n\n## What this project does\n\n- A **Go-based CLI** that provides a convenient command interface for database workflows.\n- A **Java 21 backend API** that manages connections and executes SQL against target databases via **JDBC**.\n- A forward-looking design for **AI-assisted SQL generation** and **MCP-based extensibility** (plugin-style routing), while keeping JDBC as the core execution path.\n\n## High-level architecture\n\n- **CLI (Go)**\n  - Command engine built with Cobra.\n  - Communicates with the backend via HTTP/JSON.\n- **Backend service (Java 21, Spring Boot)**\n  - REST API layer.\n  - Connection/session management and JDBC execution.\n  - Uses HikariCP for JDBC connection pooling.\n  - Packs common database drivers in the service (Oracle and PostgreSQL are included in the Maven dependencies).\n\n```text\nUser -\u003e swissql-cli (Go) -\u003e HTTP/JSON -\u003e swissql-backend (Java/Spring Boot) -\u003e JDBC -\u003e Database\n```\n\n## Quick Start\n\n- **Start swissql-backend (Docker)**\n\n```powershell\n# Windows PowerShell example:\ndocker run -d --rm --name swissql-backend `\n  -p 8080:8080 `\n  ghcr.io/kamusis/swissql-backend\n```\n\n- **Connect from SwissQL CLI to a Oracle database via the backend**\n\n```bash\nswissql connect \"oracle://user:password@host:port/serviceName\"\n```\n- **Connect from SwissQL CLI to a PostgreSQL database via the backend**\n\n```bash\n# if Postgres runs on the host and backend runs in Docker, use host.docker.internal instead of localhost:\n./swissql connect \"postgres://postgres:postgres@host.docker.internal:5432/postgres\"\n```\n\n## Advanced usage\n\n### DBeaver Project Import\n\nSwissQL can import connection profiles from DBeaver `.dbp` project files:\n\n```bash\n# Import all connections from a DBeaver project\nswissql import-dbeaver-project --dbp /path/to/project.dbp\n\n# Import with prefix for profile names\nswissql import-dbeaver-project --dbp project.dbp --conn_prefix \"prod\"\n\n# Dry run to see what would be created\nswissql import-dbeaver-project --dbp project.dbp --dry_run\n\n# Handle conflicts (skip, fail, or overwrite)\nswissql import-dbeaver-project --dbp project.dbp --on_conflict overwrite\n```\n\n**Features:**\n- Automatic database type detection and DSN conversion\n- Profile name sanitization and conflict handling\n- Secure credential handling (passwords not imported, prompted on first use)\n- Support for various database types (Oracle, PostgreSQL, MySQL, SQL Server, DB2, Informix, etc.)\n\n### Profile Management\n\nSwissQL supports persistent connection profiles with encrypted credential storage:\n\n```bash\n# List all profiles\nswissql list profiles\n\n# List profiles with filtering\nswissql list profiles --filter db_type=postgres\nswissql list profiles --filter name=prod --filter save_password=true\n\n# Connect using saved profile\nswissql connect --profile my-oracle-db\n# Or shorthand in REPL:\nswissql\u003e connect my-oracle-db\n```\n\n**Profile Storage:**\n- Profiles: `~/.swissql/connections.json`\n- Credentials: `~/.swissql/credentials.json` (AES-CBC encrypted)\n- Automatic credential prompting and optional saving\n\n### Driver Support\n\nSwissQL supports both built-in and directory-provided JDBC drivers:\n\n**Built-in Drivers:**\n- Oracle (ojdbc11)\n- PostgreSQL (postgresql)\n\n**Directory-provided Drivers:**\nPlace JDBC drivers and manifests in `swissql-backend/jdbc_drivers/\u003cdb_type\u003e/`:\n\n```\njdbc_drivers/\n├── mysql/\n│   ├── driver.json\n│   └── mysql-connector-j-8.x.x.jar\n├── sqlserver/\n│   ├── driver.json\n│   └── mssql-jdbc-12.x.x.jar\n└── yashandb/\n    ├── driver.json\n    └── yasdb-jdbc-23.x.x.jar\n```\n\n**Driver Manifest Example:**\n```json\n{\n  \"dbType\": \"mysql\",\n  \"aliases\": [\"mariadb\"],\n  \"driverClass\": \"com.mysql.cj.jdbc.Driver\",\n  \"jdbcUrlTemplate\": \"jdbc:mysql://{host}:{port}/{database}\",\n  \"defaultPort\": 3306\n}\n```\n\n- **Enable AI features (Docker Compose + Docker secrets)**\n\nIf you want to use `/ai ...`, you can enable the AI gateway by providing a few configuration values as Docker secrets (no `application.properties` file and no `/config` mount required).\n\nRecommended workflow (you can do this in any folder on your machine):\n\n1. Create a working directory (example name: `swissql-backend`) and `cd` into it.\n2. Create the 3 secret files under `./secrets/`.\n3. Create `docker-compose.yml` in the same directory.\n4. Start the container.\n\nExample (Windows PowerShell):\n\n```powershell\n# 1) Create a working directory anywhere\nmkdir swissql-backend\ncd swissql-backend\n\n# 2) Create secrets (files contain ONLY the raw value, no KEY= prefix)\nmkdir secrets\nSet-Content -NoNewline -Path .\\secrets\\PORTKEY_API_KEY -Value \"\u003cyour_portkey_api_key\u003e\"\nSet-Content -NoNewline -Path .\\secrets\\PORTKEY_VIRTUAL_KEY -Value \"\u003cyour_portkey_virtual_key\u003e\"\nSet-Content -NoNewline -Path .\\secrets\\PORTKEY_MODEL -Value \"\u003cyour_model\u003e\"\n\n# 3) Create docker-compose.yml (see below)\n# 4) Start\ndocker compose up -d\n```\n\n`docker-compose.yml` example (saved next to the `secrets/` folder):\n\n```yaml\nservices:\n  swissql-backend:\n    image: ghcr.io/kamusis/swissql-backend:latest\n    container_name: swissql-backend\n    ports:\n      - \"8080:8080\"\n    secrets:\n      - PORTKEY_API_KEY\n      - PORTKEY_VIRTUAL_KEY\n      - PORTKEY_MODEL\n\nsecrets:\n  PORTKEY_API_KEY:\n    file: ./secrets/PORTKEY_API_KEY\n  PORTKEY_VIRTUAL_KEY:\n    file: ./secrets/PORTKEY_VIRTUAL_KEY\n  PORTKEY_MODEL:\n    file: ./secrets/PORTKEY_MODEL\n```\n\nFor additional (optional) settings, see the **AI setup** section below.\n\n- **Mounting Oracle wallets folder**\n\nIf you are connecting to an Oracle instance in OCI (for example, Autonomous Database), you typically need an Oracle client wallet (mTLS) in order to authenticate and connect. In that case, you must mount the wallet directory into the container, and set `TNS_ADMIN` to the wallet path inside the container (for example, `/wallets/ora1`). You can mount multiple wallet directories at the same time (for example, `/wallets/ora1`, `/wallets/ora2`) and connect to different Oracle instances by setting `TNS_ADMIN` accordingly in each CLI connection string.\n\n`docker-compose.yml` example (AI secrets + multiple wallet mounts):\n\n```yaml\nservices:\n  swissql-backend:\n    image: ghcr.io/kamusis/swissql-backend:latest\n    container_name: swissql-backend\n    ports:\n      - \"8080:8080\"\n    volumes:\n      - \"/path/to/Wallet1_OCI:/wallets/ora1:ro\"\n      - \"/path/to/Wallet2_OCI:/wallets/ora2:ro\"\n    secrets:\n      - PORTKEY_API_KEY\n      - PORTKEY_VIRTUAL_KEY\n      - PORTKEY_MODEL\n\nsecrets:\n  PORTKEY_API_KEY:\n    file: ./secrets/PORTKEY_API_KEY\n  PORTKEY_VIRTUAL_KEY:\n    file: ./secrets/PORTKEY_VIRTUAL_KEY\n  PORTKEY_MODEL:\n    file: ./secrets/PORTKEY_MODEL\n```\n\n\u003e **Note for Windows users:** When specifying volume paths in `docker-compose.yml`, use single quotes (e.g., `'C:/path/to/wallet'`) or forward slashes to avoid issues with YAML parsing backslashes.\n\n```bash\ndocker compose up -d\n```\n\nConnect from SwissQL CLI to the Oracle instance in OCI via the backend\n\n```bash\n# Oracle (OCI) via mounted wallet (TNS_ADMIN points to the container path):\n./swissql connect \"oracle://user:password@aora23ai_high?TNS_ADMIN=/wallets/ora1\"\n```\n\n## Current MVP capabilities\n\nThe backend currently implements the following REST endpoints:\n\n- **Health**\n  - `GET /v1/status`\n- **Sessions**\n  - `POST /v1/connect` (returns `session_id`)\n  - `POST /v1/disconnect?session_id=...`\n  - `GET /v1/sessions/validate?session_id=...`\n- **SQL execution**\n  - `POST /v1/execute_sql`\n- **Collectors (YAML-defined tools)**\n  - `GET /v1/collectors/list?session_id=...`\n  - `GET /v1/collectors/queries?session_id=...\u0026collector_id=...`\n  - `POST /v1/collectors/run`\n- **Samplers (session-scoped resources)**\n  - `PUT /v1/sessions/{session_id}/samplers/{sampler_id}`\n  - `DELETE /v1/sessions/{session_id}/samplers/{sampler_id}`\n  - `GET /v1/sessions/{session_id}/samplers`\n  - `GET /v1/sessions/{session_id}/samplers/{sampler_id}`\n  - `GET /v1/sessions/{session_id}/samplers/{sampler_id}/snapshot`\n- **Metadata helpers**\n  - `GET /v1/meta/list?session_id=...\u0026kind=table|view\u0026schema=...`\n  - `GET /v1/meta/describe?session_id=...\u0026name=...\u0026detail=full`\n  - `GET /v1/meta/conninfo?session_id=...`\n  - `POST /v1/meta/explain` (supports `analyze`)\n- **Autocomplete / completions**\n  - `GET /v1/meta/completions?session_id=...\u0026kind=schema|table|column\u0026schema=...\u0026table=...\u0026prefix=...`\n- **AI assistance**\n  - `POST /v1/ai/generate` (generates SQL JSON; does not execute)\n  - `GET /v1/ai/context?session_id=...\u0026limit=...`\n  - `POST /v1/ai/context/clear`\n- **Driver management**\n  - `GET /v1/meta/drivers` (list loaded JDBC drivers)\n  - `POST /v1/meta/drivers/reload` (reload drivers from directory)\n\nThe CLI currently provides an interactive REPL with the following commands:\n\n- **CLI**\n  - `help` (show help)\n  - `detach` (leave REPL without disconnecting)\n  - `exit | quit` (disconnect backend session and remove it from registry)\n  - `set display wide|narrow` (toggle truncation mode)\n  - `set display expanded on|off` (expanded display mode)\n  - `set display width \u003cn\u003e` (set max column width)\n  - `set output table|csv|tsv|json` (set output format)\n  - `import-dbeaver-project` (import DBeaver .dbp project connections)\n  - `list profiles` (list saved connection profiles with filtering)\n- **psql-compat (\\\\)**\n  - `\\conninfo` (show current session and backend information)\n  - `\\d \u003cname\u003e` (alias: `desc`) (describe a table/view)\n  - `\\d+ \u003cname\u003e` (alias: `desc+`) (describe with more details)\n  - `\\dt | \\dv` (list tables/views)\n  - `\\explain \u003csql\u003e` (aliases: `explain`, `explain plan for`) (show execution plan)\n  - `\\explain analyze \u003csql\u003e` (alias: `explain analyze`) (show actual execution plan; executes the statement)\n  - `\\top` (render latest sampler snapshot for `top`)\n  - `\\sampler \u003caction\u003e \u003csampler_id\u003e` (control samplers)\n  - `\\swiss list` (list available collectors)\n  - `\\swiss list queries [--collector=\u003ccollector_id\u003e]` (list runnable queries under `queries:` blocks)\n  - `\\swiss run \u003cquery_id\u003e [--param=value]` (run a query; auto-resolve collector)\n  - `\\swiss run \u003ccollector_id|collector_ref\u003e \u003cquery_id\u003e [--param=value]` (run a query; explicit collector)\n  - `\\watch \u003ccommand\u003e` (repeatedly execute a command (e.g., `\\watch top`))\n  - `\\i \u003cfile\u003e` (alias: `@\u003cfile\u003e`) (execute statements from a file)\n  - `\\x [on|off]` (expanded display mode)\n  - `\\o \u003cfile\u003e` (redirect query output to a file)\n  - `\\o` (restore output to stdout)\n- **AI (/)**\n  - `/ai \u003cprompt\u003e` (generate SQL via AI and confirm before execution)\n  - `/context show` (show recent executed SQL context used by AI)\n  - `/context clear` (clear AI context)\n\n\u003e **Note**\n\u003e \n\u003e If you are not a developer, you can stop here. The content below is mainly for contributors/developers.\n\n## **Architecture Principles**\n\nThis repository is intentionally structured as a multi-client architecture (today: CLI; future: GUI).\n\nThe most important rule:\n\n- **DO NOT IMPLEMENT BUSINESS LOGIC IN THE CLI !!** All business logic must be designed and implemented as backend APIs first. The CLI is only a thin client responsible for calling backend APIs and presenting results in the terminal.\n\nThis keeps the domain logic centralized and makes it straightforward to add additional clients (for example a GUI) without re-implementing logic.\n\n## Developer setup (local)\n\n### Prerequisites\n\n- **Go**: 1.23.x (see `swissql-cli/go.mod`)\n- **Java**: 21 (see `swissql-backend/pom.xml`)\n- **Maven**: 3.8+ recommended\n- Access to a target database (e.g., Oracle or PostgreSQL) and credentials.\n\n### Clone the repository\n\n```bash\ngit clone \u003cyour-github-repo-url\u003e\n```\n\n### Run the backend (Spring Boot)\n\nFrom the repository root, build and run:\n\n```bash\nmvn -f swissql-backend/pom.xml -DskipTests package\nmvn -f swissql-backend/pom.xml spring-boot:run\n```\n\nThe backend should start on localhost (see Spring Boot defaults / project configuration).\n\nIf you want to use the local configuration, set the `SPRING_PROFILES_ACTIVE` environment variable to `local` before starting the backend:\n\n```powershell\n$env:SPRING_PROFILES_ACTIVE = \"local\"\n```\n\nYou can verify it via:\n\n```bash\ncurl http://localhost:8080/v1/status\n```\n\n### Build and run the CLI\n\nBuild the CLI:\n\n```bash\ncd swissql-cli\n\ngo build -o swissql.exe .\n```\n\nRun:\n\n```bash\n./swissql.exe --help\n```\n\n### Typical local workflow\n\n- Start the backend service.\n- Use the CLI commands to:\n  - Connect to a DB (backend creates a session).\n  - Execute SQL using the returned session.\n\n### AI setup (optional)\n\nThe backend can generate SQL from natural language via an OpenAI-compatible gateway (Portkey by default). If AI is not configured, the endpoint still exists but returns an “AI generation is disabled” response.\n\nWhere to store configuration locally:\n\n- Option A (recommended for local dev): use `swissql-backend/src/main/resources/application-local.properties` (gitignored) and keep secrets out of Git.\n  - A committed template is available at `swissql-backend/src/main/resources/application-example.properties`.\n- Option B: export environment variables in your shell before starting the backend.\n\nEnable the `local` Spring profile (PowerShell) before starting the backend:\n\n```powershell\n$env:SPRING_PROFILES_ACTIVE=\"local\"\n```\n\nRequired environment variables:\n\n- `PORTKEY_API_KEY`\n- `PORTKEY_VIRTUAL_KEY` (or `PORTKEY_VIRTUAL_KEY_\u003cPROFILE\u003e`)\n- `PORTKEY_MODEL` (or `PORTKEY_MODEL_\u003cPROFILE\u003e`)\n\nOptional environment variables:\n\n- `PORTKEY_PROFILE` (e.g. `DEV`, `PROD`)\n- `PORTKEY_BASE_URL` (or `PORTKEY_BASE_URL_\u003cPROFILE\u003e`, defaults to `https://api.portkey.ai`)\n- `PORTKEY_TIMEOUT_MS` (request timeout in milliseconds, defaults to `30000`)\n\nProfile example (`PORTKEY_PROFILE=DEV`):\n\n- `PORTKEY_VIRTUAL_KEY_DEV=...`\n- `PORTKEY_MODEL_DEV=...`\n- (optional) `PORTKEY_BASE_URL_DEV=...`\n\n### DSN format (Oracle)\n\nThe design document defines the Oracle DSN semantics as:\n\n- Service name:\n  - `oracle://user:password@host:port/serviceName`\n- SID (via query parameter):\n  - `oracle://user:password@host:port/?sid=ORCL`\n\nFor Oracle Cloud / Autonomous Database connections using a Wallet (TNS alias), the backend also supports passing `TNS_ADMIN` as a query parameter. The host part is treated as the TNS alias (for example `ora23ai_high`).\n\nExample:\n\n`oracle://user:password@ora23ai_high?TNS_ADMIN=/path/to/Wallet_ORA23AI`\n\nNote: if your wallet path contains spaces or special characters, URL-encode the value (e.g., replace spaces with `%20`). The backend URL-decodes DSN query parameters such as `TNS_ADMIN`.\n\nIf your username/password contains URL-reserved characters (for example `@`, `:`), URL-encode them as well.\n\n## Repository structure\n\n```text\nswissql-cli/        # Go CLI\nswissql-backend/    # Java 21 Spring Boot backend\n```\n\n## Notes\n\n- The protocol and endpoints are designed for an MVP-friendly REST API and may evolve.\n- Do not commit credentials. Use environment variables, stdin-based password input, or your OS keychain (planned).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkamusis%2Fswissql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkamusis%2Fswissql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkamusis%2Fswissql/lists"}