Skip to content

Commit

Permalink
add database persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
danicat committed Jul 15, 2024
1 parent d2c666d commit 9f386c3
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.PHONY: build
build:
go build -o bin/tq
go build -o bin/tq -ldflags="-X 'main.Version=v0.1'"

.PHONY: test
test: build
Expand Down
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,45 @@ It is currently under development so it doesn't support a lot of information yet

## Usage

Disclaimer: this tool is currently a prototype that has been through no more than 48 hours of active development, so use it at your own risk. Ironically, I haven't written any tests for it `:)`
```sh
% tq --help
Usage of tq:
-dbfile string
database file name for use with --persist and --open (default "testquery.db")
-open
open a database from a previous run
-persist
persist database between runs
-pkg string
directory of the package to test (default ".")
-query string
runs a single query and returns the result

```
By default tq will launch in iterative mode unless you pass a `--query` flag:

```sh
% tq --persist --open --query "select * from code_coverage where file = 'div.go'"
+--------+-------------+-----------------------------------------------------------+---------+
| FILE | LINE_NUMBER | CONTENT | COVERED |
+--------+-------------+-----------------------------------------------------------+---------+
| div.go | 1 | package testdata | 0 |
| div.go | 2 | | 0 |
| div.go | 3 | import "errors" | 0 |
| div.go | 4 | | 0 |
| div.go | 5 | var ErrDivideByZero = errors.New("cannot divide by zero") | 0 |
| div.go | 6 | | 0 |
| div.go | 7 | func divide(dividend, divisor int) (int, error) { | 1 |
| div.go | 8 | if divisor == 0 { | 1 |
| div.go | 9 | return 0, ErrDivideByZero | 1 |
| div.go | 10 | } | 1 |
| div.go | 11 | | 0 |
| div.go | 12 | return dividend / divisor, nil | 1 |
| div.go | 13 | } | 0 |
| div.go | 14 | | 0 |
+--------+-------------+-----------------------------------------------------------+---------+
```
To use it, compile the code with `make build` (or `go build` if you are being wild) and run `tq` from the command line. By default `tq` will run data collection on the current directory but you can pass a package to it by using the `--pkg` flag.
Expand Down
9 changes: 9 additions & 0 deletions data.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,12 @@ func populateTables(ctx context.Context, db *sql.DB, pkgDir string) error {

return nil
}

func persistDatabase(db *sql.DB, dbFile string) error {
_, err := db.Exec("VACUUM INTO ?", dbFile)
if err != nil {
return fmt.Errorf("failed to save database file: %w", err)
}

return nil
}
59 changes: 44 additions & 15 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,75 @@ import (
"github.com/jedib0t/go-pretty/v6/table"
)

var Version = "dev"

func main() {
pkgDir := flag.String("pkg", ".", "directory of the package to test")
persist := flag.Bool("persist", false, "persist database between runs")
dbFile := flag.String("dbfile", "testquery.db", "database file name for use with --persist and --open")
openDB := flag.Bool("open", false, "open a database from a previous run")
query := flag.String("query", "", "runs a single query and returns the result")
version := flag.Bool("version", false, "shows version information")
flag.Parse()

if *version {
fmt.Println("tq", Version)
return
}

ctx := context.Background()

rl, err := readline.NewEx(&readline.Config{
Prompt: "> ",
HistoryFile: "/tmp/readline-multiline",
HistoryFile: "/tmp/testquery-history",
DisableAutoSaveHistory: true,
})
if err != nil {
log.Fatalln(err)
}
defer rl.Close()

err = run(ctx, *pkgDir, rl)
err = run(ctx, *pkgDir, rl, *persist, *openDB, *dbFile, *query)
if err != nil && !errors.Is(err, io.EOF) && !errors.Is(err, context.Canceled) {
log.Fatalln(err)
}
}

func run(ctx context.Context, pkgDir string, rl *readline.Instance) error {
// Initialize the in-memory SQLite database
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
return fmt.Errorf("failed to instantiate sqlite: %w", err)
}
defer db.Close()
func run(ctx context.Context, pkgDir string, rl *readline.Instance, persist, open bool, dbFile string, query string) error {
var db *sql.DB
var err error

err = createTables(ctx, db)
if err != nil {
return fmt.Errorf("failed to apply ddl: %w", err)
if open {
db, err = sql.Open("sqlite3", dbFile)
if err != nil {
return fmt.Errorf("failed to open database: %w", err)
}
defer db.Close()
} else {
db, err = sql.Open("sqlite3", ":memory:")
if err != nil {
return fmt.Errorf("failed to instantiate sqlite: %w", err)
}
defer db.Close()

err = createTables(ctx, db)
if err != nil {
return fmt.Errorf("failed to apply ddl: %w", err)
}

err = populateTables(ctx, db, pkgDir)
if err != nil {
return fmt.Errorf("failed to populate tables: %w", err)
}
}

err = populateTables(ctx, db, pkgDir)
if err != nil {
return fmt.Errorf("failed to populate tables: %w", err)
if persist {
defer persistDatabase(db, dbFile)
}

if query != "" {
return executeQuery(db, query)
}
return prompt(ctx, db, rl)
}

Expand Down
4 changes: 3 additions & 1 deletion sql/queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ select function_name, file, start_line, end_line from missing_coverage;
select test_name, function_name, start_line, end_line count from test_coverage where count > 0;
select file, line_number, content from all_code limit 10;

select file, line_number, content from all_code where (file, line_number) in (select file, start_line from test_coverage where count = 0);
select file, line_number, content from all_code where (file, line_number) in (select file, start_line from test_coverage where count = 0);

select distinct ac.file, line_number, content, ifnull(count, 0) covered from all_code ac left join all_coverage cov on ac.file = cov.file and ac.line_number between cov.start_line and cov.end_line where ac.file not like '%_test.go';
5 changes: 4 additions & 1 deletion sql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,7 @@ select package, test
create view missing_coverage as
select package, function_name, file, start_line, start_col, end_line, end_col
from all_coverage
where count = 0;
where count = 0;

create view code_coverage as
select distinct ac.file, line_number, content, ifnull(count, 0) covered from all_code ac left join all_coverage cov on ac.file = cov.file and ac.line_number between cov.start_line and cov.end_line where ac.file not like '%_test.go';

0 comments on commit 9f386c3

Please sign in to comment.