Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Add BigQuery support #2

Merged
merged 8 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,29 @@
#--------------------------------------------------#
# The following was generated with gitignore.nvim: #
#--------------------------------------------------#
# Gitignore for the following technologies: Go

# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work

test_build
tbd
55 changes: 41 additions & 14 deletions forms.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ type FormResponse struct {
Account string
Database string
Schema string
Project string
Dataset string
BuildDir string
GenerateDescriptions bool
GroqKeyEnvVar string
Expand All @@ -30,22 +32,21 @@ func Forms() (formResponse FormResponse) {
Description(`A sweet and speedy code generator for dbt.
tbd will generate source YAML config and SQL staging models for all the tables in the schema you specify.
To prepare, make sure you have the following:
* An existing dbt profile.yml file to reference
OR
✴︎ *_Username_* (e.g. [email protected])
✴︎ *_Account ID_* (e.g. elfstone-consulting.us-west-1)
✴︎ *_Schema_* you want to generate (e.g. minas-tirith)
✴︎ *_Database_* that schema is in (e.g. gondor)
Authentication will be handled via SSO in the web browser.
For security, we don't currently support password-based authentication.`),
✴︎ An existing dbt profile.yml file to reference
**OR**
✴︎ The necessary connection details for your warehouse
_Authentication will be handled via SSO._
_For security, we don't support password auth._`),
),
huh.NewGroup(
huh.NewNote().
Title("⚠️ Experimental Feature: LLM Generation 🦙✨").
Description(`I'm currently exploring *_optional_* LLM-powered alpha features.
At present this is limited to generating column descriptions and inferring tests via Groq.
You'll need:
✴︎ A Groq API key stored in an environment variable.`),
✴︎ A Groq API key stored in an env var`),
huh.NewConfirm().Affirmative("Sure!").Negative("Nope").
Title("Do you want to generate column descriptions and tests via LLM?").
Value(&formResponse.GenerateDescriptions),
Expand All @@ -68,15 +69,19 @@ You'll need:
Placeholder("dev"),
),
)
manual_form := huh.NewForm(
warehouse_form := huh.NewForm(
huh.NewGroup(
huh.NewSelect[string]().
Title("Choose your warehouse.").
Options(
huh.NewOption("Snowflake", "snowflake"),
huh.NewOption("BigQuery", "bigquery"),
).
Value(&formResponse.Warehouse),

),
)
snowflake_form := huh.NewForm(
huh.NewGroup(
huh.NewInput().
Title("What is your username?").
Value(&formResponse.Username).Placeholder("[email protected]"),
Expand All @@ -94,6 +99,14 @@ You'll need:
Value(&formResponse.Database).Placeholder("gondor"),
),
)
bigquery_form := huh.NewForm(
huh.NewGroup(
huh.NewInput().Title("What is your GCP project's id?").
Value(&formResponse.Project).Placeholder("legolas_inc"),
huh.NewInput().Title("What is the dataset you want to generate?").
Value(&formResponse.Dataset).Placeholder("mirkwood"),
),
)
llm_form := huh.NewForm(
huh.NewGroup(
huh.NewInput().
Expand Down Expand Up @@ -125,7 +138,9 @@ If you use an existing directory, tbd will overwrite any existing files with the
)
intro_form.WithTheme(huh.ThemeCatppuccin())
dbt_form.WithTheme(huh.ThemeCatppuccin())
manual_form.WithTheme(huh.ThemeCatppuccin())
warehouse_form.WithTheme(huh.ThemeCatppuccin())
snowflake_form.WithTheme(huh.ThemeCatppuccin())
bigquery_form.WithTheme(huh.ThemeCatppuccin())
llm_form.WithTheme(huh.ThemeCatppuccin())
dir_form.WithTheme(huh.ThemeCatppuccin())
confirm_form.WithTheme(huh.ThemeCatppuccin())
Expand All @@ -136,10 +151,22 @@ If you use an existing directory, tbd will overwrite any existing files with the
if formResponse.UseDbtProfile {
err = dbt_form.Run()
} else {
err = manual_form.Run()
err = warehouse_form.Run()
switch formResponse.Warehouse {
case "snowflake":
err = snowflake_form.Run()
if err != nil {
log.Fatalf("Error running snowflake form %v\n", err)
}
case "bigquery":
err = bigquery_form.Run()
if err != nil {
log.Fatalf("Error running bigquery form %v\n", err)
}
}
}
if err != nil {
log.Fatalf("Error running connectiond details form %v\n", err)
log.Fatalf("Error running connection details form %v\n", err)
}
if formResponse.GenerateDescriptions {
err = llm_form.Run()
Expand Down
35 changes: 5 additions & 30 deletions get_dbt_profile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,15 @@ package main

import (
"os"
"path/filepath"
"testing"
)

func TestGetDbtProfile(t *testing.T) {
// Create a temporary profiles.yml file for testing
tmpDir := t.TempDir()
err := os.Mkdir(filepath.Join(tmpDir, ".dbt"), 0755)
if err != nil {
t.Fatalf("Failed to create temporary .dbt directory: %v", err)
}
profilesFile := filepath.Join(tmpDir, ".dbt", "profiles.yml")
content := []byte(`
test_profile:
target: dev
outputs:
dev:
type: snowflake
account: testaccount
user: testuser
password: testpassword
database: testdb
warehouse: testwh
schema: testschema
`)
err = os.WriteFile(profilesFile, content, 0644)
if err != nil {
t.Fatalf("Failed to create temporary profiles.yml file: %v", err)
}

os.Setenv("HOME", tmpDir)

CreateTempDbtProfile(t)
defer os.RemoveAll(os.Getenv("HOME"))
defer os.Unsetenv("HOME")
// Profile exists
profile, err := GetDbtProfile("test_profile")
profile, err := GetDbtProfile("elf")
if err != nil {
t.Errorf("GetDbtProfile returned an error for an existing profile: %v", err)
}
Expand All @@ -44,7 +19,7 @@ test_profile:
}

// Profile does not exist
profile, err = GetDbtProfile("aragorn")
profile, err = GetDbtProfile("dunedain")
if err == nil {
t.Error("GetDbtProfile did not return an error for a non-existing profile")
}
Expand Down
39 changes: 35 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,25 @@ go 1.22.0
require (
github.com/charmbracelet/huh v0.3.1-0.20240306161957-71f31c155b08
github.com/charmbracelet/huh/spinner v0.0.0-20240306161957-71f31c155b08
github.com/snowflakedb/gosnowflake v1.8.0
github.com/snowflakedb/gosnowflake v1.9.0
gopkg.in/yaml.v2 v2.4.0
)

require (
cloud.google.com/go v0.112.1 // indirect
cloud.google.com/go/bigquery v1.60.0 // indirect
cloud.google.com/go/compute v1.24.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.7 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.0 // indirect
github.com/DATA-DOG/go-sqlmock v1.5.2 // indirect
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
github.com/apache/arrow/go/v14 v14.0.2 // indirect
github.com/apache/arrow/go/v15 v15.0.0 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aws/aws-sdk-go-v2 v1.25.2 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 // indirect
Expand All @@ -41,12 +48,21 @@ require (
github.com/danieljoos/wincred v1.2.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/flatbuffers v23.5.26+incompatible // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/compress v1.17.7 // indirect
Expand All @@ -66,14 +82,29 @@ require (
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
golang.org/x/crypto v0.19.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.18.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/api v0.170.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
google.golang.org/grpc v1.62.1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
Loading