Skip to content

Commit

Permalink
Merge pull request #54 from kitagry/complete-builtin-function
Browse files Browse the repository at this point in the history
Complete builtin function
  • Loading branch information
kitagry authored Aug 27, 2023
2 parents 223c583 + 5c5e320 commit f392758
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 40 deletions.
36 changes: 36 additions & 0 deletions langserver/internal/source/completion/builtin_function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package completion

import (
"context"
"strings"

"github.com/goccy/go-zetasql/ast"
"github.com/kitagry/bqls/langserver/internal/function"
"github.com/kitagry/bqls/langserver/internal/lsp"
"github.com/kitagry/bqls/langserver/internal/source/file"
)

func (c *completor) completeBuiltinFunction(ctx context.Context, parsedFile file.ParsedFile, position lsp.Position) []CompletionItem {
termOffset := parsedFile.TermOffset(position)

// When the cursor is in the middle of the table path, do not suggest the built-in functions.
tablePathNode, ok := file.SearchAstNode[*ast.TablePathExpressionNode](parsedFile.Node, parsedFile.TermOffset(position))
if ok && tablePathNode.ParseLocationRange().End().ByteOffset() != termOffset {
return []CompletionItem{}
}

incompleteColumnName := parsedFile.FindIncompleteColumnName(position)

result := make([]CompletionItem, 0)
for _, f := range function.BuiltInFunctions {
if strings.HasPrefix(f.Name, incompleteColumnName) {
result = append(result, CompletionItem{
Kind: lsp.CIKFunction,
NewText: f.Name,
TypedPrefix: incompleteColumnName,
Documentation: f.Description,
})
}
}
return result
}
61 changes: 61 additions & 0 deletions langserver/internal/source/completion/builtin_function_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package completion

import (
"context"
"testing"

bq "cloud.google.com/go/bigquery"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/kitagry/bqls/langserver/internal/bigquery"
"github.com/kitagry/bqls/langserver/internal/bigquery/mock_bigquery"
"github.com/kitagry/bqls/langserver/internal/source/file"
"github.com/kitagry/bqls/langserver/internal/source/helper"
"github.com/sirupsen/logrus"
)

func TestCompletor_CompleteBuiltinFunction(t *testing.T) {
tests := map[string]struct {
files map[string]string
bigqueryClientMockFunc func(t *testing.T) bigquery.Client

expectCompletionItems []CompletionItem
}{
"Don't complete in table completion": {
files: map[string]string{
"file1.sql": "SELECT FROM `bigquery-public-data.samples.|`\n",
},
bigqueryClientMockFunc: func(t *testing.T) bigquery.Client {
ctrl := gomock.NewController(t)
bqClient := mock_bigquery.NewMockClient(ctrl)

bqClient.EXPECT().GetTableMetadata(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&bq.TableMetadata{}, nil).MinTimes(0)
return bqClient
},
expectCompletionItems: []CompletionItem{}, // empty
},
}

for n, tt := range tests {
t.Run(n, func(t *testing.T) {
bqClient := tt.bigqueryClientMockFunc(t)
logger := logrus.New()
logger.SetLevel(logrus.DebugLevel)

analyzer := file.NewAnalyzer(bqClient)
completor := New(logger, analyzer, bqClient)

files, path, position, err := helper.GetLspPosition(tt.files)
if err != nil {
t.Fatal(err)
}

parsedFile := analyzer.ParseFile(path, files[path])

got := completor.completeBuiltinFunction(context.Background(), parsedFile, position)
if diff := cmp.Diff(got, tt.expectCompletionItems); diff != "" {
t.Errorf("(-got, +want)\n%s", diff)
}
})
}
}
10 changes: 10 additions & 0 deletions langserver/internal/source/completion/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ func New(logger *logrus.Logger, analyzer *file.Analyzer, bqClient bigquery.Clien
}

func (c *completor) Complete(ctx context.Context, parsedFile file.ParsedFile, position lsp.Position) ([]CompletionItem, error) {
result, err := c.completeFromSQLContext(ctx, parsedFile, position)
if err != nil {
return result, err
}

result = append(result, c.completeBuiltinFunction(ctx, parsedFile, position)...)
return result, nil
}

func (c *completor) completeFromSQLContext(ctx context.Context, parsedFile file.ParsedFile, position lsp.Position) ([]CompletionItem, error) {
termOffset := parsedFile.TermOffset(position)

// cursor is on table name
Expand Down
Loading

0 comments on commit f392758

Please sign in to comment.