spindb 0.34.3 → 0.35.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 +4 -4
- package/cli/commands/attach.ts +38 -9
- package/cli/commands/backups.ts +5 -0
- package/cli/commands/connect.ts +6 -6
- package/cli/commands/create.ts +22 -1
- package/cli/commands/detach.ts +16 -9
- package/cli/commands/doctor.ts +2 -2
- package/cli/commands/duckdb.ts +273 -0
- package/cli/commands/edit.ts +31 -21
- package/cli/commands/engines.ts +51 -21
- package/cli/commands/info.ts +26 -16
- package/cli/commands/list.ts +44 -26
- package/cli/commands/menu/container-handlers.ts +17 -1
- package/cli/commands/menu/engine-handlers.ts +48 -29
- package/cli/commands/menu/update-handlers.ts +2 -2
- package/cli/commands/sqlite.ts +21 -0
- package/cli/index.ts +2 -0
- package/cli/ui/theme.ts +5 -2
- package/config/engines.json +2 -2
- package/core/base-binary-manager.ts +6 -2
- package/core/base-document-binary-manager.ts +5 -2
- package/core/base-embedded-binary-manager.ts +5 -2
- package/core/base-server-binary-manager.ts +5 -2
- package/core/hostdb-client.ts +157 -22
- package/core/hostdb-metadata.ts +67 -43
- package/engines/clickhouse/binary-urls.ts +1 -1
- package/engines/cockroachdb/binary-urls.ts +9 -7
- package/engines/cockroachdb/hostdb-releases.ts +18 -106
- package/engines/cockroachdb/version-maps.ts +1 -1
- package/engines/couchdb/binary-urls.ts +1 -1
- package/engines/duckdb/binary-urls.ts +1 -1
- package/engines/duckdb/index.ts +4 -74
- package/engines/duckdb/scanner.ts +22 -0
- package/engines/ferretdb/README.md +76 -38
- package/engines/ferretdb/backup.ts +18 -10
- package/engines/ferretdb/binary-manager.ts +233 -35
- package/engines/ferretdb/binary-urls.ts +69 -24
- package/engines/ferretdb/index.ts +424 -213
- package/engines/ferretdb/restore.ts +23 -16
- package/engines/ferretdb/version-maps.ts +36 -8
- package/engines/file-based-utils.ts +262 -0
- package/engines/index.ts +3 -4
- package/engines/influxdb/binary-urls.ts +1 -1
- package/engines/mariadb/binary-urls.ts +2 -2
- package/engines/meilisearch/binary-urls.ts +1 -1
- package/engines/mysql/binary-urls.ts +2 -2
- package/engines/postgresql/binary-urls.ts +1 -1
- package/engines/qdrant/binary-urls.ts +1 -1
- package/engines/questdb/binary-manager.ts +16 -9
- package/engines/questdb/binary-urls.ts +9 -10
- package/engines/questdb/hostdb-releases.ts +19 -97
- package/engines/questdb/version-maps.ts +2 -2
- package/engines/redis/binary-urls.ts +1 -8
- package/engines/sqlite/binary-urls.ts +1 -1
- package/engines/sqlite/index.ts +4 -74
- package/engines/sqlite/scanner.ts +11 -88
- package/engines/surrealdb/binary-urls.ts +9 -7
- package/engines/surrealdb/hostdb-releases.ts +18 -106
- package/engines/surrealdb/version-maps.ts +1 -1
- package/engines/typedb/binary-urls.ts +10 -8
- package/engines/typedb/hostdb-releases.ts +18 -113
- package/engines/typedb/version-maps.ts +1 -1
- package/engines/valkey/binary-urls.ts +1 -1
- package/package.json +4 -1
|
@@ -1,114 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* hostdb Releases Module for CockroachDB
|
|
3
3
|
*
|
|
4
|
-
* Fetches
|
|
5
|
-
*
|
|
4
|
+
* Fetches CockroachDB binary information from the hostdb repository at
|
|
5
|
+
* https://github.com/robertjbass/hostdb
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { createHostdbReleases } from '../../core/hostdb-releases-factory'
|
|
9
9
|
import {
|
|
10
10
|
COCKROACHDB_VERSION_MAP,
|
|
11
11
|
SUPPORTED_MAJOR_VERSIONS,
|
|
12
12
|
} from './version-maps'
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}[]
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Fetch available CockroachDB versions from hostdb
|
|
33
|
-
* Returns a map of major version to available patch versions
|
|
34
|
-
*
|
|
35
|
-
* Falls back to local version maps if fetch fails
|
|
36
|
-
*/
|
|
37
|
-
export async function fetchAvailableVersions(): Promise<
|
|
38
|
-
Record<string, string[]>
|
|
39
|
-
> {
|
|
40
|
-
// Return cached versions if still valid
|
|
41
|
-
if (cachedVersions && Date.now() < cacheExpiry) {
|
|
42
|
-
return cachedVersions
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
const response = await fetch(HOSTDB_RELEASES_URL)
|
|
47
|
-
if (!response.ok) {
|
|
48
|
-
throw new Error(`HTTP ${response.status}`)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const releases = (await response.json()) as HostdbReleases
|
|
52
|
-
const cockroachdbReleases = releases.cockroachdb
|
|
53
|
-
|
|
54
|
-
if (!cockroachdbReleases?.versions) {
|
|
55
|
-
throw new Error('No CockroachDB versions found in releases.json')
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Group versions by major version (YY.MM format)
|
|
59
|
-
const versionMap: Record<string, string[]> = {}
|
|
60
|
-
|
|
61
|
-
for (const { version } of cockroachdbReleases.versions) {
|
|
62
|
-
// Extract major version (e.g., "25" from "25.4.2")
|
|
63
|
-
const majorMatch = version.match(/^(\d+)/)
|
|
64
|
-
if (!majorMatch) continue
|
|
65
|
-
|
|
66
|
-
const majorVersion = majorMatch[1]
|
|
67
|
-
if (!versionMap[majorVersion]) {
|
|
68
|
-
versionMap[majorVersion] = []
|
|
69
|
-
}
|
|
70
|
-
versionMap[majorVersion].push(version)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Sort versions within each major version (newest first)
|
|
74
|
-
for (const major of Object.keys(versionMap)) {
|
|
75
|
-
versionMap[major].sort((a, b) => {
|
|
76
|
-
const partsA = a.split('.').map(Number)
|
|
77
|
-
const partsB = b.split('.').map(Number)
|
|
78
|
-
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
|
79
|
-
const diff = (partsB[i] || 0) - (partsA[i] || 0)
|
|
80
|
-
if (diff !== 0) return diff
|
|
81
|
-
}
|
|
82
|
-
return 0
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Cache the results
|
|
87
|
-
cachedVersions = versionMap
|
|
88
|
-
cacheExpiry = Date.now() + CACHE_TTL_MS
|
|
89
|
-
|
|
90
|
-
logDebug('Fetched CockroachDB versions from hostdb', { versionMap })
|
|
91
|
-
return versionMap
|
|
92
|
-
} catch (error) {
|
|
93
|
-
logDebug(`Failed to fetch hostdb releases: ${error}`)
|
|
94
|
-
|
|
95
|
-
// Fall back to local version maps
|
|
96
|
-
const fallbackMap: Record<string, string[]> = {}
|
|
97
|
-
for (const major of SUPPORTED_MAJOR_VERSIONS) {
|
|
98
|
-
const fullVersion = COCKROACHDB_VERSION_MAP[major]
|
|
99
|
-
if (fullVersion) {
|
|
100
|
-
fallbackMap[major] = [fullVersion]
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return fallbackMap
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Clear the version cache (useful for testing)
|
|
110
|
-
*/
|
|
111
|
-
export function clearVersionCache(): void {
|
|
112
|
-
cachedVersions = null
|
|
113
|
-
cacheExpiry = 0
|
|
114
|
-
}
|
|
13
|
+
import { cockroachdbBinaryManager } from './binary-manager'
|
|
14
|
+
import { Engine } from '../../types'
|
|
15
|
+
|
|
16
|
+
const hostdbReleases = createHostdbReleases({
|
|
17
|
+
engine: Engine.CockroachDB,
|
|
18
|
+
displayName: 'CockroachDB',
|
|
19
|
+
versionMap: COCKROACHDB_VERSION_MAP,
|
|
20
|
+
supportedMajorVersions: SUPPORTED_MAJOR_VERSIONS,
|
|
21
|
+
groupingStrategy: 'single-digit',
|
|
22
|
+
listInstalled: () => cockroachdbBinaryManager.listInstalled(),
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export const fetchAvailableVersions = hostdbReleases.fetchAvailableVersions
|
|
26
|
+
export const getLatestVersion = hostdbReleases.getLatestVersion
|
|
@@ -37,7 +37,7 @@ export function getHostdbPlatform(
|
|
|
37
37
|
/**
|
|
38
38
|
* Build the download URL for CouchDB binaries from hostdb
|
|
39
39
|
*
|
|
40
|
-
* Format: https://
|
|
40
|
+
* Format: https://registry.layerbase.host/couchdb-{version}/couchdb-{version}-{platform}-{arch}.{ext}
|
|
41
41
|
*
|
|
42
42
|
* @param version - CouchDB version (e.g., '3', '3.5.1')
|
|
43
43
|
* @param platform - Platform identifier (e.g., 'darwin', 'linux', 'win32')
|
|
@@ -12,7 +12,7 @@ import { Engine, type Platform, type Arch } from '../../types'
|
|
|
12
12
|
/**
|
|
13
13
|
* Build the download URL for DuckDB binaries from hostdb
|
|
14
14
|
*
|
|
15
|
-
* Format: https://
|
|
15
|
+
* Format: https://registry.layerbase.host/duckdb-{version}/duckdb-{version}-{platform}-{arch}.{ext}
|
|
16
16
|
*
|
|
17
17
|
* @param version - DuckDB version (e.g., '1', '1.4.3')
|
|
18
18
|
* @param platform - Platform identifier (e.g., 'darwin', 'linux', 'win32')
|
package/engines/duckdb/index.ts
CHANGED
|
@@ -25,18 +25,10 @@ import { platformService } from '../../core/platform-service'
|
|
|
25
25
|
import { paths } from '../../config/paths'
|
|
26
26
|
import { duckdbBinaryManager } from './binary-manager'
|
|
27
27
|
import { getBinaryUrl } from './binary-urls'
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
DUCKDB_VERSION_MAP,
|
|
31
|
-
normalizeVersion,
|
|
32
|
-
} from './version-maps'
|
|
33
|
-
import {
|
|
34
|
-
fetchHostdbReleases,
|
|
35
|
-
getEngineReleases,
|
|
36
|
-
} from '../../core/hostdb-client'
|
|
28
|
+
import { SUPPORTED_MAJOR_VERSIONS, normalizeVersion } from './version-maps'
|
|
29
|
+
import { fetchAvailableVersions } from './hostdb-releases'
|
|
37
30
|
import { logDebug } from '../../core/error-handler'
|
|
38
31
|
import {
|
|
39
|
-
Engine,
|
|
40
32
|
type Platform,
|
|
41
33
|
type Arch,
|
|
42
34
|
type ContainerConfig,
|
|
@@ -570,7 +562,7 @@ export class DuckDBEngine extends BaseEngine {
|
|
|
570
562
|
throw new Error(
|
|
571
563
|
`File not found (404) at ${url}. ` +
|
|
572
564
|
`This version may have been removed from hostdb. ` +
|
|
573
|
-
`Try a different version or check https://
|
|
565
|
+
`Try a different version or check https://registry.layerbase.host`,
|
|
574
566
|
)
|
|
575
567
|
}
|
|
576
568
|
throw new Error(
|
|
@@ -680,69 +672,7 @@ export class DuckDBEngine extends BaseEngine {
|
|
|
680
672
|
}
|
|
681
673
|
|
|
682
674
|
async fetchAvailableVersions(): Promise<Record<string, string[]>> {
|
|
683
|
-
|
|
684
|
-
try {
|
|
685
|
-
const releases = await fetchHostdbReleases()
|
|
686
|
-
const duckdbReleases = getEngineReleases(releases, Engine.DuckDB)
|
|
687
|
-
|
|
688
|
-
if (duckdbReleases && Object.keys(duckdbReleases).length > 0) {
|
|
689
|
-
const result: Record<string, string[]> = {}
|
|
690
|
-
|
|
691
|
-
for (const major of SUPPORTED_MAJOR_VERSIONS) {
|
|
692
|
-
result[major] = []
|
|
693
|
-
|
|
694
|
-
// Find all versions matching this major version
|
|
695
|
-
for (const [, release] of Object.entries(duckdbReleases)) {
|
|
696
|
-
if (release.version.startsWith(`${major}.`)) {
|
|
697
|
-
result[major].push(release.version)
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
// Sort descending (latest first)
|
|
702
|
-
result[major].sort((a, b) => {
|
|
703
|
-
const partsA = a.split('.').map(Number)
|
|
704
|
-
const partsB = b.split('.').map(Number)
|
|
705
|
-
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
|
706
|
-
const diff = (partsB[i] || 0) - (partsA[i] || 0)
|
|
707
|
-
if (diff !== 0) return diff
|
|
708
|
-
}
|
|
709
|
-
return 0
|
|
710
|
-
})
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
return result
|
|
714
|
-
}
|
|
715
|
-
} catch (error) {
|
|
716
|
-
logDebug('Failed to fetch DuckDB versions from hostdb, checking local', {
|
|
717
|
-
error: error instanceof Error ? error.message : String(error),
|
|
718
|
-
})
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
// Offline fallback: return only locally installed versions
|
|
722
|
-
const installed = await duckdbBinaryManager.listInstalled()
|
|
723
|
-
if (installed.length > 0) {
|
|
724
|
-
const result: Record<string, string[]> = {}
|
|
725
|
-
for (const binary of installed) {
|
|
726
|
-
const major = binary.version.split('.')[0]
|
|
727
|
-
if (!result[major]) {
|
|
728
|
-
result[major] = []
|
|
729
|
-
}
|
|
730
|
-
if (!result[major].includes(binary.version)) {
|
|
731
|
-
result[major].push(binary.version)
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
return result
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
// Last resort: return hardcoded version map
|
|
738
|
-
const result: Record<string, string[]> = {}
|
|
739
|
-
for (const major of SUPPORTED_MAJOR_VERSIONS) {
|
|
740
|
-
const fullVersion = DUCKDB_VERSION_MAP[major]
|
|
741
|
-
if (fullVersion) {
|
|
742
|
-
result[major] = [fullVersion]
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
return result
|
|
675
|
+
return fetchAvailableVersions()
|
|
746
676
|
}
|
|
747
677
|
|
|
748
678
|
// Helper to get duckdb path or throw a helpful error
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DuckDB Scanner — thin wrapper around shared file-based-utils
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Engine } from '../../types'
|
|
6
|
+
import {
|
|
7
|
+
scanForUnregisteredFiles,
|
|
8
|
+
deriveContainerName as sharedDeriveContainerName,
|
|
9
|
+
type UnregisteredFile,
|
|
10
|
+
} from '../file-based-utils'
|
|
11
|
+
|
|
12
|
+
export type { UnregisteredFile }
|
|
13
|
+
|
|
14
|
+
export async function scanForUnregisteredDuckDBFiles(
|
|
15
|
+
directory?: string,
|
|
16
|
+
): Promise<UnregisteredFile[]> {
|
|
17
|
+
return scanForUnregisteredFiles(Engine.DuckDB, directory)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function deriveContainerName(fileName: string): string {
|
|
21
|
+
return sharedDeriveContainerName(fileName, Engine.DuckDB)
|
|
22
|
+
}
|
|
@@ -2,45 +2,52 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
FerretDB is a MongoDB-compatible proxy that stores data in PostgreSQL. It
|
|
5
|
+
FerretDB is a MongoDB-compatible proxy that stores data in PostgreSQL. It supports **two major versions** with different backends:
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
**v2 (default, macOS/Linux only):**
|
|
8
|
+
1. **ferretdb** (hostdb: `ferretdb`) - Stateless Go proxy
|
|
9
|
+
2. **postgresql-documentdb** (hostdb: `postgresql-documentdb`) - PostgreSQL 17 with DocumentDB extension
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
**v1 (all platforms including Windows):**
|
|
12
|
+
1. **ferretdb** (hostdb: `ferretdb`) - Stateless Go proxy (same protocol, older version)
|
|
13
|
+
2. **Plain PostgreSQL** - Standard PostgreSQL via `postgresqlBinaryManager` (shared with standalone PG containers)
|
|
14
|
+
|
|
15
|
+
This is a **composite engine** with unique binary management requirements. The `isV1(version)` helper in `version-maps.ts` is the single branching point for all version-dependent behavior.
|
|
11
16
|
|
|
12
17
|
## Platform Support
|
|
13
18
|
|
|
14
|
-
| Platform | Architecture | Status | Notes |
|
|
15
|
-
|
|
16
|
-
| darwin | x64 | Supported | Both
|
|
17
|
-
| darwin | arm64 | Supported | Both
|
|
18
|
-
| linux | x64 | Supported | Both
|
|
19
|
-
| linux | arm64 | Supported | Both
|
|
20
|
-
| win32 | x64 | **NOT SUPPORTED** | postgresql-documentdb has startup issues |
|
|
19
|
+
| Platform | Architecture | v1 Status | v2 Status | Notes |
|
|
20
|
+
|----------|--------------|-----------|-----------|-------|
|
|
21
|
+
| darwin | x64 | Supported | Supported | Both backends available |
|
|
22
|
+
| darwin | arm64 | Supported | Supported | Both backends available (Apple Silicon) |
|
|
23
|
+
| linux | x64 | Supported | Supported | Both backends available |
|
|
24
|
+
| linux | arm64 | Supported | Supported | Both backends available |
|
|
25
|
+
| win32 | x64 | Supported | **NOT SUPPORTED** | v2: postgresql-documentdb has startup issues |
|
|
26
|
+
|
|
27
|
+
### Windows Support
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
FerretDB **v1 is supported on Windows**. v2 is not available on Windows because postgresql-documentdb fails to initialize properly. `spindb create` auto-selects v1 on Windows. `spindb engines download ferretdb 2` on Windows is blocked with a helpful error suggesting v1.
|
|
23
30
|
|
|
24
|
-
|
|
31
|
+
**Important hostdb note:** hostdb has `ferretdb` v2 proxy binaries for Windows but does NOT have `postgresql-documentdb` for Windows. This means the v2 proxy would download successfully but fail to start (no backend). The version-aware platform check in `binary-urls.ts` prevents this.
|
|
25
32
|
|
|
26
33
|
### macOS SIP / Container Limitations
|
|
27
34
|
|
|
28
|
-
On macOS, System Integrity Protection (SIP) can block creating symlinks in system directories (e.g., `/usr/local`). In containerized or locked-down environments, even `sudo` may not permit writes to those paths. If you hit permission errors during setup, use a non-system install location or run with elevated privileges when available. See https://github.com/robertjbass/spindb#ferretdb for details.
|
|
35
|
+
On macOS, System Integrity Protection (SIP) can block creating symlinks in system directories (e.g., `/usr/local`). In containerized or locked-down environments, even `sudo` may not permit writes to those paths. If you hit permission errors during setup, use a non-system install location or run with elevated privileges when available. See https://github.com/robertjbass/spindb#ferretdb for details. This only applies to v2 (DocumentDB's Homebrew-derived paths).
|
|
29
36
|
|
|
30
37
|
## Binary Packaging
|
|
31
38
|
|
|
32
39
|
### Archive Format
|
|
33
|
-
- **Unix (macOS/Linux)**: `tar.gz` for both
|
|
34
|
-
- **Windows**:
|
|
40
|
+
- **Unix (macOS/Linux)**: `tar.gz` for both versions
|
|
41
|
+
- **Windows**: `zip` for v1 proxy, plain PostgreSQL handled by `postgresqlBinaryManager`
|
|
35
42
|
|
|
36
|
-
### FerretDB Archive Structure
|
|
43
|
+
### FerretDB Archive Structure (both v1 and v2)
|
|
37
44
|
```
|
|
38
45
|
ferretdb/
|
|
39
46
|
└── bin/
|
|
40
47
|
└── ferretdb # Go proxy binary
|
|
41
48
|
```
|
|
42
49
|
|
|
43
|
-
### postgresql-documentdb Archive Structure
|
|
50
|
+
### postgresql-documentdb Archive Structure (v2 only)
|
|
44
51
|
```
|
|
45
52
|
postgresql-documentdb/
|
|
46
53
|
├── bin/
|
|
@@ -57,7 +64,13 @@ postgresql-documentdb/
|
|
|
57
64
|
└── share/ # Configuration and data files
|
|
58
65
|
```
|
|
59
66
|
|
|
60
|
-
###
|
|
67
|
+
### v1 Backend (Plain PostgreSQL)
|
|
68
|
+
|
|
69
|
+
v1 delegates backend management to `postgresqlBinaryManager`, which downloads standard PostgreSQL from hostdb. The PostgreSQL binaries are shared with standalone PostgreSQL containers — deleting a FerretDB v1 installation does NOT delete the shared PostgreSQL.
|
|
70
|
+
|
|
71
|
+
**Caveat:** If `postgresqlBinaryManager.isInstalled()` finds an existing minimal PostgreSQL install (e.g., from a previous DocumentDB extraction) that only has server binaries (`postgres`, `pg_ctl`, `initdb`) but lacks client tools (`psql`), the engine falls back to `postgres --single` mode for pre-start database creation.
|
|
72
|
+
|
|
73
|
+
### Why Custom PostgreSQL Build? (v2)
|
|
61
74
|
|
|
62
75
|
The postgresql-documentdb bundle is a **custom PostgreSQL 17 build** that includes:
|
|
63
76
|
- DocumentDB extension (MongoDB-compatible storage)
|
|
@@ -79,11 +92,15 @@ Homebrew PostgreSQL has hardcoded paths (`/opt/homebrew/lib/...`) that break on
|
|
|
79
92
|
```typescript
|
|
80
93
|
// FerretDB versions
|
|
81
94
|
export const FERRETDB_VERSION_MAP: Record<string, string> = {
|
|
82
|
-
'
|
|
95
|
+
'1': '1.24.2', // v1: plain PostgreSQL backend
|
|
96
|
+
'2': '2.7.0', // v2: postgresql-documentdb backend
|
|
83
97
|
}
|
|
84
98
|
|
|
85
|
-
//
|
|
99
|
+
// v2 backend version format: {pg_major}-{documentdb_version}
|
|
86
100
|
export const DEFAULT_DOCUMENTDB_VERSION = '17-0.107.0'
|
|
101
|
+
|
|
102
|
+
// v1 backend: standard PostgreSQL major version
|
|
103
|
+
export const DEFAULT_V1_POSTGRESQL_VERSION = '17'
|
|
87
104
|
```
|
|
88
105
|
|
|
89
106
|
## Implementation Details
|
|
@@ -91,14 +108,17 @@ export const DEFAULT_DOCUMENTDB_VERSION = '17-0.107.0'
|
|
|
91
108
|
### Composite Binary Manager
|
|
92
109
|
|
|
93
110
|
FerretDB uses a custom `FerretDBCompositeBinaryManager` that:
|
|
94
|
-
- Downloads both binaries atomically (rolls back if either fails)
|
|
95
|
-
-
|
|
96
|
-
-
|
|
111
|
+
- Downloads both binaries atomically (rolls back if either fails) — v2 only
|
|
112
|
+
- For v1, downloads FerretDB proxy then delegates PostgreSQL to `postgresqlBinaryManager`
|
|
113
|
+
- `isV1(version)` branches all version-dependent behavior
|
|
114
|
+
- `getBackendBinaryPath()` / `getBackendSpawnEnv()` abstract v1/v2 backend resolution
|
|
97
115
|
|
|
98
116
|
### Architecture
|
|
99
117
|
|
|
100
118
|
```
|
|
101
|
-
MongoDB Client (:27017) -> FerretDB Proxy -> PostgreSQL
|
|
119
|
+
MongoDB Client (:27017) -> FerretDB Proxy -> PostgreSQL backend (:54320+)
|
|
120
|
+
v1: plain PostgreSQL
|
|
121
|
+
v2: PostgreSQL + DocumentDB
|
|
102
122
|
```
|
|
103
123
|
|
|
104
124
|
### Three Ports Per Container
|
|
@@ -111,11 +131,19 @@ FerretDB containers use **three ports**:
|
|
|
111
131
|
### FerretDB-Specific Startup Flags
|
|
112
132
|
|
|
113
133
|
```bash
|
|
134
|
+
# v2:
|
|
114
135
|
ferretdb \
|
|
115
|
-
--no-auth \ # Disable SCRAM authentication
|
|
136
|
+
--no-auth \ # Disable SCRAM authentication (v2 only)
|
|
116
137
|
--debug-addr=127.0.0.1:${port + 10000} \ # Unique debug port per container
|
|
117
138
|
--listen-addr=127.0.0.1:${port} \ # MongoDB wire protocol port
|
|
118
139
|
--postgresql-url=postgres://postgres@127.0.0.1:${backendPort}/ferretdb
|
|
140
|
+
|
|
141
|
+
# v1 (differences):
|
|
142
|
+
ferretdb \
|
|
143
|
+
# no --no-auth (auth disabled by default in v1)
|
|
144
|
+
--debug-addr=127.0.0.1:${port + 10000} \
|
|
145
|
+
--listen-addr=127.0.0.1:${port} \
|
|
146
|
+
--postgresql-url=postgres://postgres@127.0.0.1:${backendPort}/ferretdb?sslmode=disable
|
|
119
147
|
```
|
|
120
148
|
|
|
121
149
|
### Linux LD_LIBRARY_PATH
|
|
@@ -123,10 +151,10 @@ ferretdb \
|
|
|
123
151
|
On Linux, the bundled binaries need `LD_LIBRARY_PATH` set to find shared libraries:
|
|
124
152
|
|
|
125
153
|
```typescript
|
|
126
|
-
|
|
154
|
+
getBackendSpawnEnv(): { LD_LIBRARY_PATH: '/path/to/lib:$LD_LIBRARY_PATH' }
|
|
127
155
|
```
|
|
128
156
|
|
|
129
|
-
macOS uses `@loader_path` which doesn't need environment variables.
|
|
157
|
+
macOS uses `@loader_path` which doesn't need environment variables. Applies to both v1 and v2.
|
|
130
158
|
|
|
131
159
|
### macOS Code Signing
|
|
132
160
|
|
|
@@ -163,9 +191,9 @@ Restore may fail with: `duplicate key value violates unique constraint`
|
|
|
163
191
|
|
|
164
192
|
### Uninstall Behavior
|
|
165
193
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
194
|
+
**v2:** Both FerretDB proxy and postgresql-documentdb are deleted. The postgresql-documentdb binary is a dedicated dependency not shared with other engines.
|
|
195
|
+
|
|
196
|
+
**v1:** Only the FerretDB proxy is deleted. Plain PostgreSQL binaries are **NOT deleted** because they are shared with standalone PostgreSQL containers.
|
|
169
197
|
|
|
170
198
|
This differs from QuestDB's PostgreSQL dependency (see QuestDB README).
|
|
171
199
|
|
|
@@ -173,7 +201,7 @@ This differs from QuestDB's PostgreSQL dependency (see QuestDB README).
|
|
|
173
201
|
|
|
174
202
|
### 1. Authentication Gotcha
|
|
175
203
|
|
|
176
|
-
FerretDB 2.x enables SCRAM authentication by default. The `--setup-username` and `--setup-password` flags **do NOT exist** despite documentation suggestions. Use `--no-auth` instead.
|
|
204
|
+
FerretDB 2.x enables SCRAM authentication by default. The `--setup-username` and `--setup-password` flags **do NOT exist** despite documentation suggestions. Use `--no-auth` instead. FerretDB 1.x has auth disabled by default (no flag needed).
|
|
177
205
|
|
|
178
206
|
### 2. Debug Port Conflicts
|
|
179
207
|
|
|
@@ -187,9 +215,17 @@ Like MongoDB, databases don't appear until data is written. The engine uses the
|
|
|
187
215
|
|
|
188
216
|
Namespace is derived from container name: `my-app` -> `my_app` (dashes replaced with underscores).
|
|
189
217
|
|
|
190
|
-
### 5. Windows Unsupported
|
|
218
|
+
### 5. Windows: v2 Unsupported, v1 Supported
|
|
219
|
+
|
|
220
|
+
Extensive testing confirmed postgresql-documentdb (v2 backend) does not start properly on Windows. FerretDB v1 uses plain PostgreSQL and works on all platforms including Windows. **Note:** hostdb has v2 proxy binaries for Windows but NOT the backend — the download command blocks v2 on Windows to prevent broken installs.
|
|
221
|
+
|
|
222
|
+
### 6. v1 Binary Verification
|
|
223
|
+
|
|
224
|
+
FerretDB v1 hostdb builds panic on `--version` because the source expects `build/version/version.txt` (via `//go:embed`). The hostdb build script must create this file. SpinDB skips `--version` verification for v1 (only checks binary exists).
|
|
225
|
+
|
|
226
|
+
### 7. v1 Database Creation Without psql
|
|
191
227
|
|
|
192
|
-
|
|
228
|
+
If the PostgreSQL backend is a minimal install lacking `psql`, the engine uses `postgres --single` mode before server start to create the `ferretdb` database. This requires exclusive data directory access, so it runs before `pg_ctl start`.
|
|
193
229
|
|
|
194
230
|
## Docker E2E Test Notes
|
|
195
231
|
|
|
@@ -201,9 +237,9 @@ FerretDB Docker E2E tests verify:
|
|
|
201
237
|
|
|
202
238
|
## CI/CD Notes
|
|
203
239
|
|
|
204
|
-
###
|
|
240
|
+
### Windows CI
|
|
205
241
|
|
|
206
|
-
FerretDB CI tests are skipped on Windows runners
|
|
242
|
+
FerretDB v2 CI tests are skipped on Windows runners. v1 tests should run on all platforms.
|
|
207
243
|
|
|
208
244
|
### GitHub Actions Cache Step
|
|
209
245
|
|
|
@@ -214,11 +250,13 @@ FerretDB CI tests are skipped on Windows runners due to platform limitation.
|
|
|
214
250
|
path: |
|
|
215
251
|
~/.spindb/bin/ferretdb-*
|
|
216
252
|
~/.spindb/bin/postgresql-documentdb-*
|
|
253
|
+
~/.spindb/bin/postgresql-*
|
|
217
254
|
key: ferretdb-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('engines/ferretdb/version-maps.ts') }}
|
|
218
255
|
```
|
|
219
256
|
|
|
220
257
|
## Related Documentation
|
|
221
258
|
|
|
222
259
|
- [plans/FERRETDB.md](../../plans/FERRETDB.md) - Original implementation plan (may be outdated)
|
|
223
|
-
- hostdb releases: [ferretdb-2.7.0](https://github.com/robertjbass/hostdb/releases/tag/ferretdb-2.7.0)
|
|
224
|
-
- hostdb releases: [
|
|
260
|
+
- hostdb releases: [ferretdb-2.7.0](https://github.com/robertjbass/hostdb/releases/tag/ferretdb-2.7.0) (v2 proxy)
|
|
261
|
+
- hostdb releases: [ferretdb-1.24.2](https://github.com/robertjbass/hostdb/releases/tag/ferretdb-1.24.2) (v1 proxy)
|
|
262
|
+
- hostdb releases: [postgresql-documentdb-17-0.107.0](https://github.com/robertjbass/hostdb/releases/tag/postgresql-documentdb-17-0.107.0) (v2 backend)
|
|
@@ -14,29 +14,34 @@ import { logDebug } from '../../core/error-handler'
|
|
|
14
14
|
import { platformService } from '../../core/platform-service'
|
|
15
15
|
import { ferretdbBinaryManager } from './binary-manager'
|
|
16
16
|
import {
|
|
17
|
-
normalizeDocumentDBVersion,
|
|
18
17
|
DEFAULT_DOCUMENTDB_VERSION,
|
|
18
|
+
DEFAULT_V1_POSTGRESQL_VERSION,
|
|
19
|
+
isV1,
|
|
19
20
|
} from './version-maps'
|
|
20
21
|
import type { ContainerConfig, BackupOptions, BackupResult } from '../../types'
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
|
-
* Get the path to pg_dump from the
|
|
24
|
+
* Get the path to pg_dump from the backend installation
|
|
25
|
+
* Uses version-aware backend resolution (v1 = plain PostgreSQL, v2 = postgresql-documentdb)
|
|
24
26
|
*/
|
|
25
27
|
function getPgDumpPath(container: ContainerConfig): string {
|
|
26
|
-
const { backendVersion } = container
|
|
28
|
+
const { version, backendVersion } = container
|
|
27
29
|
const { platform, arch } = platformService.getPlatformInfo()
|
|
30
|
+
const v1 = isV1(version)
|
|
28
31
|
|
|
29
|
-
const
|
|
30
|
-
backendVersion ||
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
const effectiveBackendVersion = v1
|
|
33
|
+
? backendVersion || DEFAULT_V1_POSTGRESQL_VERSION
|
|
34
|
+
: backendVersion || DEFAULT_DOCUMENTDB_VERSION
|
|
35
|
+
|
|
36
|
+
const backendPath = ferretdbBinaryManager.getBackendBinaryPath(
|
|
37
|
+
version,
|
|
38
|
+
effectiveBackendVersion,
|
|
34
39
|
platform,
|
|
35
40
|
arch,
|
|
36
41
|
)
|
|
37
42
|
|
|
38
43
|
const ext = platformService.getExecutableExtension()
|
|
39
|
-
return join(
|
|
44
|
+
return join(backendPath, 'bin', `pg_dump${ext}`)
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
/**
|
|
@@ -63,8 +68,11 @@ export async function createBackup(
|
|
|
63
68
|
const pgDump = getPgDumpPath(container)
|
|
64
69
|
|
|
65
70
|
if (!existsSync(pgDump)) {
|
|
71
|
+
const backendName = isV1(container.version)
|
|
72
|
+
? 'PostgreSQL'
|
|
73
|
+
: 'postgresql-documentdb'
|
|
66
74
|
throw new Error(
|
|
67
|
-
`pg_dump not found at ${pgDump}. Make sure
|
|
75
|
+
`pg_dump not found at ${pgDump}. Make sure ${backendName} is installed.`,
|
|
68
76
|
)
|
|
69
77
|
}
|
|
70
78
|
|