qql-cli 0.4.2

Command-line interface, REPL, converter, and migration tools for QQL
# `qql migrate` quickstart

Copy a collection as **schema + points** (not a Qdrant snapshot). The target can
be another cluster, another minor version, another shard count, or a quantized
schema.

## 1. Install

```bash
cargo install qql-cli --locked
# ... or from a local checkout:
# cargo build --release -p qql-cli
# binary: ~/.cargo/bin/qql (or target/release/qql for checkouts)
```

Use gRPC (`:6334` / `grpc://`) for the ingest path. REST (`:6333`) works too.

## 2. Inspect the plan (no writes)

```bash
qql --url grpc://localhost:6334 \
  migrate geosmart_berlin_stays --to geosmart_copy --dry-run
```

You should see `CREATE COLLECTION`, `CREATE INDEX` (payload indexes first), and
the `ALTER COLLECTION` that restores `indexing_threshold` after bulk load.

## 3. Run

Same cluster, new collection:

```bash
qql --url grpc://localhost:6334 \
  migrate geosmart_berlin_stays --to geosmart_copy --recreate
```

Cross cluster:

```bash
qql --url grpc://old-host:6334 \
  migrate docs \
  --target-url grpc://new-host:6334 \
  --to docs \
  --target-api-key "$QDRANT_TARGET_API_KEY"
```

## 4. Confirm

The command prints `written` / `source_count` / `verified`. Default verify is
exact `COUNT … WITH (exact = true)`.

Crash recovery: a checkpoint is written under `.qql-migrate/` (file name carries
both URLs plus a hash). Re-run the same command to resume; `--restart` starts
over. Tuning flags may change across a resume. Schema flags must not.

## Flags you will actually use

| Flag | Why |
|---|---|
| `--dry-run` | Print CREATE/INDEX/ALTER only |
| `--recreate` | DROP target first |
| `--workers 4` `--batch-size 128` | Parallel upsert window |
| `--quantize scalar` | Inject quantization on CREATE |
| `--where "neighbourhood_group = 'Mitte'"` | Filtered copy |
| `--cutover docs` | Point alias `docs` at the new collection |
| `--on-missing-shard-key skip` | Skip points missing the shard field (`error` aborts) |
| `--no-wait` | Faster ingest; verify polls up to 2s until counts match |
| `--batch-delay-ms 50` | Pause between ingest windows for a loaded cluster |
| `--bulk-threshold-kb` | Cap unindexed RAM during bulk load (default 2 000 000) |

`--shard-key` / `--shard-key-field` need **Qdrant distributed mode**. Standalone
nodes reject `CREATE SHARD KEY`; migrate fails in the schema phase instead of
hanging.