spindb 0.7.0 → 0.7.5

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.
Files changed (40) hide show
  1. package/README.md +421 -294
  2. package/cli/commands/backup.ts +1 -30
  3. package/cli/commands/clone.ts +0 -6
  4. package/cli/commands/config.ts +7 -1
  5. package/cli/commands/connect.ts +1 -16
  6. package/cli/commands/create.ts +4 -55
  7. package/cli/commands/delete.ts +0 -6
  8. package/cli/commands/edit.ts +9 -25
  9. package/cli/commands/engines.ts +10 -188
  10. package/cli/commands/info.ts +7 -34
  11. package/cli/commands/list.ts +2 -18
  12. package/cli/commands/logs.ts +118 -0
  13. package/cli/commands/menu/backup-handlers.ts +749 -0
  14. package/cli/commands/menu/container-handlers.ts +825 -0
  15. package/cli/commands/menu/engine-handlers.ts +362 -0
  16. package/cli/commands/menu/index.ts +179 -0
  17. package/cli/commands/menu/shared.ts +26 -0
  18. package/cli/commands/menu/shell-handlers.ts +320 -0
  19. package/cli/commands/menu/sql-handlers.ts +194 -0
  20. package/cli/commands/menu/update-handlers.ts +94 -0
  21. package/cli/commands/restore.ts +2 -28
  22. package/cli/commands/run.ts +139 -0
  23. package/cli/commands/start.ts +2 -10
  24. package/cli/commands/stop.ts +0 -5
  25. package/cli/commands/url.ts +18 -13
  26. package/cli/constants.ts +10 -0
  27. package/cli/helpers.ts +152 -0
  28. package/cli/index.ts +5 -2
  29. package/cli/ui/prompts.ts +3 -11
  30. package/core/dependency-manager.ts +0 -163
  31. package/core/error-handler.ts +0 -26
  32. package/core/platform-service.ts +60 -40
  33. package/core/start-with-retry.ts +3 -28
  34. package/core/transaction-manager.ts +0 -8
  35. package/engines/base-engine.ts +10 -0
  36. package/engines/mysql/binary-detection.ts +1 -1
  37. package/engines/mysql/index.ts +78 -2
  38. package/engines/postgresql/index.ts +49 -0
  39. package/package.json +1 -1
  40. package/cli/commands/menu.ts +0 -2670
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { spawn, exec } from 'child_process'
7
7
  import { promisify } from 'util'
8
- import { existsSync } from 'fs'
8
+ import { existsSync, createReadStream } from 'fs'
9
9
  import { mkdir, writeFile, readFile, unlink } from 'fs/promises'
10
10
  import { join } from 'path'
11
11
  import { BaseEngine } from '../base-engine'
