spindb 0.14.0 → 0.15.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 +63 -24
- package/cli/commands/menu/engine-handlers.ts +34 -2
- package/cli/commands/menu/shell-handlers.ts +21 -0
- package/cli/constants.ts +4 -1
- package/cli/helpers.ts +94 -0
- package/config/engine-defaults.ts +15 -1
- package/core/transaction-manager.ts +2 -2
- package/engines/base-engine.ts +8 -0
- package/engines/index.ts +4 -1
- package/engines/mariadb/backup.ts +232 -0
- package/engines/mariadb/binary-manager.ts +456 -0
- package/engines/mariadb/binary-urls.ts +127 -0
- package/engines/mariadb/hostdb-releases.ts +271 -0
- package/engines/mariadb/index.ts +1009 -0
- package/engines/mariadb/restore.ts +344 -0
- package/engines/mariadb/version-maps.ts +65 -0
- package/engines/mariadb/version-validator.ts +193 -0
- package/engines/postgresql/version-maps.ts +7 -10
- package/package.json +8 -4
- package/types/index.ts +11 -0
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
**The first npm CLI for running local databases without Docker.**
|
|
9
9
|
|
|
10
|
-
Spin up PostgreSQL, MySQL, SQLite, MongoDB, and Redis instances for local development. No Docker daemon, no container networking, no volume mounts. Just databases running on localhost, ready in seconds.
|
|
10
|
+
Spin up PostgreSQL, MySQL, MariaDB, SQLite, MongoDB, and Redis instances for local development. No Docker daemon, no container networking, no volume mounts. Just databases running on localhost, ready in seconds.
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -139,20 +139,40 @@ You'll get an interactive menu with arrow-key navigation:
|
|
|
139
139
|
| Versions | 14, 15, 16, 17, 18 |
|
|
140
140
|
| Default port | 5432 |
|
|
141
141
|
| Default user | `postgres` |
|
|
142
|
-
| Binary source | [
|
|
142
|
+
| Binary source | [hostdb](https://github.com/robertjbass/hostdb) (macOS/Linux), [EDB](https://www.enterprisedb.com/) (Windows) |
|
|
143
143
|
|
|
144
144
|
SpinDB downloads PostgreSQL server binaries automatically:
|
|
145
|
-
- **macOS/Linux:** Pre-compiled binaries from
|
|
145
|
+
- **macOS/Linux:** Pre-compiled binaries from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases
|
|
146
146
|
- **Windows:** Official binaries from EnterpriseDB (EDB)
|
|
147
147
|
|
|
148
|
-
**Why download binaries instead of using system PostgreSQL?** The
|
|
148
|
+
**Why download binaries instead of using system PostgreSQL?** The hostdb project provides pre-configured, portable PostgreSQL binaries—just extract and run. This lets you run PostgreSQL 14 for one project and 18 for another, side-by-side, without conflicts.
|
|
149
149
|
|
|
150
|
-
**Client tools
|
|
150
|
+
**Client tools included:** PostgreSQL binaries include `psql`, `pg_dump`, and `pg_restore` for all operations.
|
|
151
|
+
|
|
152
|
+
#### MariaDB
|
|
153
|
+
|
|
154
|
+
| | |
|
|
155
|
+
|---|---|
|
|
156
|
+
| Versions | 10.11, 11.4, 11.8 |
|
|
157
|
+
| Default port | 3307 |
|
|
158
|
+
| Default user | `root` |
|
|
159
|
+
| Binary source | [hostdb](https://github.com/robertjbass/hostdb) |
|
|
160
|
+
|
|
161
|
+
SpinDB downloads MariaDB server binaries automatically from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases—just like PostgreSQL. This provides multi-version support and works across all platforms.
|
|
151
162
|
|
|
152
163
|
```bash
|
|
153
|
-
|
|
164
|
+
# Create a MariaDB container
|
|
165
|
+
spindb create mydb --engine mariadb
|
|
166
|
+
|
|
167
|
+
# Or using the alias
|
|
168
|
+
spindb create mydb -e maria
|
|
169
|
+
|
|
170
|
+
# Check what's available
|
|
171
|
+
spindb deps check --engine mariadb
|
|
154
172
|
```
|
|
155
173
|
|
|
174
|
+
MariaDB is MySQL-compatible, so most MySQL tools and clients work seamlessly. If you need MySQL-specific features, use the `mysql` engine instead.
|
|
175
|
+
|
|
156
176
|
#### MySQL
|
|
157
177
|
|
|
158
178
|
| | |
|
|
@@ -181,7 +201,7 @@ winget install Oracle.MySQL
|
|
|
181
201
|
spindb deps check --engine mysql
|
|
182
202
|
```
|
|
183
203
|
|
|
184
|
-
**Linux users:** MariaDB
|
|
204
|
+
**Linux users:** MariaDB is also available as a standalone engine with downloadable binaries. Use `spindb create mydb --engine mariadb` for the dedicated MariaDB engine.
|
|
185
205
|
|
|
186
206
|
#### SQLite
|
|
187
207
|
|
|
@@ -302,6 +322,7 @@ spindb connect myredis --iredis
|
|
|
302
322
|
|
|
303
323
|
```bash
|
|
304
324
|
spindb create mydb # PostgreSQL (default)
|
|
325
|
+
spindb create mydb --engine mariadb # MariaDB
|
|
305
326
|
spindb create mydb --engine mysql # MySQL
|
|
306
327
|
spindb create mydb --engine sqlite # SQLite (file-based)
|
|
307
328
|
spindb create mydb --db-version 16 # Specific PostgreSQL version
|
|
@@ -328,8 +349,8 @@ spindb create mydb --from "postgresql://user:pass@host:5432/production"
|
|
|
328
349
|
|
|
329
350
|
| Option | Description |
|
|
330
351
|
|--------|-------------|
|
|
331
|
-
| `--engine`, `-e` | Database engine (`postgresql`, `mysql`, `sqlite`, `mongodb`, `redis`) |
|
|
332
|
-
| `--db-version` | Engine version (e.g., 17 for PostgreSQL, 8 for Redis) |
|
|
352
|
+
| `--engine`, `-e` | Database engine (`postgresql`, `mariadb`, `mysql`, `sqlite`, `mongodb`, `redis`) |
|
|
353
|
+
| `--db-version` | Engine version (e.g., 17 for PostgreSQL, 11.8 for MariaDB, 8 for Redis) |
|
|
333
354
|
| `--port`, `-p` | Port number (not applicable for SQLite) |
|
|
334
355
|
| `--database`, `-d` | Primary database name (Redis uses 0-15) |
|
|
335
356
|
| `--path` | File path for SQLite databases |
|
|
@@ -442,6 +463,7 @@ spindb backup mydb --dump
|
|
|
442
463
|
|
|
443
464
|
Format by engine:
|
|
444
465
|
- PostgreSQL: `.sql` (plain SQL) / `.dump` (pg_dump custom)
|
|
466
|
+
- MariaDB: `.sql` (plain SQL) / `.sql.gz` (compressed SQL)
|
|
445
467
|
- MySQL: `.sql` (plain SQL) / `.sql.gz` (compressed SQL)
|
|
446
468
|
- SQLite: `.sql` (plain SQL) / `.sqlite` (binary copy)
|
|
447
469
|
- MongoDB: `.bson` (BSON dump) / `.archive` (compressed archive)
|
|
@@ -532,6 +554,18 @@ Each engine has specific backup formats and restore behaviors:
|
|
|
532
554
|
|
|
533
555
|
</details>
|
|
534
556
|
|
|
557
|
+
<details>
|
|
558
|
+
<summary>MariaDB</summary>
|
|
559
|
+
|
|
560
|
+
| Format | Extension | Tool | Notes |
|
|
561
|
+
|--------|-----------|------|-------|
|
|
562
|
+
| SQL | `.sql` | mariadb-dump | Plain text SQL |
|
|
563
|
+
| Compressed | `.sql.gz` | mariadb-dump + gzip | Gzip compressed SQL |
|
|
564
|
+
|
|
565
|
+
**Restore behavior:** Creates new database or replaces existing. Pipes to `mariadb` client.
|
|
566
|
+
|
|
567
|
+
</details>
|
|
568
|
+
|
|
535
569
|
<details>
|
|
536
570
|
<summary>MySQL</summary>
|
|
537
571
|
|
|
@@ -734,6 +768,7 @@ SpinDB supports enhanced database shells that provide features like auto-complet
|
|
|
734
768
|
| Engine | Standard | Enhanced | Universal |
|
|
735
769
|
|--------|----------|----------|-----------|
|
|
736
770
|
| PostgreSQL | `psql` | `pgcli` | `usql` |
|
|
771
|
+
| MariaDB | `mariadb` | `mycli` | `usql` |
|
|
737
772
|
| MySQL | `mysql` | `mycli` | `usql` |
|
|
738
773
|
| SQLite | `sqlite3` | `litecli` | `usql` |
|
|
739
774
|
| MongoDB | `mongosh` | - | `usql` |
|
|
@@ -824,12 +859,13 @@ Each database engine has its own persistence mechanism:
|
|
|
824
859
|
| Engine | Mechanism | Durability |
|
|
825
860
|
|--------|-----------|------------|
|
|
826
861
|
| PostgreSQL | Write-Ahead Logging (WAL) | Every commit is immediately durable |
|
|
862
|
+
| MariaDB | InnoDB transaction logs | Every commit is immediately durable |
|
|
827
863
|
| MySQL | InnoDB transaction logs | Every commit is immediately durable |
|
|
828
864
|
| SQLite | File-based transactions | Every commit is immediately durable |
|
|
829
865
|
| MongoDB | WiredTiger with journaling | Writes journaled before acknowledged |
|
|
830
866
|
| Redis | RDB snapshots | Periodic snapshots (see below) |
|
|
831
867
|
|
|
832
|
-
**PostgreSQL, MySQL, MongoDB:** These engines use transaction logs or journaling. Every committed write is guaranteed to survive a crash or unexpected shutdown.
|
|
868
|
+
**PostgreSQL, MariaDB, MySQL, MongoDB:** These engines use transaction logs or journaling. Every committed write is guaranteed to survive a crash or unexpected shutdown.
|
|
833
869
|
|
|
834
870
|
**SQLite:** As a file-based database, SQLite writes directly to disk on each commit. No server process means no risk of losing in-flight data.
|
|
835
871
|
|
|
@@ -843,41 +879,42 @@ This means Redis may lose up to ~60 seconds of writes on an unexpected crash. Fo
|
|
|
843
879
|
### Binary Sources
|
|
844
880
|
|
|
845
881
|
**PostgreSQL:** Server binaries are downloaded automatically:
|
|
846
|
-
- **macOS/Linux:** From [
|
|
847
|
-
|
|
882
|
+
- **All platforms (macOS/Linux/Windows for macOS/Linux via hostdb, Windows via EDB):** From [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases (macOS/Linux) or [EnterpriseDB (EDB)](https://www.enterprisedb.com/download-postgresql-binaries) (Windows)
|
|
883
|
+
|
|
884
|
+
**MariaDB:** Server binaries are downloaded automatically from [hostdb](https://github.com/robertjbass/hostdb) on GitHub Releases for all platforms.
|
|
848
885
|
|
|
849
886
|
**MySQL/MongoDB/Redis:** Uses your system installation. SpinDB detects binaries from Homebrew (macOS), apt/pacman (Linux), or Chocolatey/winget/Scoop (Windows).
|
|
850
887
|
|
|
851
|
-
### Why Precompiled Binaries for PostgreSQL, but System Installs for Others?
|
|
888
|
+
### Why Precompiled Binaries for PostgreSQL and MariaDB, but System Installs for Others?
|
|
852
889
|
|
|
853
890
|
This isn't a preference—it's a practical reality of what's available.
|
|
854
891
|
|
|
855
|
-
**PostgreSQL
|
|
892
|
+
**PostgreSQL and MariaDB have excellent embedded binary distributions.** The [hostdb](https://github.com/robertjbass/hostdb) project provides pre-compiled, portable database binaries:
|
|
856
893
|
|
|
857
894
|
- Cross-platform (macOS Intel/ARM, Linux x64/ARM, Windows)
|
|
858
|
-
- Hosted on
|
|
859
|
-
- ~45 MB per version
|
|
860
|
-
- Actively maintained with new
|
|
895
|
+
- Hosted on GitHub Releases (highly reliable CDN)
|
|
896
|
+
- ~45-100 MB per version
|
|
897
|
+
- Actively maintained with new database releases
|
|
861
898
|
|
|
862
|
-
This makes multi-version support trivial: need PostgreSQL 14 for a legacy project and 18 for a new one? SpinDB downloads
|
|
899
|
+
This makes multi-version support trivial: need PostgreSQL 14 for a legacy project and 18 for a new one? Need MariaDB 11.8? SpinDB downloads them all, and they run side-by-side without conflicts.
|
|
863
900
|
|
|
864
|
-
**No equivalent exists for MySQL, MongoDB, or Redis.** None of these databases have a comparable embedded binary
|
|
901
|
+
**No equivalent exists for MySQL, MongoDB, or Redis (yet).** None of these databases have a comparable embedded binary distribution:
|
|
865
902
|
|
|
866
|
-
- **MySQL:** Oracle distributes MySQL as large installers with system dependencies, not embeddable binaries.
|
|
903
|
+
- **MySQL:** Oracle distributes MySQL as large installers with system dependencies, not embeddable binaries.
|
|
867
904
|
- **MongoDB:** Server binaries are several hundred MB and aren't designed for portable distribution.
|
|
868
905
|
- **Redis:** While Redis is small (~6-12 MB), there's no official portable distribution. Community Windows ports exist, but macOS/Linux rely on system packages.
|
|
869
906
|
|
|
870
907
|
For these databases, system packages (Homebrew, apt, choco) are the most reliable option. They handle dependencies, platform quirks, and security updates. SpinDB simply orchestrates what's already installed.
|
|
871
908
|
|
|
872
|
-
**Does this limit multi-version support?** Yes, for MySQL/MongoDB/Redis you get whatever version your package manager provides. In practice, this is rarely a problem—developers seldom need multiple versions of these databases simultaneously.
|
|
909
|
+
**Does this limit multi-version support?** Yes, for MySQL/MongoDB/Redis you get whatever version your package manager provides. In practice, this is rarely a problem—developers seldom need multiple versions of these databases simultaneously. As hostdb expands to support more databases, SpinDB will adopt them for multi-version support.
|
|
873
910
|
|
|
874
911
|
---
|
|
875
912
|
|
|
876
913
|
## Limitations
|
|
877
914
|
|
|
878
|
-
- **Client tools required** - `
|
|
915
|
+
- **Client tools required** - `mysql`, `mongosh`, and `redis-cli` must be installed separately for some operations (connecting, backups, restores) for system-installed engines
|
|
879
916
|
- **Local only** - Databases bind to `127.0.0.1`; remote connections planned for v1.1
|
|
880
|
-
- **Single version for MySQL/MongoDB/Redis** - Unlike PostgreSQL, MySQL, MongoDB, and Redis use system installations, so you're limited to one version per machine (see [Why Precompiled Binaries for PostgreSQL?](#why-precompiled-binaries-for-postgresql-but-system-installs-for-others))
|
|
917
|
+
- **Single version for MySQL/MongoDB/Redis** - Unlike PostgreSQL and MariaDB, MySQL, MongoDB, and Redis use system installations, so you're limited to one version per machine (see [Why Precompiled Binaries for PostgreSQL and MariaDB?](#why-precompiled-binaries-for-postgresql-and-mariadb-but-system-installs-for-others))
|
|
881
918
|
- **Redis remote dump not supported** - Redis doesn't support creating containers from remote connection strings. Use backup/restore for data migration.
|
|
882
919
|
|
|
883
920
|
---
|
|
@@ -892,7 +929,6 @@ See [TODO.md](TODO.md) for the full roadmap.
|
|
|
892
929
|
- Secrets management (macOS Keychain)
|
|
893
930
|
|
|
894
931
|
### v1.2 - Additional Engines
|
|
895
|
-
- MariaDB as standalone engine
|
|
896
932
|
- CockroachDB (distributed SQL)
|
|
897
933
|
|
|
898
934
|
### v1.3 - Advanced Features
|
|
@@ -900,6 +936,9 @@ See [TODO.md](TODO.md) for the full roadmap.
|
|
|
900
936
|
- Scheduled backups
|
|
901
937
|
- Import from Docker
|
|
902
938
|
|
|
939
|
+
### Future Infrastructure
|
|
940
|
+
- **hostdb npm package**: Available database versions will be published as an npm package from [hostdb](https://github.com/robertjbass/hostdb) and imported into SpinDB, eliminating the need to manually sync version-maps.ts with releases.json
|
|
941
|
+
|
|
903
942
|
### Possible Future Engines
|
|
904
943
|
|
|
905
944
|
These engines are under consideration but not yet on the roadmap. Community interest and feasibility will determine priority:
|
|
@@ -11,6 +11,7 @@ import { getEngineIcon, ENGINE_ICONS } from '../../constants'
|
|
|
11
11
|
import {
|
|
12
12
|
getInstalledEngines,
|
|
13
13
|
type InstalledPostgresEngine,
|
|
14
|
+
type InstalledMariadbEngine,
|
|
14
15
|
type InstalledMysqlEngine,
|
|
15
16
|
type InstalledSqliteEngine,
|
|
16
17
|
type InstalledMongodbEngine,
|
|
@@ -54,6 +55,9 @@ export async function handleEngines(): Promise<void> {
|
|
|
54
55
|
const pgEngines = engines.filter(
|
|
55
56
|
(e): e is InstalledPostgresEngine => e.engine === 'postgresql',
|
|
56
57
|
)
|
|
58
|
+
const mariadbEngines = engines.filter(
|
|
59
|
+
(e): e is InstalledMariadbEngine => e.engine === 'mariadb',
|
|
60
|
+
)
|
|
57
61
|
const mysqlEngines = engines.filter(
|
|
58
62
|
(e): e is InstalledMysqlEngine => e.engine === 'mysql',
|
|
59
63
|
)
|
|
@@ -68,6 +72,7 @@ export async function handleEngines(): Promise<void> {
|
|
|
68
72
|
)
|
|
69
73
|
|
|
70
74
|
const totalPgSize = pgEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
|
|
75
|
+
const totalMariadbSize = mariadbEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
|
|
71
76
|
|
|
72
77
|
const COL_ENGINE = 14
|
|
73
78
|
const COL_VERSION = 12
|
|
@@ -97,6 +102,20 @@ export async function handleEngines(): Promise<void> {
|
|
|
97
102
|
)
|
|
98
103
|
}
|
|
99
104
|
|
|
105
|
+
for (const engine of mariadbEngines) {
|
|
106
|
+
const icon = getEngineIcon(engine.engine)
|
|
107
|
+
const platformInfo = `${engine.platform}-${engine.arch}`
|
|
108
|
+
const engineDisplay = `${icon} ${engine.engine}`
|
|
109
|
+
|
|
110
|
+
console.log(
|
|
111
|
+
chalk.gray(' ') +
|
|
112
|
+
chalk.cyan(padToWidth(engineDisplay, COL_ENGINE)) +
|
|
113
|
+
chalk.yellow(engine.version.padEnd(COL_VERSION)) +
|
|
114
|
+
chalk.gray(platformInfo.padEnd(COL_SOURCE)) +
|
|
115
|
+
chalk.white(formatBytes(engine.sizeBytes)),
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
100
119
|
for (const mysqlEngine of mysqlEngines) {
|
|
101
120
|
const icon = ENGINE_ICONS.mysql
|
|
102
121
|
const displayName = mysqlEngine.isMariaDB ? 'mariadb' : 'mysql'
|
|
@@ -113,8 +132,7 @@ export async function handleEngines(): Promise<void> {
|
|
|
113
132
|
|
|
114
133
|
if (sqliteEngine) {
|
|
115
134
|
const icon = ENGINE_ICONS.sqlite
|
|
116
|
-
|
|
117
|
-
const engineDisplay = `${icon} sqlite`
|
|
135
|
+
const engineDisplay = `${icon} sqlite`
|
|
118
136
|
|
|
119
137
|
console.log(
|
|
120
138
|
chalk.gray(' ') +
|
|
@@ -161,6 +179,13 @@ export async function handleEngines(): Promise<void> {
|
|
|
161
179
|
),
|
|
162
180
|
)
|
|
163
181
|
}
|
|
182
|
+
if (mariadbEngines.length > 0) {
|
|
183
|
+
console.log(
|
|
184
|
+
chalk.gray(
|
|
185
|
+
` MariaDB: ${mariadbEngines.length} version(s), ${formatBytes(totalMariadbSize)}`,
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
}
|
|
164
189
|
if (mysqlEngines.length > 0) {
|
|
165
190
|
const versionCount = mysqlEngines.length
|
|
166
191
|
const versionText = versionCount === 1 ? 'version' : 'versions'
|
|
@@ -198,6 +223,13 @@ export async function handleEngines(): Promise<void> {
|
|
|
198
223
|
})
|
|
199
224
|
}
|
|
200
225
|
|
|
226
|
+
for (const e of mariadbEngines) {
|
|
227
|
+
choices.push({
|
|
228
|
+
name: `${chalk.red('✕')} Delete ${e.engine} ${e.version} ${chalk.gray(`(${formatBytes(e.sizeBytes)})`)}`,
|
|
229
|
+
value: `delete:${e.path}:${e.engine}:${e.version}`,
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
201
233
|
for (const mysqlEngine of mysqlEngines) {
|
|
202
234
|
const displayName = mysqlEngine.isMariaDB ? 'MariaDB' : 'MySQL'
|
|
203
235
|
// Show formula name if it's a versioned install
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getIredisManualInstructions,
|
|
22
22
|
} from '../../../core/dependency-manager'
|
|
23
23
|
import { platformService } from '../../../core/platform-service'
|
|
24
|
+
import { configManager } from '../../../core/config-manager'
|
|
24
25
|
import { getEngine } from '../../../engines'
|
|
25
26
|
import { createSpinner } from '../../ui/spinner'
|
|
26
27
|
import { uiError, uiWarning, uiInfo, uiSuccess } from '../../ui/theme'
|
|
@@ -118,6 +119,12 @@ export async function handleOpenShell(containerName: string): Promise<void> {
|
|
|
118
119
|
engineSpecificInstalled = mycliInstalled
|
|
119
120
|
engineSpecificValue = 'mycli'
|
|
120
121
|
engineSpecificInstallValue = 'install-mycli'
|
|
122
|
+
} else if (config.engine === 'mariadb') {
|
|
123
|
+
defaultShellName = 'mariadb'
|
|
124
|
+
engineSpecificCli = 'mycli'
|
|
125
|
+
engineSpecificInstalled = mycliInstalled
|
|
126
|
+
engineSpecificValue = 'mycli'
|
|
127
|
+
engineSpecificInstallValue = 'install-mycli'
|
|
121
128
|
} else if (config.engine === 'mongodb') {
|
|
122
129
|
defaultShellName = 'mongosh'
|
|
123
130
|
// mongosh IS the enhanced shell for MongoDB (no separate enhanced CLI like pgcli/mycli)
|
|
@@ -425,6 +432,20 @@ async function launchShell(
|
|
|
425
432
|
config.database,
|
|
426
433
|
]
|
|
427
434
|
installHint = 'brew install mysql-client'
|
|
435
|
+
} else if (config.engine === 'mariadb') {
|
|
436
|
+
// MariaDB uses downloaded binaries, not system PATH - get the actual path
|
|
437
|
+
const mariadbPath = await configManager.getBinaryPath('mariadb')
|
|
438
|
+
shellCmd = mariadbPath || 'mariadb'
|
|
439
|
+
shellArgs = [
|
|
440
|
+
'-u',
|
|
441
|
+
'root',
|
|
442
|
+
'-h',
|
|
443
|
+
'127.0.0.1',
|
|
444
|
+
'-P',
|
|
445
|
+
String(config.port),
|
|
446
|
+
config.database,
|
|
447
|
+
]
|
|
448
|
+
installHint = 'spindb engines download mariadb'
|
|
428
449
|
} else if (config.engine === 'mongodb') {
|
|
429
450
|
shellCmd = 'mongosh'
|
|
430
451
|
shellArgs = [connectionString]
|
package/cli/constants.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
// Note: Some emojis render narrower than others in terminals.
|
|
2
|
+
// Add extra space after narrow emojis (🦭, 🪶) for visual alignment.
|
|
1
3
|
export const ENGINE_ICONS: Record<string, string> = {
|
|
2
4
|
postgresql: '🐘',
|
|
3
5
|
mysql: '🐬',
|
|
4
|
-
|
|
6
|
+
mariadb: '🦭 ', // Extra space - seal emoji renders narrow
|
|
7
|
+
sqlite: '🪶 ', // Extra space - feather emoji renders narrow
|
|
5
8
|
mongodb: '🍃',
|
|
6
9
|
redis: '🔴',
|
|
7
10
|
}
|
package/cli/helpers.ts
CHANGED
|
@@ -30,6 +30,16 @@ export type InstalledPostgresEngine = {
|
|
|
30
30
|
source: 'downloaded'
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export type InstalledMariadbEngine = {
|
|
34
|
+
engine: 'mariadb'
|
|
35
|
+
version: string
|
|
36
|
+
platform: string
|
|
37
|
+
arch: string
|
|
38
|
+
path: string
|
|
39
|
+
sizeBytes: number
|
|
40
|
+
source: 'downloaded'
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
export type InstalledMysqlEngine = {
|
|
34
44
|
engine: 'mysql'
|
|
35
45
|
version: string
|
|
@@ -64,6 +74,7 @@ export type InstalledRedisEngine = {
|
|
|
64
74
|
|
|
65
75
|
export type InstalledEngine =
|
|
66
76
|
| InstalledPostgresEngine
|
|
77
|
+
| InstalledMariadbEngine
|
|
67
78
|
| InstalledMysqlEngine
|
|
68
79
|
| InstalledSqliteEngine
|
|
69
80
|
| InstalledMongodbEngine
|
|
@@ -143,6 +154,86 @@ export async function getInstalledPostgresEngines(): Promise<
|
|
|
143
154
|
return engines
|
|
144
155
|
}
|
|
145
156
|
|
|
157
|
+
async function getMariadbVersion(binPath: string): Promise<string | null> {
|
|
158
|
+
const ext = platformService.getExecutableExtension()
|
|
159
|
+
// Try mariadbd first, then mysqld
|
|
160
|
+
let serverPath = join(binPath, 'bin', `mariadbd${ext}`)
|
|
161
|
+
if (!existsSync(serverPath)) {
|
|
162
|
+
serverPath = join(binPath, 'bin', `mysqld${ext}`)
|
|
163
|
+
}
|
|
164
|
+
if (!existsSync(serverPath)) {
|
|
165
|
+
return null
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
const { stdout } = await execFileAsync(serverPath, ['--version'])
|
|
170
|
+
// Parse output like "mariadbd Ver 11.8.5-MariaDB"
|
|
171
|
+
const match = stdout.match(/Ver\s+([\d.]+)/)
|
|
172
|
+
return match ? match[1] : null
|
|
173
|
+
} catch {
|
|
174
|
+
return null
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export async function getInstalledMariadbEngines(): Promise<
|
|
179
|
+
InstalledMariadbEngine[]
|
|
180
|
+
> {
|
|
181
|
+
const binDir = paths.bin
|
|
182
|
+
|
|
183
|
+
if (!existsSync(binDir)) {
|
|
184
|
+
return []
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const entries = await readdir(binDir, { withFileTypes: true })
|
|
188
|
+
const engines: InstalledMariadbEngine[] = []
|
|
189
|
+
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
if (entry.isDirectory()) {
|
|
192
|
+
// Match mariadb-{version}-{platform}-{arch} directories
|
|
193
|
+
const match = entry.name.match(/^(\w+)-([\d.]+)-(\w+)-(\w+)$/)
|
|
194
|
+
if (match && match[1] === 'mariadb') {
|
|
195
|
+
const [, , majorVersion, platform, arch] = match
|
|
196
|
+
const dirPath = join(binDir, entry.name)
|
|
197
|
+
|
|
198
|
+
const actualVersion =
|
|
199
|
+
(await getMariadbVersion(dirPath)) || majorVersion
|
|
200
|
+
|
|
201
|
+
let sizeBytes = 0
|
|
202
|
+
try {
|
|
203
|
+
const files = await readdir(dirPath, { recursive: true })
|
|
204
|
+
for (const file of files) {
|
|
205
|
+
try {
|
|
206
|
+
const filePath = join(dirPath, file.toString())
|
|
207
|
+
const fileStat = await lstat(filePath)
|
|
208
|
+
if (fileStat.isFile()) {
|
|
209
|
+
sizeBytes += fileStat.size
|
|
210
|
+
}
|
|
211
|
+
} catch {
|
|
212
|
+
// Skip files we can't stat
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
// Skip directories we can't read
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
engines.push({
|
|
220
|
+
engine: 'mariadb',
|
|
221
|
+
version: actualVersion,
|
|
222
|
+
platform,
|
|
223
|
+
arch,
|
|
224
|
+
path: dirPath,
|
|
225
|
+
sizeBytes,
|
|
226
|
+
source: 'downloaded',
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
engines.sort((a, b) => compareVersions(b.version, a.version))
|
|
233
|
+
|
|
234
|
+
return engines
|
|
235
|
+
}
|
|
236
|
+
|
|
146
237
|
/**
|
|
147
238
|
* Extract Homebrew formula name from a binary path by resolving symlinks
|
|
148
239
|
*/
|
|
@@ -468,6 +559,9 @@ export async function getInstalledEngines(): Promise<InstalledEngine[]> {
|
|
|
468
559
|
const pgEngines = await getInstalledPostgresEngines()
|
|
469
560
|
engines.push(...pgEngines)
|
|
470
561
|
|
|
562
|
+
const mariadbEngines = await getInstalledMariadbEngines()
|
|
563
|
+
engines.push(...mariadbEngines)
|
|
564
|
+
|
|
471
565
|
const mysqlEngines = await getInstalledMysqlEngines()
|
|
472
566
|
engines.push(...mysqlEngines)
|
|
473
567
|
|
|
@@ -35,7 +35,7 @@ export const engineDefaults: Record<string, EngineDefaults> = {
|
|
|
35
35
|
defaultVersion: '18',
|
|
36
36
|
defaultPort: 5432,
|
|
37
37
|
portRange: { start: 5432, end: 5500 },
|
|
38
|
-
supportedVersions: ['
|
|
38
|
+
supportedVersions: ['15', '16', '17', '18'], // keep in sync with engines/postgresql/version-maps.ts
|
|
39
39
|
latestVersion: '18',
|
|
40
40
|
superuser: 'postgres',
|
|
41
41
|
connectionScheme: 'postgresql',
|
|
@@ -59,6 +59,20 @@ export const engineDefaults: Record<string, EngineDefaults> = {
|
|
|
59
59
|
clientTools: ['mysql', 'mysqldump', 'mysqlpump'],
|
|
60
60
|
maxConnections: 200, // Higher than default 151 for parallel builds
|
|
61
61
|
},
|
|
62
|
+
mariadb: {
|
|
63
|
+
defaultVersion: '11.8',
|
|
64
|
+
defaultPort: 3307, // Different from MySQL to allow side-by-side
|
|
65
|
+
portRange: { start: 3307, end: 3400 },
|
|
66
|
+
supportedVersions: ['10.11', '11.4', '11.8'], // Keep in sync with engines/mariadb/version-maps.ts
|
|
67
|
+
latestVersion: '11.8',
|
|
68
|
+
superuser: 'root',
|
|
69
|
+
connectionScheme: 'mysql', // MariaDB uses MySQL protocol
|
|
70
|
+
logFileName: 'mariadb.log',
|
|
71
|
+
pidFileName: 'mariadb.pid',
|
|
72
|
+
dataSubdir: 'data',
|
|
73
|
+
clientTools: ['mysql', 'mysqldump', 'mysqladmin'],
|
|
74
|
+
maxConnections: 200, // Higher than default 151 for parallel builds
|
|
75
|
+
},
|
|
62
76
|
sqlite: {
|
|
63
77
|
defaultVersion: '3',
|
|
64
78
|
defaultPort: 0, // File-based, no port
|
|
@@ -16,7 +16,7 @@ export type RollbackAction = {
|
|
|
16
16
|
* Manages a stack of rollback actions for transactional operations.
|
|
17
17
|
*
|
|
18
18
|
* Usage:
|
|
19
|
-
* ```
|
|
19
|
+
* ```ts
|
|
20
20
|
* const tx = new TransactionManager()
|
|
21
21
|
*
|
|
22
22
|
* try {
|
|
@@ -134,7 +134,7 @@ export class TransactionManager {
|
|
|
134
134
|
* Helper function to execute an operation with automatic rollback on failure.
|
|
135
135
|
*
|
|
136
136
|
* Usage:
|
|
137
|
-
* ```
|
|
137
|
+
* ```ts
|
|
138
138
|
* await withTransaction(async (tx) => {
|
|
139
139
|
* await step1()
|
|
140
140
|
* tx.addRollback({ description: 'Undo step1', execute: undoStep1 })
|
package/engines/base-engine.ts
CHANGED
|
@@ -96,6 +96,14 @@ export abstract class BaseEngine {
|
|
|
96
96
|
throw new Error('mysql client not found')
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Get the path to the mariadb client if available
|
|
101
|
+
* Default implementation throws; MariaDB engine overrides this method.
|
|
102
|
+
*/
|
|
103
|
+
async getMariadbClientPath(): Promise<string> {
|
|
104
|
+
throw new Error('mariadb client not found')
|
|
105
|
+
}
|
|
106
|
+
|
|
99
107
|
/**
|
|
100
108
|
* Get the path to the mysqladmin client if available
|
|
101
109
|
* Default implementation throws; engines that can provide a bundled or
|
package/engines/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { postgresqlEngine } from './postgresql'
|
|
2
2
|
import { mysqlEngine } from './mysql'
|
|
3
|
+
import { mariadbEngine } from './mariadb'
|
|
3
4
|
import { sqliteEngine } from './sqlite'
|
|
4
5
|
import { mongodbEngine } from './mongodb'
|
|
5
6
|
import { redisEngine } from './redis'
|
|
@@ -16,7 +17,9 @@ export const engines: Record<string, BaseEngine> = {
|
|
|
16
17
|
pg: postgresqlEngine,
|
|
17
18
|
// MySQL and aliases
|
|
18
19
|
mysql: mysqlEngine,
|
|
19
|
-
|
|
20
|
+
// MariaDB (standalone engine with downloadable binaries)
|
|
21
|
+
mariadb: mariadbEngine,
|
|
22
|
+
maria: mariadbEngine,
|
|
20
23
|
// SQLite and aliases
|
|
21
24
|
sqlite: sqliteEngine,
|
|
22
25
|
lite: sqliteEngine,
|