spindb 0.35.4 → 0.36.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -9
- package/cli/commands/engines.ts +89 -435
- package/cli/commands/menu/backup-handlers.ts +5 -0
- package/cli/commands/menu/settings-handlers.ts +3 -0
- package/cli/commands/menu/shell-handlers.ts +40 -0
- package/cli/constants.ts +4 -0
- package/cli/helpers.ts +74 -0
- package/config/backup-formats.ts +14 -0
- package/config/engine-defaults.ts +13 -0
- package/config/engines.json +17 -0
- package/core/config-manager.ts +10 -0
- package/core/credential-manager.ts +2 -0
- package/core/dependency-manager.ts +2 -0
- package/core/docker-exporter.ts +7 -0
- package/core/library-env.ts +120 -0
- package/engines/index.ts +5 -0
- package/engines/mariadb/index.ts +45 -14
- package/engines/redis/index.ts +39 -0
- package/engines/valkey/index.ts +40 -0
- package/engines/weaviate/README.md +302 -0
- package/engines/weaviate/api-client.ts +61 -0
- package/engines/weaviate/backup.ts +145 -0
- package/engines/weaviate/binary-manager.ts +80 -0
- package/engines/weaviate/binary-urls.ts +115 -0
- package/engines/weaviate/cli-utils.ts +43 -0
- package/engines/weaviate/hostdb-releases.ts +23 -0
- package/engines/weaviate/index.ts +1139 -0
- package/engines/weaviate/restore.ts +235 -0
- package/engines/weaviate/version-maps.ts +78 -0
- package/engines/weaviate/version-validator.ts +128 -0
- package/package.json +2 -1
- package/types/index.ts +9 -0
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
**One CLI for all your local databases.**
|
|
9
9
|
|
|
10
|
-
SpinDB is a universal database management tool that combines a package manager, a unified API, and native client tooling for
|
|
10
|
+
SpinDB is a universal database management tool that combines a package manager, a unified API, and native client tooling for 19 different database engines—all from a single command-line interface. No Docker, no VMs, no platform-specific installers. Just databases, running natively on your machine.
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
13
|
npm install -g spindb
|
|
@@ -28,7 +28,7 @@ spindb create cache --engine redis
|
|
|
28
28
|
|
|
29
29
|
## Supported Engines & Platforms
|
|
30
30
|
|
|
31
|
-
SpinDB supports **
|
|
31
|
+
SpinDB supports **19 database engines** across **5 platform architectures**—all with a consistent API.
|
|
32
32
|
|
|
33
33
|
| Engine | Type | macOS ARM | macOS Intel | Linux x64 | Linux ARM | Windows |
|
|
34
34
|
|--------|------|:---------:|:-----------:|:---------:|:---------:|:-------:|
|
|
@@ -50,8 +50,9 @@ SpinDB supports **18 database engines** across **5 platform architectures**—al
|
|
|
50
50
|
| ⏱️ **QuestDB** | Time-Series | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
51
51
|
| 🤖 **TypeDB** | Knowledge Graph | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
52
52
|
| 📈 **InfluxDB** | Time-Series | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
53
|
+
| 🔮 **Weaviate** | Vector Database | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
53
54
|
|
|
54
|
-
**
|
|
55
|
+
**95 combinations. One CLI. Zero configuration.**
|
|
55
56
|
|
|
56
57
|
> ClickHouse is available on Windows via WSL. FerretDB v1 is natively supported on Windows (uses plain PostgreSQL backend); v2 requires macOS/Linux.
|
|
57
58
|
|
|
@@ -117,6 +118,16 @@ spindb connect tsdata # Interactive SQL console
|
|
|
117
118
|
|
|
118
119
|
> InfluxDB supports two file formats: `.lp` (line protocol) for writing data, `.sql` for queries.
|
|
119
120
|
|
|
121
|
+
### Weaviate
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
spindb create vectors --engine weaviate --start
|
|
125
|
+
spindb query vectors "GET /v1/schema" # Query via REST API
|
|
126
|
+
spindb connect vectors # Open web dashboard
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
> Weaviate is an AI-native vector database. REST API on default port 8080, gRPC on port+1. Uses classes/collections.
|
|
130
|
+
|
|
120
131
|
### Enhanced Shells & Visual Tools
|
|
121
132
|
|
|
122
133
|
```bash
|
|
@@ -129,7 +140,7 @@ spindb connect mydb --ui # Built-in Web UI (DuckDB)
|
|
|
129
140
|
### Any Engine
|
|
130
141
|
|
|
131
142
|
```bash
|
|
132
|
-
spindb create mydb --engine [postgresql|mysql|mariadb|mongodb|ferretdb|redis|valkey|clickhouse|sqlite|duckdb|qdrant|meilisearch|couchdb|cockroachdb|surrealdb|questdb|typedb|influxdb]
|
|
143
|
+
spindb create mydb --engine [postgresql|mysql|mariadb|mongodb|ferretdb|redis|valkey|clickhouse|sqlite|duckdb|qdrant|meilisearch|couchdb|cockroachdb|surrealdb|questdb|typedb|influxdb|weaviate]
|
|
133
144
|
spindb start mydb
|
|
134
145
|
spindb connect mydb
|
|
135
146
|
spindb backup mydb
|
|
@@ -171,7 +182,7 @@ SpinDB runs databases as **native processes** with **isolated data directories**
|
|
|
171
182
|
|
|
172
183
|
| Feature | SpinDB | DBngin | Postgres.app | Laragon |
|
|
173
184
|
|---------|--------|--------|--------------|---------|
|
|
174
|
-
| **Engines supported** |
|
|
185
|
+
| **Engines supported** | 19 | 3 (PG/MySQL/Redis) | 1 (PostgreSQL) | 4 (PG/MySQL/MariaDB/MongoDB) |
|
|
175
186
|
| CLI-first | ✅ | ❌ GUI-only | ❌ GUI-only | ⚠️ Limited CLI |
|
|
176
187
|
| Multi-version support | ✅ | ✅ | ✅ | ✅ |
|
|
177
188
|
| Built-in backup/restore | ✅ | ✅ | ❌ | ⚠️ Manual |
|
|
@@ -187,7 +198,7 @@ SpinDB runs databases as **native processes** with **isolated data directories**
|
|
|
187
198
|
|
|
188
199
|
| Feature | SpinDB | Docker Desktop | Podman | OrbStack |
|
|
189
200
|
|---------|--------|----------------|--------|----------|
|
|
190
|
-
| **Engines supported** |
|
|
201
|
+
| **Engines supported** | 19 unified | Any (manual setup) | Any (manual setup) | Any (manual setup) |
|
|
191
202
|
| Daemon required | ❌ | ✅ | ❌ (rootless) | ✅ |
|
|
192
203
|
| Resource overhead | Native | VM + containers | VM + containers | VM + containers |
|
|
193
204
|
| Built-in backup/restore | ✅ | ❌ Manual | ❌ Manual | ❌ Manual |
|
|
@@ -203,7 +214,7 @@ SpinDB runs databases as **native processes** with **isolated data directories**
|
|
|
203
214
|
|
|
204
215
|
| Feature | SpinDB | Homebrew | apt/winget | asdf-vm |
|
|
205
216
|
|---------|--------|----------|------------|---------|
|
|
206
|
-
| **Engines supported** |
|
|
217
|
+
| **Engines supported** | 19 unified | Many (separate formulas) | Many (separate packages) | Many (plugins) |
|
|
207
218
|
| Multi-version side-by-side | ✅ | ⚠️ Complex | ❌ | ✅ |
|
|
208
219
|
| Isolated data directories | ✅ | ❌ System-wide | ❌ System-wide | ❌ |
|
|
209
220
|
| Built-in backup/restore | ✅ | ❌ | ❌ | ❌ |
|
|
@@ -273,7 +284,7 @@ See [DEPLOY.md](DEPLOY.md) for comprehensive deployment documentation.
|
|
|
273
284
|
- **Local only** - Databases bind to `127.0.0.1`. Remote connection support planned for v1.1.
|
|
274
285
|
- **ClickHouse Windows** - Not supported (hostdb doesn't build for Windows).
|
|
275
286
|
- **FerretDB Windows** - v1 supported natively (plain PostgreSQL backend). v2 not supported (postgresql-documentdb has startup issues); use WSL for v2.
|
|
276
|
-
- **Qdrant, Meilisearch, CouchDB** - Use REST API instead of CLI shell. Access via HTTP at the configured port.
|
|
287
|
+
- **Qdrant, Meilisearch, CouchDB, Weaviate** - Use REST API instead of CLI shell. Access via HTTP at the configured port.
|
|
277
288
|
|
|
278
289
|
---
|
|
279
290
|
|
|
@@ -394,7 +405,7 @@ See [ENGINE_CHECKLIST.md](ENGINE_CHECKLIST.md) for adding new database engines.
|
|
|
394
405
|
|
|
395
406
|
SpinDB is powered by:
|
|
396
407
|
|
|
397
|
-
- **[hostdb](https://github.com/robertjbass/hostdb)** - Pre-compiled database binaries for
|
|
408
|
+
- **[hostdb](https://github.com/robertjbass/hostdb)** - Pre-compiled database binaries for 19 engines across all major platforms. Makes Docker-free multi-version database support possible.
|
|
398
409
|
|
|
399
410
|
---
|
|
400
411
|
|
package/cli/commands/engines.ts
CHANGED
|
@@ -30,26 +30,7 @@ import { promptConfirm } from '../ui/prompts'
|
|
|
30
30
|
import { createSpinner } from '../ui/spinner'
|
|
31
31
|
import { uiError, uiWarning, uiInfo, uiSuccess, formatBytes } from '../ui/theme'
|
|
32
32
|
import { getEngineIcon } from '../constants'
|
|
33
|
-
import {
|
|
34
|
-
getInstalledEngines,
|
|
35
|
-
getInstalledPostgresEngines,
|
|
36
|
-
type InstalledPostgresEngine,
|
|
37
|
-
type InstalledMysqlEngine,
|
|
38
|
-
type InstalledSqliteEngine,
|
|
39
|
-
type InstalledDuckDBEngine,
|
|
40
|
-
type InstalledMongodbEngine,
|
|
41
|
-
type InstalledFerretDBEngine,
|
|
42
|
-
type InstalledRedisEngine,
|
|
43
|
-
type InstalledValkeyEngine,
|
|
44
|
-
type InstalledQdrantEngine,
|
|
45
|
-
type InstalledMeilisearchEngine,
|
|
46
|
-
type InstalledCouchDBEngine,
|
|
47
|
-
type InstalledCockroachDBEngine,
|
|
48
|
-
type InstalledSurrealDBEngine,
|
|
49
|
-
type InstalledQuestDBEngine,
|
|
50
|
-
type InstalledTypeDBEngine,
|
|
51
|
-
type InstalledInfluxDBEngine,
|
|
52
|
-
} from '../helpers'
|
|
33
|
+
import { getInstalledEngines, getInstalledPostgresEngines } from '../helpers'
|
|
53
34
|
import { Engine, Platform } from '../../types'
|
|
54
35
|
import {
|
|
55
36
|
loadEnginesJson,
|
|
@@ -73,6 +54,7 @@ import { surrealdbBinaryManager } from '../../engines/surrealdb/binary-manager'
|
|
|
73
54
|
import { questdbBinaryManager } from '../../engines/questdb/binary-manager'
|
|
74
55
|
import { typedbBinaryManager } from '../../engines/typedb/binary-manager'
|
|
75
56
|
import { influxdbBinaryManager } from '../../engines/influxdb/binary-manager'
|
|
57
|
+
import { weaviateBinaryManager } from '../../engines/weaviate/binary-manager'
|
|
76
58
|
import {
|
|
77
59
|
DEFAULT_DOCUMENTDB_VERSION,
|
|
78
60
|
DEFAULT_V1_POSTGRESQL_VERSION,
|
|
@@ -434,59 +416,11 @@ async function listEngines(options: { json?: boolean }): Promise<void> {
|
|
|
434
416
|
return
|
|
435
417
|
}
|
|
436
418
|
|
|
437
|
-
//
|
|
438
|
-
const
|
|
439
|
-
(
|
|
440
|
-
)
|
|
441
|
-
const mysqlEngines = engines.filter(
|
|
442
|
-
(e): e is InstalledMysqlEngine => e.engine === 'mysql',
|
|
443
|
-
)
|
|
444
|
-
const sqliteEngine = engines.find(
|
|
445
|
-
(e): e is InstalledSqliteEngine => e.engine === 'sqlite',
|
|
446
|
-
)
|
|
447
|
-
const duckdbEngines = engines.filter(
|
|
448
|
-
(e): e is InstalledDuckDBEngine => e.engine === 'duckdb',
|
|
449
|
-
)
|
|
450
|
-
const mongodbEngines = engines.filter(
|
|
451
|
-
(e): e is InstalledMongodbEngine => e.engine === 'mongodb',
|
|
452
|
-
)
|
|
453
|
-
const ferretdbEngines = engines.filter(
|
|
454
|
-
(e): e is InstalledFerretDBEngine => e.engine === 'ferretdb',
|
|
455
|
-
)
|
|
456
|
-
const redisEngines = engines.filter(
|
|
457
|
-
(e): e is InstalledRedisEngine => e.engine === 'redis',
|
|
458
|
-
)
|
|
459
|
-
const valkeyEngines = engines.filter(
|
|
460
|
-
(e): e is InstalledValkeyEngine => e.engine === 'valkey',
|
|
461
|
-
)
|
|
462
|
-
const qdrantEngines = engines.filter(
|
|
463
|
-
(e): e is InstalledQdrantEngine => e.engine === 'qdrant',
|
|
464
|
-
)
|
|
465
|
-
const meilisearchEngines = engines.filter(
|
|
466
|
-
(e): e is InstalledMeilisearchEngine => e.engine === 'meilisearch',
|
|
467
|
-
)
|
|
468
|
-
const couchdbEngines = engines.filter(
|
|
469
|
-
(e): e is InstalledCouchDBEngine => e.engine === 'couchdb',
|
|
470
|
-
)
|
|
471
|
-
const cockroachdbEngines = engines.filter(
|
|
472
|
-
(e): e is InstalledCockroachDBEngine => e.engine === 'cockroachdb',
|
|
473
|
-
)
|
|
474
|
-
const surrealdbEngines = engines.filter(
|
|
475
|
-
(e): e is InstalledSurrealDBEngine => e.engine === 'surrealdb',
|
|
476
|
-
)
|
|
477
|
-
const questdbEngines = engines.filter(
|
|
478
|
-
(e): e is InstalledQuestDBEngine => e.engine === 'questdb',
|
|
479
|
-
)
|
|
480
|
-
const typedbEngines = engines.filter(
|
|
481
|
-
(e): e is InstalledTypeDBEngine => e.engine === 'typedb',
|
|
482
|
-
)
|
|
483
|
-
const influxdbEngines = engines.filter(
|
|
484
|
-
(e): e is InstalledInfluxDBEngine => e.engine === 'influxdb',
|
|
419
|
+
// Sort engines alphabetically by engine name
|
|
420
|
+
const sortedEngines = [...engines].sort((a, b) =>
|
|
421
|
+
a.engine.localeCompare(b.engine),
|
|
485
422
|
)
|
|
486
423
|
|
|
487
|
-
// Calculate total size for PostgreSQL
|
|
488
|
-
const totalPgSize = pgEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
|
|
489
|
-
|
|
490
424
|
// Table header
|
|
491
425
|
// Icon is 5 chars, longest engine name is 11 (meilisearch/cockroachdb), so 18 total for ENGINE column
|
|
492
426
|
console.log()
|
|
@@ -499,8 +433,8 @@ async function listEngines(options: { json?: boolean }): Promise<void> {
|
|
|
499
433
|
)
|
|
500
434
|
console.log(chalk.gray(' ' + '─'.repeat(59)))
|
|
501
435
|
|
|
502
|
-
//
|
|
503
|
-
for (const engine of
|
|
436
|
+
// Display all engines in alphabetical order
|
|
437
|
+
for (const engine of sortedEngines) {
|
|
504
438
|
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
505
439
|
|
|
506
440
|
console.log(
|
|
@@ -513,375 +447,48 @@ async function listEngines(options: { json?: boolean }): Promise<void> {
|
|
|
513
447
|
)
|
|
514
448
|
}
|
|
515
449
|
|
|
516
|
-
|
|
517
|
-
for (const mysqlEngine of mysqlEngines) {
|
|
518
|
-
const platformInfo = `${mysqlEngine.platform}-${mysqlEngine.arch}`
|
|
519
|
-
|
|
520
|
-
console.log(
|
|
521
|
-
chalk.gray(' ') +
|
|
522
|
-
getEngineIcon('mysql') +
|
|
523
|
-
chalk.cyan('mysql'.padEnd(13)) +
|
|
524
|
-
chalk.yellow(mysqlEngine.version.padEnd(12)) +
|
|
525
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
526
|
-
chalk.white(formatBytes(mysqlEngine.sizeBytes)),
|
|
527
|
-
)
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// SQLite row
|
|
531
|
-
if (sqliteEngine) {
|
|
532
|
-
console.log(
|
|
533
|
-
chalk.gray(' ') +
|
|
534
|
-
getEngineIcon('sqlite') +
|
|
535
|
-
chalk.cyan('sqlite'.padEnd(13)) +
|
|
536
|
-
chalk.yellow(sqliteEngine.version.padEnd(12)) +
|
|
537
|
-
chalk.gray('system'.padEnd(18)) +
|
|
538
|
-
chalk.gray('(system-installed)'),
|
|
539
|
-
)
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// DuckDB rows
|
|
543
|
-
for (const engine of duckdbEngines) {
|
|
544
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
545
|
-
|
|
546
|
-
console.log(
|
|
547
|
-
chalk.gray(' ') +
|
|
548
|
-
getEngineIcon('duckdb') +
|
|
549
|
-
chalk.cyan('duckdb'.padEnd(13)) +
|
|
550
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
551
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
552
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
553
|
-
)
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// MongoDB rows
|
|
557
|
-
for (const engine of mongodbEngines) {
|
|
558
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
559
|
-
|
|
560
|
-
console.log(
|
|
561
|
-
chalk.gray(' ') +
|
|
562
|
-
getEngineIcon('mongodb') +
|
|
563
|
-
chalk.cyan('mongodb'.padEnd(13)) +
|
|
564
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
565
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
566
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
567
|
-
)
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// FerretDB rows
|
|
571
|
-
for (const engine of ferretdbEngines) {
|
|
572
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
573
|
-
|
|
574
|
-
console.log(
|
|
575
|
-
chalk.gray(' ') +
|
|
576
|
-
getEngineIcon('ferretdb') +
|
|
577
|
-
chalk.cyan('ferretdb'.padEnd(13)) +
|
|
578
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
579
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
580
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
581
|
-
)
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// Redis rows
|
|
585
|
-
for (const engine of redisEngines) {
|
|
586
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
587
|
-
|
|
588
|
-
console.log(
|
|
589
|
-
chalk.gray(' ') +
|
|
590
|
-
getEngineIcon('redis') +
|
|
591
|
-
chalk.cyan('redis'.padEnd(13)) +
|
|
592
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
593
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
594
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
595
|
-
)
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
// Valkey rows
|
|
599
|
-
for (const engine of valkeyEngines) {
|
|
600
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
601
|
-
|
|
602
|
-
console.log(
|
|
603
|
-
chalk.gray(' ') +
|
|
604
|
-
getEngineIcon('valkey') +
|
|
605
|
-
chalk.cyan('valkey'.padEnd(13)) +
|
|
606
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
607
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
608
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
609
|
-
)
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// Qdrant rows
|
|
613
|
-
for (const engine of qdrantEngines) {
|
|
614
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
615
|
-
|
|
616
|
-
console.log(
|
|
617
|
-
chalk.gray(' ') +
|
|
618
|
-
getEngineIcon('qdrant') +
|
|
619
|
-
chalk.cyan('qdrant'.padEnd(13)) +
|
|
620
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
621
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
622
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
623
|
-
)
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// Meilisearch rows
|
|
627
|
-
for (const engine of meilisearchEngines) {
|
|
628
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
629
|
-
|
|
630
|
-
console.log(
|
|
631
|
-
chalk.gray(' ') +
|
|
632
|
-
getEngineIcon('meilisearch') +
|
|
633
|
-
chalk.cyan('meilisearch'.padEnd(13)) +
|
|
634
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
635
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
636
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
637
|
-
)
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
// CouchDB rows
|
|
641
|
-
for (const engine of couchdbEngines) {
|
|
642
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
643
|
-
|
|
644
|
-
console.log(
|
|
645
|
-
chalk.gray(' ') +
|
|
646
|
-
getEngineIcon('couchdb') +
|
|
647
|
-
chalk.cyan('couchdb'.padEnd(13)) +
|
|
648
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
649
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
650
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
651
|
-
)
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
// CockroachDB rows
|
|
655
|
-
for (const engine of cockroachdbEngines) {
|
|
656
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
657
|
-
|
|
658
|
-
console.log(
|
|
659
|
-
chalk.gray(' ') +
|
|
660
|
-
getEngineIcon('cockroachdb') +
|
|
661
|
-
chalk.cyan('cockroachdb'.padEnd(13)) +
|
|
662
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
663
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
664
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
665
|
-
)
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
// SurrealDB rows
|
|
669
|
-
for (const engine of surrealdbEngines) {
|
|
670
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
671
|
-
|
|
672
|
-
console.log(
|
|
673
|
-
chalk.gray(' ') +
|
|
674
|
-
getEngineIcon('surrealdb') +
|
|
675
|
-
chalk.cyan('surrealdb'.padEnd(13)) +
|
|
676
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
677
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
678
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
679
|
-
)
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
// QuestDB rows
|
|
683
|
-
for (const engine of questdbEngines) {
|
|
684
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
685
|
-
|
|
686
|
-
console.log(
|
|
687
|
-
chalk.gray(' ') +
|
|
688
|
-
getEngineIcon('questdb') +
|
|
689
|
-
chalk.cyan('questdb'.padEnd(13)) +
|
|
690
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
691
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
692
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
693
|
-
)
|
|
694
|
-
}
|
|
450
|
+
console.log(chalk.gray(' ' + '─'.repeat(59)))
|
|
695
451
|
|
|
696
|
-
//
|
|
697
|
-
|
|
698
|
-
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
452
|
+
// Summary - group by engine name (already sorted)
|
|
453
|
+
console.log()
|
|
699
454
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
455
|
+
// Engine display name map for summary
|
|
456
|
+
const ENGINE_DISPLAY_NAMES: Record<string, string> = {
|
|
457
|
+
clickhouse: 'ClickHouse',
|
|
458
|
+
cockroachdb: 'CockroachDB',
|
|
459
|
+
couchdb: 'CouchDB',
|
|
460
|
+
duckdb: 'DuckDB',
|
|
461
|
+
ferretdb: 'FerretDB',
|
|
462
|
+
influxdb: 'InfluxDB',
|
|
463
|
+
mariadb: 'MariaDB',
|
|
464
|
+
meilisearch: 'Meilisearch',
|
|
465
|
+
mongodb: 'MongoDB',
|
|
466
|
+
mysql: 'MySQL',
|
|
467
|
+
postgresql: 'PostgreSQL',
|
|
468
|
+
qdrant: 'Qdrant',
|
|
469
|
+
questdb: 'QuestDB',
|
|
470
|
+
redis: 'Redis',
|
|
471
|
+
sqlite: 'SQLite',
|
|
472
|
+
surrealdb: 'SurrealDB',
|
|
473
|
+
typedb: 'TypeDB',
|
|
474
|
+
valkey: 'Valkey',
|
|
475
|
+
weaviate: 'Weaviate',
|
|
708
476
|
}
|
|
709
477
|
|
|
710
|
-
//
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
getEngineIcon('influxdb') +
|
|
717
|
-
chalk.cyan('influxdb'.padEnd(13)) +
|
|
718
|
-
chalk.yellow(engine.version.padEnd(12)) +
|
|
719
|
-
chalk.gray(platformInfo.padEnd(18)) +
|
|
720
|
-
chalk.white(formatBytes(engine.sizeBytes)),
|
|
721
|
-
)
|
|
478
|
+
// Group engines by name for summary
|
|
479
|
+
const engineGroups = new Map<string, typeof sortedEngines>()
|
|
480
|
+
for (const engine of sortedEngines) {
|
|
481
|
+
const group = engineGroups.get(engine.engine) || []
|
|
482
|
+
group.push(engine)
|
|
483
|
+
engineGroups.set(engine.engine, group)
|
|
722
484
|
}
|
|
723
485
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
console.log()
|
|
728
|
-
if (pgEngines.length > 0) {
|
|
729
|
-
console.log(
|
|
730
|
-
chalk.gray(
|
|
731
|
-
` PostgreSQL: ${pgEngines.length} version(s), ${formatBytes(totalPgSize)}`,
|
|
732
|
-
),
|
|
733
|
-
)
|
|
734
|
-
}
|
|
735
|
-
if (mysqlEngines.length > 0) {
|
|
736
|
-
const totalMysqlSize = mysqlEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
|
|
737
|
-
console.log(
|
|
738
|
-
chalk.gray(
|
|
739
|
-
` MySQL: ${mysqlEngines.length} version(s), ${formatBytes(totalMysqlSize)}`,
|
|
740
|
-
),
|
|
741
|
-
)
|
|
742
|
-
}
|
|
743
|
-
if (sqliteEngine) {
|
|
744
|
-
console.log(
|
|
745
|
-
chalk.gray(` SQLite: system-installed at ${sqliteEngine.path}`),
|
|
746
|
-
)
|
|
747
|
-
}
|
|
748
|
-
if (duckdbEngines.length > 0) {
|
|
749
|
-
const totalDuckdbSize = duckdbEngines.reduce(
|
|
750
|
-
(acc, e) => acc + e.sizeBytes,
|
|
751
|
-
0,
|
|
752
|
-
)
|
|
753
|
-
console.log(
|
|
754
|
-
chalk.gray(
|
|
755
|
-
` DuckDB: ${duckdbEngines.length} version(s), ${formatBytes(totalDuckdbSize)}`,
|
|
756
|
-
),
|
|
757
|
-
)
|
|
758
|
-
}
|
|
759
|
-
if (mongodbEngines.length > 0) {
|
|
760
|
-
const totalMongodbSize = mongodbEngines.reduce(
|
|
761
|
-
(acc, e) => acc + e.sizeBytes,
|
|
762
|
-
0,
|
|
763
|
-
)
|
|
764
|
-
console.log(
|
|
765
|
-
chalk.gray(
|
|
766
|
-
` MongoDB: ${mongodbEngines.length} version(s), ${formatBytes(totalMongodbSize)}`,
|
|
767
|
-
),
|
|
768
|
-
)
|
|
769
|
-
}
|
|
770
|
-
if (ferretdbEngines.length > 0) {
|
|
771
|
-
const totalFerretdbSize = ferretdbEngines.reduce(
|
|
772
|
-
(acc, e) => acc + e.sizeBytes,
|
|
773
|
-
0,
|
|
774
|
-
)
|
|
775
|
-
console.log(
|
|
776
|
-
chalk.gray(
|
|
777
|
-
` FerretDB: ${ferretdbEngines.length} version(s), ${formatBytes(totalFerretdbSize)}`,
|
|
778
|
-
),
|
|
779
|
-
)
|
|
780
|
-
}
|
|
781
|
-
if (redisEngines.length > 0) {
|
|
782
|
-
const totalRedisSize = redisEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
|
|
783
|
-
console.log(
|
|
784
|
-
chalk.gray(
|
|
785
|
-
` Redis: ${redisEngines.length} version(s), ${formatBytes(totalRedisSize)}`,
|
|
786
|
-
),
|
|
787
|
-
)
|
|
788
|
-
}
|
|
789
|
-
if (valkeyEngines.length > 0) {
|
|
790
|
-
const totalValkeySize = valkeyEngines.reduce(
|
|
791
|
-
(acc, e) => acc + e.sizeBytes,
|
|
792
|
-
0,
|
|
793
|
-
)
|
|
794
|
-
console.log(
|
|
795
|
-
chalk.gray(
|
|
796
|
-
` Valkey: ${valkeyEngines.length} version(s), ${formatBytes(totalValkeySize)}`,
|
|
797
|
-
),
|
|
798
|
-
)
|
|
799
|
-
}
|
|
800
|
-
if (qdrantEngines.length > 0) {
|
|
801
|
-
const totalQdrantSize = qdrantEngines.reduce(
|
|
802
|
-
(acc, e) => acc + e.sizeBytes,
|
|
803
|
-
0,
|
|
804
|
-
)
|
|
805
|
-
console.log(
|
|
806
|
-
chalk.gray(
|
|
807
|
-
` Qdrant: ${qdrantEngines.length} version(s), ${formatBytes(totalQdrantSize)}`,
|
|
808
|
-
),
|
|
809
|
-
)
|
|
810
|
-
}
|
|
811
|
-
if (meilisearchEngines.length > 0) {
|
|
812
|
-
const totalMeilisearchSize = meilisearchEngines.reduce(
|
|
813
|
-
(acc, e) => acc + e.sizeBytes,
|
|
814
|
-
0,
|
|
815
|
-
)
|
|
486
|
+
for (const [engineName, group] of engineGroups) {
|
|
487
|
+
const displayName = ENGINE_DISPLAY_NAMES[engineName] || engineName
|
|
488
|
+
const totalSize = group.reduce((acc, e) => acc + e.sizeBytes, 0)
|
|
816
489
|
console.log(
|
|
817
490
|
chalk.gray(
|
|
818
|
-
`
|
|
819
|
-
),
|
|
820
|
-
)
|
|
821
|
-
}
|
|
822
|
-
if (couchdbEngines.length > 0) {
|
|
823
|
-
const totalCouchDBSize = couchdbEngines.reduce(
|
|
824
|
-
(acc, e) => acc + e.sizeBytes,
|
|
825
|
-
0,
|
|
826
|
-
)
|
|
827
|
-
console.log(
|
|
828
|
-
chalk.gray(
|
|
829
|
-
` CouchDB: ${couchdbEngines.length} version(s), ${formatBytes(totalCouchDBSize)}`,
|
|
830
|
-
),
|
|
831
|
-
)
|
|
832
|
-
}
|
|
833
|
-
if (cockroachdbEngines.length > 0) {
|
|
834
|
-
const totalCockroachDBSize = cockroachdbEngines.reduce(
|
|
835
|
-
(acc, e) => acc + e.sizeBytes,
|
|
836
|
-
0,
|
|
837
|
-
)
|
|
838
|
-
console.log(
|
|
839
|
-
chalk.gray(
|
|
840
|
-
` CockroachDB: ${cockroachdbEngines.length} version(s), ${formatBytes(totalCockroachDBSize)}`,
|
|
841
|
-
),
|
|
842
|
-
)
|
|
843
|
-
}
|
|
844
|
-
if (surrealdbEngines.length > 0) {
|
|
845
|
-
const totalSurrealDBSize = surrealdbEngines.reduce(
|
|
846
|
-
(acc, e) => acc + e.sizeBytes,
|
|
847
|
-
0,
|
|
848
|
-
)
|
|
849
|
-
console.log(
|
|
850
|
-
chalk.gray(
|
|
851
|
-
` SurrealDB: ${surrealdbEngines.length} version(s), ${formatBytes(totalSurrealDBSize)}`,
|
|
852
|
-
),
|
|
853
|
-
)
|
|
854
|
-
}
|
|
855
|
-
if (questdbEngines.length > 0) {
|
|
856
|
-
const totalQuestDBSize = questdbEngines.reduce(
|
|
857
|
-
(acc, e) => acc + e.sizeBytes,
|
|
858
|
-
0,
|
|
859
|
-
)
|
|
860
|
-
console.log(
|
|
861
|
-
chalk.gray(
|
|
862
|
-
` QuestDB: ${questdbEngines.length} version(s), ${formatBytes(totalQuestDBSize)}`,
|
|
863
|
-
),
|
|
864
|
-
)
|
|
865
|
-
}
|
|
866
|
-
if (typedbEngines.length > 0) {
|
|
867
|
-
const totalTypeDBSize = typedbEngines.reduce(
|
|
868
|
-
(acc, e) => acc + e.sizeBytes,
|
|
869
|
-
0,
|
|
870
|
-
)
|
|
871
|
-
console.log(
|
|
872
|
-
chalk.gray(
|
|
873
|
-
` TypeDB: ${typedbEngines.length} version(s), ${formatBytes(totalTypeDBSize)}`,
|
|
874
|
-
),
|
|
875
|
-
)
|
|
876
|
-
}
|
|
877
|
-
if (influxdbEngines.length > 0) {
|
|
878
|
-
const totalInfluxDBSize = influxdbEngines.reduce(
|
|
879
|
-
(acc, e) => acc + e.sizeBytes,
|
|
880
|
-
0,
|
|
881
|
-
)
|
|
882
|
-
console.log(
|
|
883
|
-
chalk.gray(
|
|
884
|
-
` InfluxDB: ${influxdbEngines.length} version(s), ${formatBytes(totalInfluxDBSize)}`,
|
|
491
|
+
` ${displayName}: ${group.length} version(s), ${formatBytes(totalSize)}`,
|
|
885
492
|
),
|
|
886
493
|
)
|
|
887
494
|
}
|
|
@@ -2121,9 +1728,56 @@ enginesCommand
|
|
|
2121
1728
|
return
|
|
2122
1729
|
}
|
|
2123
1730
|
|
|
1731
|
+
if (['weaviate', 'wv'].includes(normalizedEngine)) {
|
|
1732
|
+
if (!version) {
|
|
1733
|
+
console.error(uiError('Weaviate requires a version (e.g., 1)'))
|
|
1734
|
+
process.exit(1)
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
const engine = getEngine(Engine.Weaviate)
|
|
1738
|
+
|
|
1739
|
+
const spinner = createSpinner(
|
|
1740
|
+
`Checking Weaviate ${version} binaries...`,
|
|
1741
|
+
)
|
|
1742
|
+
spinner.start()
|
|
1743
|
+
|
|
1744
|
+
let wasCached = false
|
|
1745
|
+
await engine.ensureBinaries(version, ({ stage, message }) => {
|
|
1746
|
+
if (stage === 'cached') {
|
|
1747
|
+
wasCached = true
|
|
1748
|
+
spinner.text = `Weaviate ${version} binaries ready (cached)`
|
|
1749
|
+
} else {
|
|
1750
|
+
spinner.text = message
|
|
1751
|
+
}
|
|
1752
|
+
})
|
|
1753
|
+
|
|
1754
|
+
if (wasCached) {
|
|
1755
|
+
spinner.succeed(`Weaviate ${version} binaries already installed`)
|
|
1756
|
+
} else {
|
|
1757
|
+
spinner.succeed(`Weaviate ${version} binaries downloaded`)
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// Show the path for reference
|
|
1761
|
+
const { platform: weaviatePlatform, arch: weaviateArch } =
|
|
1762
|
+
platformService.getPlatformInfo()
|
|
1763
|
+
const weaviateFullVersion =
|
|
1764
|
+
weaviateBinaryManager.getFullVersion(version)
|
|
1765
|
+
const binPath = paths.getBinaryPath({
|
|
1766
|
+
engine: 'weaviate',
|
|
1767
|
+
version: weaviateFullVersion,
|
|
1768
|
+
platform: weaviatePlatform,
|
|
1769
|
+
arch: weaviateArch,
|
|
1770
|
+
})
|
|
1771
|
+
console.log(chalk.gray(` Location: ${binPath}`))
|
|
1772
|
+
|
|
1773
|
+
// Skip client tools check for Weaviate - it's a REST API server
|
|
1774
|
+
// with no CLI client tools (uses HTTP protocols instead)
|
|
1775
|
+
return
|
|
1776
|
+
}
|
|
1777
|
+
|
|
2124
1778
|
console.error(
|
|
2125
1779
|
uiError(
|
|
2126
|
-
`Unknown engine "${engineName}". Supported: postgresql, mysql, mariadb, sqlite, duckdb, mongodb, ferretdb, redis, valkey, clickhouse, qdrant, meilisearch, couchdb, cockroachdb, surrealdb, questdb, typedb, influxdb`,
|
|
1780
|
+
`Unknown engine "${engineName}". Supported: postgresql, mysql, mariadb, sqlite, duckdb, mongodb, ferretdb, redis, valkey, clickhouse, qdrant, meilisearch, couchdb, cockroachdb, surrealdb, questdb, typedb, influxdb, weaviate`,
|
|
2127
1781
|
),
|
|
2128
1782
|
)
|
|
2129
1783
|
process.exit(1)
|
|
@@ -223,6 +223,11 @@ function validateConnectionString(
|
|
|
223
223
|
return 'Connection string must start with influxdb://, http://, or https://'
|
|
224
224
|
}
|
|
225
225
|
break
|
|
226
|
+
case Engine.Weaviate:
|
|
227
|
+
if (!input.startsWith('http://') && !input.startsWith('https://')) {
|
|
228
|
+
return 'Connection string must start with http:// or https://'
|
|
229
|
+
}
|
|
230
|
+
break
|
|
226
231
|
case Engine.SQLite:
|
|
227
232
|
case Engine.DuckDB:
|
|
228
233
|
return 'File-based engines do not support remote connection strings'
|