@@ -289,8 +289,9 @@ export class MySQLEngine extends BaseEngine {
289
289
  // Write PID file manually since we're running detached
290
290
  try {
291
291
  await writeFile(pidFile, String(proc.pid))
292
- } catch {
292
+ } catch (error) {
293
293
  // PID file might be written by mysqld itself
294
+ logDebug(`Could not write PID file (mysqld may write it): ${error}`)
294
295
  }
295
296
 
296
297
  // Wait for MySQL to be ready
@@ -842,6 +843,81 @@ export class MySQLEngine extends BaseEngine {
842
843
  ): Promise<BackupResult> {
843
844
  return createBackup(container, outputPath, options)
844
845
  }
846
+
847
+ /**
848
+ * Run a SQL file or inline SQL statement against the database
849
+ * CLI wrapper: mysql -h 127.0.0.1 -P {port} -u root {db} < {file}
850
+ * CLI wrapper: mysql -h 127.0.0.1 -P {port} -u root {db} -e "{sql}"
851
+ */
852
+ async runScript(
853
+ container: ContainerConfig,
854
+ options: { file?: string; sql?: string; database?: string },
855
+ ): Promise<void> {
856
+ const { port } = container
857
+ const db = options.database || container.database || 'mysql'
858
+
859
+ const mysql = await getMysqlClientPath()
860
+ if (!mysql) {
861
+ throw new Error(
862
+ 'mysql client not found. Install MySQL client tools:\n' +
863
+ ' macOS: brew install mysql-client\n' +
864
+ ' Ubuntu/Debian: sudo apt install mysql-client',
865
+ )
866
+ }
867
+
868
+ const args = [
869
+ '-h',
870
+ '127.0.0.1',
871
+ '-P',
872
+ String(port),
873
+ '-u',
874
+ engineDef.superuser,
875
+ db,
876
+ ]
877
+
878
+ if (options.sql) {
879
+ // For inline SQL, use -e flag
880
+ args.push('-e', options.sql)
881
+ return new Promise((resolve, reject) => {
882
+ const proc = spawn(mysql, args, { stdio: 'inherit' })
883
+
884
+ proc.on('error', reject)
885
+ proc.on('close', (code) => {
886
+ if (code === 0) {
887
+ resolve()
888
+ } else {
889
+ reject(new Error(`mysql exited with code ${code}`))
890
+ }
891
+ })
892
+ })
893
+ } else if (options.file) {
894
+ // For file input, pipe the file to mysql stdin
895
+ return new Promise((resolve, reject) => {
896
+ const fileStream = createReadStream(options.file!)
897
+ const proc = spawn(mysql, args, {
898
+ stdio: ['pipe', 'inherit', 'inherit'],
899
+ })
900
+
901
+ fileStream.pipe(proc.stdin)
902
+
903
+ fileStream.on('error', (err) => {
904
+ proc.kill()
905
+ reject(err)
906
+ })
907
+
908
+ proc.on('error', reject)
909
+ proc.on('close', (code) => {
910
+ if (code === 0) {
911
+ resolve()
912
+ } else {
913
+ reject(new Error(`mysql exited with code ${code}`))
914
+ }
915
+ })
916
+ })
917
+ } else {
918
+ throw new Error('Either file or sql option must be provided')
919
+ }
920
+ }
845
921
  }
846
922
 
847
923
  export const mysqlEngine = new MySQLEngine()
@@ -457,6 +457,55 @@ export class PostgreSQLEngine extends BaseEngine {
457
457
  ): Promise<BackupResult> {
458
458
  return createBackup(container, outputPath, options)
459
459
  }
460
+
461
+ /**
462
+ * Run a SQL file or inline SQL statement against the database
463
+ * CLI wrapper: psql -h 127.0.0.1 -p {port} -U postgres -d {db} -f {file}
464
+ * CLI wrapper: psql -h 127.0.0.1 -p {port} -U postgres -d {db} -c "{sql}"
465
+ */
466
+ async runScript(
467
+ container: ContainerConfig,
468
+ options: { file?: string; sql?: string; database?: string },
469
+ ): Promise<void> {
470
+ const { port } = container
471
+ const db = options.database || container.database || 'postgres'
472
+ const psqlPath = await this.getPsqlPath()
473
+
474
+ const args = [
475
+ '-h',
476
+ '127.0.0.1',
477
+ '-p',
478
+ String(port),
479
+ '-U',
480
+ defaults.superuser,
481
+ '-d',
482
+ db,
483
+ ]
484
+
485
+ if (options.file) {
486
+ args.push('-f', options.file)
487
+ } else if (options.sql) {
488
+ args.push('-c', options.sql)
489
+ } else {
490
+ throw new Error('Either file or sql option must be provided')
491
+ }
492
+
493
+ return new Promise((resolve, reject) => {
494
+ const proc = spawn(psqlPath, args, { stdio: 'inherit' })
495
+
496
+ proc.on('error', (err: NodeJS.ErrnoException) => {
497
+ reject(err)
498
+ })
499
+
500
+ proc.on('close', (code) => {
501
+ if (code === 0) {
502
+ resolve()
503
+ } else {
504
+ reject(new Error(`psql exited with code ${code}`))
505
+ }
506
+ })
507
+ })
508
+ }
460
509
  }
461
510
 
462
511
  export const postgresqlEngine = new PostgreSQLEngine()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spindb",
3
- "version": "0.7.0",
3
+ "version": "0.7.5",
4
4
  "description": "Spin up local database containers without Docker. A DBngin-like CLI for PostgreSQL and MySQL.",
5
5
  "type": "module",
6
6
  "bin": {