diff --git a/go/cmd/dolt/cli/documentation_helper.go b/go/cmd/dolt/cli/documentation_helper.go index 0c4c243a09d..d479325d040 100644 --- a/go/cmd/dolt/cli/documentation_helper.go +++ b/go/cmd/dolt/cli/documentation_helper.go @@ -217,6 +217,9 @@ var CliFormat = docFormat{"<", ">", "", ""} // Synopsis is an mdx format, but already inside a code block var SynopsisMarkdownFormat = docFormat{"<", ">", "`", "`"} +// Format that deletes all template options +var EmptyFormat = docFormat{"", "", "", ""} + func transformSynopsisToMarkdown(commandStr string, synopsis []string) string { if len(synopsis) == 0 { return "" diff --git a/go/cmd/dolt/cli/help.go b/go/cmd/dolt/cli/help.go index 2e35195ae4a..c2e9cd6c47f 100644 --- a/go/cmd/dolt/cli/help.go +++ b/go/cmd/dolt/cli/help.go @@ -166,21 +166,35 @@ func terminalSize() (width, height int) { func OptionsUsage(ap *argparser.ArgParser, indent string, lineLen int) string { var lines []string - for _, kvTuple := range ap.ArgListHelp { - k, v := kvTuple[0], kvTuple[1] - lines = append(lines, "<"+k+">") - l, err := templateDocStringHelper(v, CliFormat) - if err != nil { - panic(err) - } - l = embolden(l) - descLines := toParagraphLines(l, lineLen) + for _, usage := range OptionsUsageList(ap, CliFormat) { + name, description := usage[0], usage[1] + + lines = append(lines, name) + + descLines := toParagraphLines(description, lineLen) descLines = indentLines(descLines, " ") descLines = append(descLines, "") lines = append(lines, descLines...) } + lines = indentLines(lines, indent) + return strings.Join(lines, "\n") +} + +// OptionsUsageList returns a pair of strings for each option/argument in |ap|, where the first string +// is the name of the option/argument and the second string is the description of the option/argument. +func OptionsUsageList(ap *argparser.ArgParser, docFormat docFormat) [][2]string { + res := [][2]string{} + + for _, help := range ap.ArgListHelp { + name, description := help[0], help[1] + + nameFormatted := "<" + name + ">" + + res = append(res, [2]string{nameFormatted, description}) + } + for _, supOpt := range ap.Supported { argHelpFmt := "--%[2]s" @@ -192,22 +206,22 @@ func OptionsUsage(ap *argparser.ArgParser, indent string, lineLen int) string { argHelpFmt = "--%[2]s=<%[3]s>" } - lines = append(lines, fmt.Sprintf(argHelpFmt, supOpt.Abbrev, supOpt.Name, supOpt.ValDesc)) + nameFormatted := fmt.Sprintf(argHelpFmt, supOpt.Abbrev, supOpt.Name, supOpt.ValDesc) - l, err := templateDocStringHelper(supOpt.Desc, CliFormat) + res = append(res, [2]string{nameFormatted, supOpt.Desc}) + } + + for i := range res { + descriptionFormatted, err := templateDocStringHelper(res[i][1], docFormat) if err != nil { panic(err) } - l = embolden(l) - descLines := toParagraphLines(l, lineLen) - descLines = indentLines(descLines, " ") - descLines = append(descLines, "") + descriptionFormatted = embolden(descriptionFormatted) - lines = append(lines, descLines...) + res[i][1] = descriptionFormatted } - lines = indentLines(lines, indent) - return strings.Join(lines, "\n") + return res } func ToIndentedParagraph(inStr, indent string, lineLen int) string { diff --git a/go/cmd/dolt/dolt.go b/go/cmd/dolt/dolt.go index 9c89eb4fdbd..489e3c41fbf 100644 --- a/go/cmd/dolt/dolt.go +++ b/go/cmd/dolt/dolt.go @@ -44,15 +44,13 @@ import ( "github.com/dolthub/dolt/go/cmd/dolt/commands" "github.com/dolthub/dolt/go/cmd/dolt/commands/admin" "github.com/dolthub/dolt/go/cmd/dolt/commands/ci" - "github.com/dolthub/dolt/go/cmd/dolt/commands/cnfcmds" "github.com/dolthub/dolt/go/cmd/dolt/commands/credcmds" "github.com/dolthub/dolt/go/cmd/dolt/commands/cvcmds" "github.com/dolthub/dolt/go/cmd/dolt/commands/docscmds" "github.com/dolthub/dolt/go/cmd/dolt/commands/indexcmds" "github.com/dolthub/dolt/go/cmd/dolt/commands/schcmds" "github.com/dolthub/dolt/go/cmd/dolt/commands/sqlserver" - "github.com/dolthub/dolt/go/cmd/dolt/commands/stashcmds" - "github.com/dolthub/dolt/go/cmd/dolt/commands/tblcmds" + "github.com/dolthub/dolt/go/cmd/dolt/doltcmd" "github.com/dolthub/dolt/go/cmd/dolt/doltversion" "github.com/dolthub/dolt/go/libraries/doltcore/dbfactory" "github.com/dolthub/dolt/go/libraries/doltcore/dconfig" @@ -60,6 +58,7 @@ import ( "github.com/dolthub/dolt/go/libraries/doltcore/env" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dfunctions" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" + "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dtables" "github.com/dolthub/dolt/go/libraries/events" "github.com/dolthub/dolt/go/libraries/utils/argparser" "github.com/dolthub/dolt/go/libraries/utils/config" @@ -71,65 +70,6 @@ import ( var dumpDocsCommand = &commands.DumpDocsCmd{} var dumpZshCommand = &commands.GenZshCompCmd{} -var doltSubCommands = []cli.Command{ - commands.InitCmd{}, - commands.StatusCmd{}, - commands.AddCmd{}, - commands.DiffCmd{}, - commands.ResetCmd{}, - commands.CleanCmd{}, - commands.CommitCmd{}, - commands.SqlCmd{VersionStr: doltversion.Version}, - admin.Commands, - sqlserver.SqlServerCmd{VersionStr: doltversion.Version}, - commands.LogCmd{}, - commands.ShowCmd{}, - commands.BranchCmd{}, - commands.CheckoutCmd{}, - commands.MergeCmd{}, - cnfcmds.Commands, - commands.CherryPickCmd{}, - commands.RevertCmd{}, - commands.CloneCmd{}, - commands.FetchCmd{}, - commands.PullCmd{}, - commands.PushCmd{}, - commands.ConfigCmd{}, - commands.RemoteCmd{}, - commands.BackupCmd{}, - commands.LoginCmd{}, - credcmds.Commands, - commands.LsCmd{}, - schcmds.Commands, - tblcmds.Commands, - commands.TagCmd{}, - commands.BlameCmd{}, - cvcmds.Commands, - commands.SendMetricsCmd{}, - commands.MigrateCmd{}, - indexcmds.Commands, - commands.ReadTablesCmd{}, - commands.GarbageCollectionCmd{}, - commands.FsckCmd{}, - commands.FilterBranchCmd{}, - commands.MergeBaseCmd{}, - commands.RootsCmd{}, - commands.VersionCmd{VersionStr: doltversion.Version}, - commands.DumpCmd{}, - commands.InspectCmd{}, - dumpDocsCommand, - dumpZshCommand, - docscmds.Commands, - stashcmds.StashCommands, - &commands.Assist{}, - commands.ProfileCmd{}, - commands.QueryDiff{}, - commands.ReflogCmd{}, - commands.RebaseCmd{}, - commands.ArchiveCmd{}, - ci.Commands, -} - var commandsWithoutCliCtx = []cli.Command{ admin.Commands, commands.CloneCmd{}, @@ -204,7 +144,7 @@ func needsWriteAccess(commandName string) bool { return true } -var doltCommand = cli.NewSubCommandHandler("dolt", "it's git for data", doltSubCommands) +var doltCommand = doltcmd.DoltCommand var globalArgParser = cli.CreateGlobalArgParser("dolt") var globalDocs = cli.CommandDocsForCommandString("dolt", doc, globalArgParser) @@ -226,6 +166,8 @@ func init() { if _, ok := os.LookupEnv(disableEventFlushEnvVar); ok { eventFlushDisabled = true } + + dtables.DoltCommand = doltCommand } const pprofServerFlag = "--pprof-server" diff --git a/go/cmd/dolt/doltcmd/doltcmd.go b/go/cmd/dolt/doltcmd/doltcmd.go new file mode 100644 index 00000000000..1b00ad7d229 --- /dev/null +++ b/go/cmd/dolt/doltcmd/doltcmd.go @@ -0,0 +1,120 @@ +// Copyright 2025 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package doltcmd + +import ( + "github.com/dolthub/dolt/go/cmd/dolt/cli" + "github.com/dolthub/dolt/go/cmd/dolt/commands" + "github.com/dolthub/dolt/go/cmd/dolt/commands/admin" + "github.com/dolthub/dolt/go/cmd/dolt/commands/ci" + "github.com/dolthub/dolt/go/cmd/dolt/commands/cnfcmds" + "github.com/dolthub/dolt/go/cmd/dolt/commands/credcmds" + "github.com/dolthub/dolt/go/cmd/dolt/commands/cvcmds" + "github.com/dolthub/dolt/go/cmd/dolt/commands/docscmds" + "github.com/dolthub/dolt/go/cmd/dolt/commands/indexcmds" + "github.com/dolthub/dolt/go/cmd/dolt/commands/schcmds" + "github.com/dolthub/dolt/go/cmd/dolt/commands/sqlserver" + "github.com/dolthub/dolt/go/cmd/dolt/commands/stashcmds" + "github.com/dolthub/dolt/go/cmd/dolt/commands/tblcmds" + "github.com/dolthub/dolt/go/cmd/dolt/doltversion" +) + +var dumpDocsCommand = &commands.DumpDocsCmd{} +var dumpZshCommand = &commands.GenZshCompCmd{} + +var doltSubCommands = []cli.Command{ + commands.InitCmd{}, + commands.StatusCmd{}, + commands.AddCmd{}, + commands.DiffCmd{}, + commands.ResetCmd{}, + commands.CleanCmd{}, + commands.CommitCmd{}, + commands.SqlCmd{VersionStr: doltversion.Version}, + admin.Commands, + sqlserver.SqlServerCmd{VersionStr: doltversion.Version}, + commands.LogCmd{}, + commands.ShowCmd{}, + commands.BranchCmd{}, + commands.CheckoutCmd{}, + commands.MergeCmd{}, + cnfcmds.Commands, + commands.CherryPickCmd{}, + commands.RevertCmd{}, + commands.CloneCmd{}, + commands.FetchCmd{}, + commands.PullCmd{}, + commands.PushCmd{}, + commands.ConfigCmd{}, + commands.RemoteCmd{}, + commands.BackupCmd{}, + commands.LoginCmd{}, + credcmds.Commands, + commands.LsCmd{}, + schcmds.Commands, + tblcmds.Commands, + commands.TagCmd{}, + commands.BlameCmd{}, + cvcmds.Commands, + commands.SendMetricsCmd{}, + commands.MigrateCmd{}, + indexcmds.Commands, + commands.ReadTablesCmd{}, + commands.GarbageCollectionCmd{}, + commands.FsckCmd{}, + commands.FilterBranchCmd{}, + commands.MergeBaseCmd{}, + commands.RootsCmd{}, + commands.VersionCmd{VersionStr: doltversion.Version}, + commands.DumpCmd{}, + commands.InspectCmd{}, + dumpDocsCommand, + dumpZshCommand, + docscmds.Commands, + stashcmds.StashCommands, + &commands.Assist{}, + commands.ProfileCmd{}, + commands.QueryDiff{}, + commands.ReflogCmd{}, + commands.RebaseCmd{}, + commands.ArchiveCmd{}, + ci.Commands, +} + +var DoltCommand = cli.NewSubCommandHandler("dolt", "it's git for data", doltSubCommands) + +var globalArgParser = cli.CreateGlobalArgParser("dolt") + +var doc = cli.CommandDocumentationContent{ + ShortDesc: "Dolt is git for data", + LongDesc: `Dolt comprises of multiple subcommands that allow users to import, export, update, and manipulate data with SQL.`, + + Synopsis: []string{ + "[global flags] subcommand [subcommand arguments]", + }, +} +var globalDocs = cli.CommandDocsForCommandString("dolt", doc, globalArgParser) + +var globalSpecialMsg = ` +Dolt subcommands are in transition to using the flags listed below as global flags. +Not all subcommands use these flags. If your command accepts these flags without error, then they are supported. +` + +func init() { + dumpDocsCommand.DoltCommand = DoltCommand + dumpDocsCommand.GlobalDocs = globalDocs + dumpDocsCommand.GlobalSpecialMsg = globalSpecialMsg + dumpZshCommand.DoltCommand = DoltCommand +} diff --git a/go/libraries/doltcore/doltdb/system_table.go b/go/libraries/doltcore/doltdb/system_table.go index 7f560799022..e3eae4ea1c2 100644 --- a/go/libraries/doltcore/doltdb/system_table.go +++ b/go/libraries/doltcore/doltdb/system_table.go @@ -217,6 +217,7 @@ var getGeneratedSystemTables = func() []string { GetCommitAncestorsTableName(), GetStatusTableName(), GetRemotesTableName(), + GetHelpTableName(), } } @@ -380,6 +381,11 @@ var GetTagsTableName = func() string { return TagsTableName } +// GetHelpTableName returns the help table name +var GetHelpTableName = func() string { + return HelpTableName +} + const ( // LogTableName is the log system table name LogTableName = "dolt_log" @@ -585,3 +591,7 @@ const ( // was originally defined. Mode settings, such as ANSI_QUOTES, are needed to correctly parse the fragment. ProceduresTableSqlModeCol = "sql_mode" ) + +const ( + HelpTableName = "dolt_help" +) diff --git a/go/libraries/doltcore/sqle/database.go b/go/libraries/doltcore/sqle/database.go index 390f2e0c384..8f2c3fba880 100644 --- a/go/libraries/doltcore/sqle/database.go +++ b/go/libraries/doltcore/sqle/database.go @@ -714,6 +714,14 @@ func (db Database) getTableInsensitive(ctx *sql.Context, head *doltdb.Commit, ds return nil, false, err } dt = NewSchemaTable(backingTable) + case doltdb.GetHelpTableName(), doltdb.HelpTableName: + isDoltgresSystemTable, err := resolve.IsDoltgresSystemTable(ctx, tname, root) + if err != nil { + return nil, false, err + } + if !resolve.UseSearchPath || isDoltgresSystemTable { + dt, found = dtables.NewHelpTable(ctx, db.Name(), lwrName), true + } } if found { diff --git a/go/libraries/doltcore/sqle/dtables/help_table.go b/go/libraries/doltcore/sqle/dtables/help_table.go new file mode 100644 index 00000000000..d7a70967c01 --- /dev/null +++ b/go/libraries/doltcore/sqle/dtables/help_table.go @@ -0,0 +1,225 @@ +// Copyright 2025 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dtables + +import ( + "encoding/json" + "io" + "strings" + + "github.com/dolthub/dolt/go/cmd/dolt/cli" + "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dprocedures" + "github.com/dolthub/dolt/go/libraries/doltcore/sqle/index" + "github.com/dolthub/go-mysql-server/sql" + sqlTypes "github.com/dolthub/go-mysql-server/sql/types" +) + +type HelpTable struct { + dbName string + tableName string +} + +var HelpTableTypes = []string{ + "system_table", + "procedure", + "function", + "variable", +} + +// NewHelpTable creates a HelpTable +func NewHelpTable(_ *sql.Context, dbName, tableName string) sql.Table { + return &HelpTable{dbName: dbName, tableName: tableName} +} + +// Name is a sql.Table interface function which returns the name of the table. +func (ht *HelpTable) Name() string { + return ht.tableName +} + +// String is a sql.Table interface function which returns the name of the table. +func (ht *HelpTable) String() string { + return ht.tableName +} + +// Schema is a sql.Table interface function that gets the sql.Schema of the help system table. +func (ht *HelpTable) Schema() sql.Schema { + return []*sql.Column{ + { + Name: "name", + Type: sqlTypes.TinyText, + Source: ht.tableName, + PrimaryKey: true, + DatabaseSource: ht.dbName, + }, + { + Name: "type", + Type: sqlTypes.MustCreateEnumType(HelpTableTypes, sql.Collation_Default), + Source: ht.tableName, + PrimaryKey: false, + DatabaseSource: ht.dbName, + }, + { + Name: "synopsis", + Type: sqlTypes.LongText, + Source: ht.tableName, + PrimaryKey: false, + DatabaseSource: ht.dbName, + }, + { + Name: "short_description", + Type: sqlTypes.LongText, + Source: ht.tableName, + PrimaryKey: false, + DatabaseSource: ht.dbName, + }, + { + Name: "long_description", + Type: sqlTypes.LongText, + Source: ht.tableName, + PrimaryKey: false, + DatabaseSource: ht.dbName, + }, + { + Name: "arguments", + Type: sqlTypes.JSON, + Source: ht.tableName, + PrimaryKey: false, + DatabaseSource: ht.dbName, + }, + } +} + +// Collation implements the sql.Table interface. +func (ht *HelpTable) Collation() sql.CollationID { + return sql.Collation_Default +} + +// Partitions is a sql.Table interface function that returns a partition +// of the data. Currently the data is unpartitioned. +func (ht *HelpTable) Partitions(*sql.Context) (sql.PartitionIter, error) { + return index.SinglePartitionIterFromNomsMap(nil), nil +} + +// PartitionRows is a sql.Table interface function that gets a row iterator for a partition. +func (ht *HelpTable) PartitionRows(_ *sql.Context, _ sql.Partition) (sql.RowIter, error) { + return NewHelpRowIter(), nil +} + +type HelpRowIter struct { + idx int + rows []sql.Row +} + +func NewHelpRowIter() *HelpRowIter { + return &HelpRowIter{} +} + +// DoltCommand is set in cmd/dolt/dolt.go to avoid circular dependency. +var DoltCommand cli.SubCommandHandler + +func (itr *HelpRowIter) Next(_ *sql.Context) (sql.Row, error) { + if itr.rows == nil { + var err error + itr.rows, err = generateProcedureHelpRows(DoltCommand.Name(), DoltCommand) + if err != nil { + return nil, err + } + } + + if itr.idx >= len(itr.rows) { + return nil, io.EOF + } + + row := itr.rows[itr.idx] + itr.idx++ + + return row, nil +} + +func (itr *HelpRowIter) Close(_ *sql.Context) error { + return nil +} + +// generateProcedureHelpRows generates a sql row for each procedure that has an equivalent CLI command. +func generateProcedureHelpRows(cmdStr string, cmd cli.Command) ([]sql.Row, error) { + if hidCmd, ok := cmd.(cli.HiddenCommand); ok && hidCmd.Hidden() { + return []sql.Row{}, nil + } + + rows := []sql.Row{} + + procedureName := strings.ReplaceAll(cmdStr, "-", "_") + docs := cmd.Docs() + if procedureExists(procedureName) && docs != nil { + argsMap := map[string]string{} + for _, usage := range cli.OptionsUsageList(docs.ArgParser, cli.EmptyFormat) { + argsMap[usage[0]] = usage[1] + } + + argsJson, err := json.Marshal(argsMap) + if err != nil { + return nil, err + } + + synopsis, err := docs.GetSynopsis(cli.CliFormat) + if err != nil { + return nil, err + } + + synopsisWithCommand := make([]string, len(synopsis)) + cliName := strings.ReplaceAll(cmdStr, "_", " ") + for i := range synopsis { + synopsisWithCommand[i] = cliName + " " + synopsis[i] + } + + shortDesc := docs.GetShortDesc() + + longDesc, err := docs.GetLongDesc(cli.CliFormat) + if err != nil { + return nil, err + } + + rows = append(rows, sql.NewRow( + procedureName, + "procedure", + strings.Join(synopsisWithCommand, "\n"), + shortDesc, + longDesc, + string(argsJson), + )) + } + + if subCmdHandler, ok := cmd.(cli.SubCommandHandler); ok { + for _, subCmd := range subCmdHandler.Subcommands { + newRows, err := generateProcedureHelpRows(cmdStr+"_"+subCmd.Name(), subCmd) + if err != nil { + return nil, err + } + rows = append(rows, newRows...) + } + } + + return rows, nil +} + +// procedureExists returns whether |procedureName| is the name of a dolt procedure. +func procedureExists(procedureName string) bool { + for _, procedure := range dprocedures.DoltProcedures { + if procedure.Name == procedureName { + return true + } + } + return false +} diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go index 20043743b26..713c0dfa328 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go @@ -2052,3 +2052,9 @@ func TestDoltWorkspace(t *testing.T) { harness := newDoltEnginetestHarness(t) RunDoltWorkspaceTests(t, harness) } + +func TestDoltHelpSystemTable(t *testing.T) { + harness := newDoltHarness(t) + defer harness.Close() + RunDoltHelpSystemTableTests(t, harness) +} diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go index 0e83de5cca9..efd221635f4 100755 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go @@ -35,10 +35,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/dolthub/dolt/go/cmd/dolt/doltcmd" "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" "github.com/dolthub/dolt/go/libraries/doltcore/schema" "github.com/dolthub/dolt/go/libraries/doltcore/sqle" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" + "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dtables" "github.com/dolthub/dolt/go/store/datas" "github.com/dolthub/dolt/go/store/types" ) @@ -1985,3 +1987,15 @@ func RunDoltWorkspaceTests(t *testing.T, h DoltEnginetestHarness) { }() } } + +func RunDoltHelpSystemTableTests(t *testing.T, harness DoltEnginetestHarness) { + dtables.DoltCommand = doltcmd.DoltCommand + + for _, script := range DoltHelpScripts { + t.Run(script.Name, func(t *testing.T) { + harness = harness.NewHarness(t) + defer harness.Close() + enginetest.TestScript(t, harness, script) + }) + } +} diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index 7197c182af0..fd0aa37e0c3 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -7565,6 +7565,7 @@ var DoltSystemVariables = []queries.ScriptTest{ {"dolt_constraint_violations"}, {"dolt_constraint_violations_test"}, {"dolt_diff_test"}, + {"dolt_help"}, {"dolt_history_test"}, {"dolt_log"}, {"dolt_remote_branches"}, diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries_help.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries_help.go new file mode 100644 index 00000000000..6862ec1a5dc --- /dev/null +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries_help.go @@ -0,0 +1,191 @@ +// Copyright 2024 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package enginetest + +import ( + "github.com/dolthub/go-mysql-server/enginetest/queries" + "github.com/dolthub/go-mysql-server/sql" +) + +var DoltHelpScripts = []queries.ScriptTest{ + { + Name: "dolt_help arguments are valid json", + SetUpScript: []string{}, + Query: "select * from dolt_help where json_valid(arguments)=false;", + Expected: []sql.Row{}, + }, + { + Name: "dolt_help synopsis remains the same after multiple queries", + SetUpScript: []string{ + "set @InitialSynopsis=(select synopsis from dolt_help where name='dolt_branch')", + }, + Query: "select * from dolt_help where name='dolt_branch' and synopsis!=@InitialSynopsis", + Expected: []sql.Row{}, + }, + { + Name: "dolt_help names are correct", + SetUpScript: []string{}, + Query: "select name from dolt_help", + Expected: []sql.Row{ + {"dolt_add"}, + {"dolt_reset"}, + {"dolt_clean"}, + {"dolt_commit"}, + {"dolt_branch"}, + {"dolt_checkout"}, + {"dolt_merge"}, + {"dolt_conflicts_resolve"}, + {"dolt_cherry_pick"}, + {"dolt_revert"}, + {"dolt_clone"}, + {"dolt_fetch"}, + {"dolt_pull"}, + {"dolt_push"}, + {"dolt_remote"}, + {"dolt_backup"}, + {"dolt_tag"}, + {"dolt_gc"}, + {"dolt_rebase"}, + }, + }, + { + Name: "dolt_help types are correct", + SetUpScript: []string{}, + Assertions: []queries.ScriptTestAssertion{ + { + Query: "select type from dolt_help where name='dolt_rebase'", + Expected: []sql.Row{ + {"procedure"}, + }, + }, + { + Query: "select type from dolt_help where name='dolt_gc'", + Expected: []sql.Row{ + {"procedure"}, + }, + }, + { + Query: "select type from dolt_help where name='dolt_tag'", + Expected: []sql.Row{ + {"procedure"}, + }, + }, + }, + }, + { + Name: "dolt_help synopses are correct", + SetUpScript: []string{}, + Assertions: []queries.ScriptTestAssertion{ + { + Query: "select count(*) from dolt_help where name='dolt_conflicts_resolve' and synopsis like '%dolt conflicts resolve%table%'", + Expected: []sql.Row{ + {1}, + }, + }, + { + Query: "select count(*) from dolt_help where name='dolt_merge' and synopsis like '%dolt merge%branch%'", + Expected: []sql.Row{ + {1}, + }, + }, + { + Query: "select count(*) from dolt_help where name='dolt_branch' and synopsis like '%dolt branch%--list%'", + Expected: []sql.Row{ + {1}, + }, + }, + }, + }, + { + Name: "dolt_help short descriptions are correct", + SetUpScript: []string{}, + Assertions: []queries.ScriptTestAssertion{ + { + Query: "select short_description from dolt_help where name='dolt_clean'", + Expected: []sql.Row{ + {"Deletes untracked working tables"}, + }, + }, + { + Query: "select short_description from dolt_help where name='dolt_checkout'", + Expected: []sql.Row{ + {"Switch branches or restore working tree tables"}, + }, + }, + { + Query: "select short_description from dolt_help where name='dolt_fetch'", + Expected: []sql.Row{ + {"Download objects and refs from another repository"}, + }, + }, + }, + }, + + { + Name: "dolt_help long descriptions are correct", + SetUpScript: []string{}, + Assertions: []queries.ScriptTestAssertion{ + { + Query: "select count(*) from dolt_help where name='dolt_add' and long_description like '%updates the list of tables%'", + Expected: []sql.Row{ + {1}, + }, + }, + { + Query: "select count(*) from dolt_help where name='dolt_cherry_pick' and long_description like '%Applies the changes from an existing commit%'", + Expected: []sql.Row{ + {1}, + }, + }, + { + Query: "select count(*) from dolt_help where name='dolt_revert' and long_description like '%Removes the changes made in a commit%'", + Expected: []sql.Row{ + {1}, + }, + }, + }, + }, + + { + Name: "dolt_help arguments are correct", + SetUpScript: []string{}, + Assertions: []queries.ScriptTestAssertion{ + { + Query: "select count(*) from dolt_help where name='dolt_commit' and arguments like '%--amend%Amend previous commit%'", + Expected: []sql.Row{ + {1}, + }, + }, + { + Query: "select count(*) from dolt_help where name='dolt_commit' and arguments like '%--skip-empty%Only create a commit if there are staged changes%'", + Expected: []sql.Row{ + {1}, + }, + }, + { + Query: "select count(*) from dolt_help where name='dolt_rebase' and arguments like '%--continue%Continue an interactive rebase%'", + Expected: []sql.Row{ + {1}, + }, + }, + { + Query: "select count(*) from dolt_help where name='dolt_revert' and arguments like '%--author%Specify an explicit author%'", + Expected: []sql.Row{ + {1}, + }, + }, + }, + }, +} diff --git a/integration-tests/bats/ls.bats b/integration-tests/bats/ls.bats index 6841f4d3749..28f3c53eeb6 100755 --- a/integration-tests/bats/ls.bats +++ b/integration-tests/bats/ls.bats @@ -60,7 +60,7 @@ teardown() { @test "ls: --system shows system tables" { run dolt ls --system [ "$status" -eq 0 ] - [ "${#lines[@]}" -eq 22 ] + [ "${#lines[@]}" -eq 23 ] [[ "$output" =~ "System tables:" ]] || false [[ "$output" =~ "dolt_status" ]] || false [[ "$output" =~ "dolt_commits" ]] || false @@ -71,6 +71,7 @@ teardown() { [[ "$output" =~ "dolt_remotes" ]] || false [[ "$output" =~ "dolt_branches" ]] || false [[ "$output" =~ "dolt_remote_branches" ]] || false + [[ "$output" =~ "dolt_help" ]] || false [[ "$output" =~ "dolt_constraint_violations_table_one" ]] || false [[ "$output" =~ "dolt_history_table_one" ]] || false [[ "$output" =~ "dolt_conflicts_table_one" ]] || false diff --git a/integration-tests/bats/system-tables.bats b/integration-tests/bats/system-tables.bats index 95e0455f298..5ed19accf29 100644 --- a/integration-tests/bats/system-tables.bats +++ b/integration-tests/bats/system-tables.bats @@ -36,6 +36,7 @@ teardown() { [[ "$output" =~ "dolt_remote_branches" ]] || false [[ "$output" =~ "dolt_remotes" ]] || false [[ "$output" =~ "dolt_status" ]] || false + [[ "$output" =~ "dolt_help" ]] || false [[ "$output" =~ "test" ]] || false dolt add test @@ -620,3 +621,33 @@ SQL [ "$status" -eq 0 ] [ "$output" = "" ] } + +@test "system-tables: query dolt_help system table" { + run dolt sql -q "select type from dolt_help where name='dolt_rebase'" + [ "$status" -eq 0 ] + [[ "$output" =~ "procedure" ]] || false + + run dolt sql -q "select synopsis from dolt_help where name='dolt_backup'" + [ "$status" -eq 0 ] + [[ "$output" =~ "dolt backup [-v | --verbose]" ]] || false + [[ "$output" =~ "dolt backup restore [--force] " ]] || false + + run dolt sql -q "select short_description from dolt_help where name='dolt_commit'" + [ "$status" -eq 0 ] + [[ "$output" =~ "Record changes to the database" ]] || false + + run dolt sql -q "select long_description from dolt_help where name='dolt_add'" + [ "$status" -eq 0 ] + [[ "$output" =~ "This command updates the list of tables using the current content found in the working root" ]] || false + [[ "$output" =~ "This command can be performed multiple times before a commit." ]] || false + + run dolt sql -q "select arguments from dolt_help where name='dolt_pull'" + [ "$status" -eq 0 ] + [[ "$output" =~ "".*"The name of the remote to pull from." ]] || false + [[ "$output" =~ "".*"The name of a branch on the specified remote to be merged into the current working set." ]] || false + [[ "$output" =~ "-f, --force".*"Update from the remote HEAD even if there are errors." ]] || false + + run dolt sql -q "select arguments from dolt_help where name='dolt_tag'" + [ "$status" -eq 0 ] + [[ "$output" =~ "-m , --message=".*"Use the given msg as the tag message." ]] || false +}