1+ /*
2+ * Copyright (c) 2024-2025 Elide Technologies, Inc.
3+ *
4+ * Licensed under the MIT license (the "License"); you may not use this file except in compliance
5+ * with the License. You may obtain a copy of the License at
6+ *
7+ * https://opensource.org/license/mit/
8+ *
9+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11+ * License for the specific language governing permissions and limitations under the License.
12+ */
13+
114package elide.tool.cli.cmd.db
215
316import io.micronaut.core.annotation.Introspected
417import io.micronaut.core.annotation.ReflectiveAccess
518import picocli.CommandLine.Command
619import picocli.CommandLine.Option
20+ import picocli.CommandLine.Parameters
21+ import java.nio.file.Files
22+ import java.nio.file.Path
23+ import elide.tool.cli.AbstractSubcommand
724import elide.tool.cli.CommandContext
825import elide.tool.cli.CommandResult
9- import elide.tool.cli.ProjectAwareSubcommand
1026import elide.tool.cli.ToolState
27+ import elide.tool.exec.SubprocessRunner.delegateTask
28+ import elide.tool.exec.SubprocessRunner.subprocess
29+ import elide.tool.exec.which
1130
1231@Command(
1332 name = " db" ,
@@ -17,7 +36,7 @@ import elide.tool.cli.ToolState
1736)
1837@Introspected
1938@ReflectiveAccess
20- internal class DbCommand : ProjectAwareSubcommand <ToolState , CommandContext >() {
39+ internal class DbCommand : AbstractSubcommand <ToolState , CommandContext >() {
2140 override suspend fun CommandContext.invoke (state : ToolContext <ToolState >): CommandResult {
2241 return err(" `elide db` requires a subcommand (try: studio)" )
2342 }
@@ -30,7 +49,15 @@ internal class DbCommand : ProjectAwareSubcommand<ToolState, CommandContext>() {
3049)
3150@Introspected
3251@ReflectiveAccess
33- internal class DbStudioCommand : ProjectAwareSubcommand <ToolState , CommandContext >() {
52+ internal class DbStudioCommand : AbstractSubcommand <ToolState , CommandContext >() {
53+
54+ @Parameters(
55+ index = " 0" ,
56+ description = [" Path to SQLite database file" ],
57+ arity = " 0..1" ,
58+ paramLabel = " DATABASE_PATH" ,
59+ )
60+ internal var databasePath: String? = null
3461
3562 @Option(
3663 names = [" --port" , " -p" ],
@@ -47,12 +74,31 @@ internal class DbStudioCommand : ProjectAwareSubcommand<ToolState, CommandContex
4774 internal var host: String = " localhost"
4875
4976 override suspend fun CommandContext.invoke (state : ToolContext <ToolState >): CommandResult {
50- output {
51- append(" Starting database UI on http://$host :$port " )
77+ val dbPath = databasePath ? : return err(" Database path is required" )
78+
79+ val dbFile = Path .of(dbPath)
80+ if (! Files .exists(dbFile)) {
81+ return err(" Database file not found: $dbPath " )
5282 }
5383
54- // TODO
84+ val absoluteDbPath = dbFile.toAbsolutePath().toString()
85+
86+ val npxPath = which(Path .of(" npx" )) ? : return err(" npx not found. Please install Node.js." )
87+
88+ val task = subprocess(npxPath) {
89+ args.add(" @outerbase/studio" )
90+ args.add(" --port" )
91+ args.add(port.toString())
92+ args.add(absoluteDbPath)
93+ }
94+
95+ output {
96+ appendLine(" Starting database UI on http://$host :$port " )
97+ appendLine(" Database: $absoluteDbPath " )
98+ appendLine()
99+ appendLine(" Press Ctrl+C to stop the server" )
100+ }
55101
56- return success( )
102+ return delegateTask(task )
57103 }
58104}
0 commit comments