Skip to content

Instantly share code, notes, and snippets.

@sumeet-bansal
Created May 8, 2026 15:24
Show Gist options
  • Select an option

  • Save sumeet-bansal/66a037aa0ade853189721df4c1a43898 to your computer and use it in GitHub Desktop.

Select an option

Save sumeet-bansal/66a037aa0ade853189721df4c1a43898 to your computer and use it in GitHub Desktop.
query-database skill for Traba — Postgres prod/dev + BigQuery marts/events

query-database

Query Traba's data sources directly. Two backends:

  • Postgres (operational replica) — live, transactional, narrow but deep. Use for the current state of any record.
  • BigQuery (analytics warehouse) — modeled, broad, includes data Postgres doesn't have. Use for analytics, history, app events, third-party tools, and LLM-categorized signals.

Default is Postgres prod. Pass dev, prod, or bq as the first word to override.

Usage

/query-database [question or SQL]                # postgres prod
/query-database dev <SQL>                         # postgres dev (write-capable)
/query-database bq <SQL>                          # bigquery

Postgres

bash ~/workspace/.claude/skills/query-database/query.sh <env> "<SQL>"
  • Schema lives in ~/workspace/monorepo/apps/traba-server-node/prisma/schema.prisma. Models have @@map("table_name"); fields have @map("columnName") when the Prisma name differs.
  • Tables: snake_case. Columns: camelCase in double quotes. Enums: 'UPPER_SNAKE_CASE'.
  • The dev user has write privileges. Only run writes when the user has explicitly asked.

BigQuery

bq query --use_legacy_sql=false --project_id=traba-app --format=pretty "<SQL>"

--project_id is required even when the SQL fully qualifies tables; without it bq errors with "Cannot start a job without a project id".

Tables are referenced as `traba-app.<dataset>.<table>`. All identifiers are lowercase snake_case in BigQuery — column names that are camelCase in Postgres become snake_case in BQ marts (workerIdworker_id).

Available projects and key datasets

  • traba-app — primary analytics project. Most useful datasets:
    • marts — modeled fact tables (worker_shifts, worker_applications, placements, shift_charges). LLM-enriched columns live here.
    • metrics — aggregated rollups (placements_by_day, monthly__worker_ltv, executive summaries).
    • worker_app, worker_app_legacy — Segment-tracked events from the worker mobile app (320+ event tables, every tap/click/screen-load).
    • intercom, intercom_intercom — full Intercom history including conversation_part_history (the actual messages, not just ticket metadata Postgres has).
    • freshdesk — Freshdesk tickets with conversation body.
    • firestore_export_prod — Firestore changelogs (timesheets, worker_shift, account_status).
    • src_pg — Postgres replica into BQ (so the same Postgres data, queryable analytically).
    • prod_node_server — backend server logs.
    • salesforce, prod_salesforce — Salesforce CRM data.
    • statsig — feature flag exposures.
  • traba-business-intelligence — BI workspace.
  • traba-ops — ops project (mostly user-personal datasets like traba_<username>).

When to use BigQuery vs Postgres

  • Postgres for: current state of a record, real-time data (anything written in the last few minutes), foreign-key joins to live data, anything you'd need to act on (modify, react to).
  • BigQuery for:
    • LLM-enriched / categorized data. marts.worker_shifts__cancel_categories has 30+ LLM-flagged cancel categories (health_flag, pay_errors_flag, transportation_issue_flag, childcare_flag, etc.) that don't exist in Postgres.
    • Modeled rollups. marts.placements (worker × company placements), metrics.monthly__worker_ltv, metrics.placements_by_day__churn. Pre-joined and pre-aggregated; cheaper to read than rolling them yourself.
    • App-event timeline. Anything in worker_app.* is a Segment event with timestamp, user_id, properties JSON. Use to reconstruct what a worker did in the app on a specific day.
    • Full conversation bodies. Postgres only has ticket metadata; intercom.conversation_part_history and freshdesk.conversation have the actual message text.
    • Historical / time-series queries. BQ is partitioned by day on most fact tables and is faster than Postgres for any "by day / week / month over the last N months" question.
    • Cross-source joins. Salesforce + Postgres + Segment + Intercom all live in BQ; joining across them is a single query there vs three exports.
  • Either works for: simple lookups by ID. Default to Postgres because it's faster and lower-latency.

Schema discovery in BigQuery

bq ls --project_id traba-app <dataset>                        # list tables
bq show --schema traba-app:<dataset>.<table>                  # JSON schema
bq show --format prettyjson traba-app:<dataset>.<table>       # full table info incl. partitioning

Common BQ-specific gotchas

  • Project ID required. Always pass --project_id=traba-app (or wherever the dataset lives) even when the SQL fully qualifies tables.
  • Backticks for table refs. `traba-app.marts.worker_shifts`, not double-quotes.
  • Dialect. Use --use_legacy_sql=false for standard SQL. Legacy SQL is silently the default in some configurations and will surprise you on syntax (#standardSQL directive also works).
  • Casing. BQ identifiers are case-insensitive on lookup but case-sensitive in DDL. Marts tend to be snake_case; raw Postgres replicas under src_pg preserve camelCase.
  • Cost. BQ charges per byte scanned. Use --dry_run to estimate, and prefer partitioned tables with _PARTITIONTIME filters or explicit date columns.
  • Permissions. Some datasets (e.g., scores, dialpad) require additional access. bq ls will return "Access Denied: Dataset" if you don't have it; ask before assuming a dataset is missing.

Output formatting

  • --format=pretty for human-readable ASCII tables (default for ad-hoc queries).
  • --format=csv or --format=json for machine-readable.
  • Add --max_rows=N for large result sets (default 100).

Query Guidelines (both backends)

  • Always use LIMIT (default 20, max 100 unless the user asks for more).
  • For exploratory work, start narrow (specific worker/company) before broadening — BQ scans cost real money.
  • For spatial queries in Postgres, columns use PostGIS types (geography, geometry).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment