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

API refactoring: move query function to Database interface #93

Merged
merged 4 commits into from
Oct 21, 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
36 changes: 18 additions & 18 deletions .github/workflows/ci.yml → .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI
name: Test

on:
workflow_dispatch:
Expand All @@ -10,7 +10,7 @@ on:
pull_request:

jobs:
build:
coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -19,7 +19,7 @@ jobs:
uses: actions/setup-go@v5
with:
go-version: 1.22.x
- name: Check build
- name: Build
run: |
go version
pwd && ls -l
Expand All @@ -32,6 +32,21 @@ jobs:
--with $MODULE_NAME="."
./k6ext version

- name: Test
if: ${{ github.ref_name == 'main' }}
run: go test -count 1 -coverprofile=coverage.txt ./...

- name: Upload Coverage
if: ${{ github.ref_name == 'main' }}
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: grafana/xk6-sql

- name: Generate Go Report Card
if: ${{ github.ref_name == 'main' }}
uses: creekorful/[email protected]

test:
strategy:
fail-fast: false
Expand All @@ -51,18 +66,3 @@ jobs:
which go
go version
go test -race -timeout 60s ./...

- name: Coverage Test
if: ${{ matrix.platform == 'ubuntu-latest' && github.ref_name == 'main' }}
run: go test -count 1 -coverprofile=coverage.txt ./...

- name: Upload Coverage
if: ${{ matrix.platform == 'ubuntu-latest' && github.ref_name == 'main' }}
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: grafana/xk6-sql

- name: Generate Go Report Card
if: ${{ matrix.platform == 'ubuntu-latest' && github.ref_name == 'main' }}
uses: creekorful/[email protected]
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[![API Reference](https://img.shields.io/badge/API-reference-blue?logo=readme&logoColor=lightgray)](https://sql.x.k6.io)
[![GitHub Release](https://img.shields.io/github/v/release/grafana/xk6-sql)](https://github.com/grafana/xk6-sql/releases/)
[![Go Report Card](https://goreportcard.com/badge/github.com/grafana/xk6-sql)](https://goreportcard.com/report/github.com/grafana/xk6-sql)
[![GitHub Actions](https://github.com/grafana/xk6-sql/actions/workflows/ci.yml/badge.svg)](https://github.com/grafana/xk6-sql/actions/workflows/ci.yml)
[![GitHub Actions](https://github.com/grafana/xk6-sql/actions/workflows/test.yml/badge.svg)](https://github.com/grafana/xk6-sql/actions/workflows/test.yml)
[![codecov](https://codecov.io/gh/grafana/xk6-sql/graph/badge.svg?token=DSkK7glKPq)](https://codecov.io/gh/grafana/xk6-sql)

# xk6-sql
Expand Down Expand Up @@ -53,7 +53,7 @@ export default function () {
`);
console.log(`${result.rowsAffected()} rows inserted`);

let rows = sql.query(db, "SELECT * FROM roster WHERE given_name = $1;", "Peter");
let rows = db.query("SELECT * FROM roster WHERE given_name = $1;", "Peter");
for (const row of rows) {
console.log(`${row.family_name}, ${row.given_name}`);
}
Expand All @@ -78,13 +78,13 @@ export default function () {
scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop):
* default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)

time="2024-10-21T14:38:58+02:00" level=info msg="4 rows inserted" source=console
time="2024-10-21T14:38:58+02:00" level=info msg="Pan, Peter" source=console
time="2024-10-21T15:47:50+02:00" level=info msg="4 rows inserted" source=console
time="2024-10-21T15:47:50+02:00" level=info msg="Pan, Peter" source=console

data_received........: 0 B 0 B/s
data_sent............: 0 B 0 B/s
iteration_duration...: avg=573.77µs min=573.77µs med=573.77µs max=573.77µs p(90)=573.77µs p(95)=573.77µs
iterations...........: 1 967.948327/s
iteration_duration...: avg=371.25µs min=371.25µs med=371.25µs max=371.25µs p(90)=371.25µs p(95)=371.25µs
iterations...........: 1 1061.969082/s


running (00m00.0s), 0/1 VUs, 1 complete and 0 interrupted iterations
Expand Down
2 changes: 1 addition & 1 deletion examples/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default function () {
`);
console.log(`${result.rowsAffected()} rows inserted`);

let rows = sql.query(db, "SELECT * FROM roster WHERE given_name = $1;", "Peter");
let rows = db.query("SELECT * FROM roster WHERE given_name = $1;", "Peter");
for (const row of rows) {
console.log(`${row.family_name}, ${row.given_name}`);
}
Expand Down
8 changes: 4 additions & 4 deletions examples/example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop):
* default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)

time="2024-10-21T14:54:42+02:00" level=info msg="4 rows inserted" source=console
time="2024-10-21T14:54:42+02:00" level=info msg="Pan, Peter" source=console
time="2024-10-21T15:47:50+02:00" level=info msg="4 rows inserted" source=console
time="2024-10-21T15:47:50+02:00" level=info msg="Pan, Peter" source=console

data_received........: 0 B 0 B/s
data_sent............: 0 B 0 B/s
iteration_duration...: avg=344.4µs min=344.4µs med=344.4µs max=344.4µs p(90)=344.4µs p(95)=344.4µs
iterations...........: 1 1076.071821/s
iteration_duration...: avg=371.25µs min=371.25µs med=371.25µs max=371.25µs p(90)=371.25µs p(95)=371.25µs
iterations...........: 1 1061.969082/s


running (00m00.0s), 0/1 VUs, 1 complete and 0 interrupted iterations
Expand Down
6 changes: 3 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
* `);
* console.log(`${result.rowsAffected()} rows inserted`);
*
* let rows = sql.query(db, "SELECT * FROM roster WHERE given_name = $1;", "Peter");
* let rows = db.query("SELECT * FROM roster WHERE given_name = $1;", "Peter");
* for (const row of rows) {
* console.log(`${row.family_name}, ${row.given_name}`);
* }
Expand Down Expand Up @@ -159,7 +159,7 @@ export interface Database {
* const db = sql.open(driver, "roster_db");
*
* export default function () {
* let rows = sql.query(db, "SELECT * FROM roster WHERE given_name = $1;", "Peter");
* let rows = db.query("SELECT * FROM roster WHERE given_name = $1;", "Peter");
* for (const row of results) {
* console.log(`${row.family_name}, ${row.given_name}`);
* }
Expand Down Expand Up @@ -189,7 +189,7 @@ export interface Row {
* const db = sql.open(driver, "roster_db");
*
* export default function () {
* let rows = sql.query(db, "SELECT * FROM roster WHERE given_name = $1;", "Peter");
* let rows = db.query("SELECT * FROM roster WHERE given_name = $1;", "Peter");
* for (const row of results) {
* console.log(`${row.family_name}, ${row.given_name}`);
* }
Expand Down
15 changes: 15 additions & 0 deletions register_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package sql

import (
"testing"

"github.com/grafana/xk6-sql/sql"
"github.com/stretchr/testify/require"
"go.k6.io/k6/ext"
)

func Test_register(t *testing.T) {
t.Parallel()

require.Contains(t, ext.Get(ext.JSExtension), sql.ImportPath)
}
29 changes: 21 additions & 8 deletions sql/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ func (*rootModule) NewModuleInstance(_ modules.VU) modules.Instance {

instance.exports.Default = instance
instance.exports.Named = map[string]interface{}{
"open": instance.Open,
"query": instance.Query,
"open": instance.Open,
}

return instance
Expand All @@ -51,7 +50,7 @@ type KeyValue map[string]interface{}

// open establishes a connection to the specified database type using
// the provided connection string.
func (mod *module) Open(driverID sobek.Value, connectionString string) (*sql.DB, error) {
func (mod *module) Open(driverID sobek.Value, connectionString string) (*Database, error) {
driverSym, ok := driverID.(*sobek.Symbol)
if !ok {
return nil, fmt.Errorf("%w: invalid driver parameter type", errUnsupportedDatabase)
Expand All @@ -67,13 +66,17 @@ func (mod *module) Open(driverID sobek.Value, connectionString string) (*sql.DB,
return nil, err
}

return db, nil
return &Database{db: db}, nil
}

// query executes the provided query string against the database, while
// providing results as a slice of KeyValue instance(s) if available.
func (*module) Query(db *sql.DB, query string, args ...interface{}) ([]KeyValue, error) {
rows, err := db.Query(query, args...)
// Database is a database handle representing a pool of zero or more underlying connections.
type Database struct {
db *sql.DB
}

// Query executes a query that returns rows, typically a SELECT.
func (dbase *Database) Query(query string, args ...interface{}) ([]KeyValue, error) {
rows, err := dbase.db.Query(query, args...)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -114,4 +117,14 @@ func (*module) Query(db *sql.DB, query string, args ...interface{}) ([]KeyValue,
return result, nil
}

// Exec a query without returning any rows.
func (dbase *Database) Exec(query string, args ...interface{}) (sql.Result, error) {
return dbase.db.Exec(query, args...)
}

// Close the database and prevents new queries from starting.
func (dbase *Database) Close() error {
return dbase.db.Close()
}

var errUnsupportedDatabase = errors.New("unsupported database")
28 changes: 28 additions & 0 deletions sql/sql_internal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package sql

import (
"testing"

"github.com/grafana/sobek"
"github.com/stretchr/testify/require"
)

func TestOpen(t *testing.T) { //nolint: paralleltest
mod := New().NewModuleInstance(nil).(*module)

driver := RegisterDriver("ramsql")
require.NotNil(t, driver)

db, err := mod.Open(driver, "")

require.NoError(t, err)
require.NotNil(t, db)

_, err = mod.Open(sobek.New().ToValue("foo"), "testdb") // not a Symbol

require.Error(t, err)

_, err = mod.Open(sobek.NewSymbol("ramsql"), "testdb") // not a registered Symbol

require.Error(t, err)
}
6 changes: 3 additions & 3 deletions sql/testdata/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ for (let i = 0; i < 5; i++) {
db.exec("INSERT INTO test_table (name, value) VALUES ('name-" + i + "', 'value-" + i + "');");
}

let all_rows = sql.query(db, "SELECT * FROM test_table;");
let all_rows = db.query("SELECT * FROM test_table;");
if (all_rows.length != 5) {
throw new Error("Expected all five rows to be returned; got " + all_rows.length);
}

let one_row = sql.query(db, "SELECT * FROM test_table WHERE name = $1;", "name-2");
let one_row = db.query("SELECT * FROM test_table WHERE name = $1;", "name-2");
if (one_row.length != 1) {
throw new Error("Expected single row to be returned; got " + one_row.length);
}

let no_rows = sql.query(db, "SELECT * FROM test_table WHERE name = $1;", "bogus-name");
let no_rows = db.query("SELECT * FROM test_table WHERE name = $1;", "bogus-name");
if (no_rows.length != 0) {
throw new Error("Expected no rows to be returned; got " + no_rows.length);
}
Expand Down
22 changes: 22 additions & 0 deletions sqltest/sqltest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package sqltest_test

import (
_ "embed"
"testing"

"github.com/grafana/xk6-sql/sql"
"github.com/grafana/xk6-sql/sqltest"

_ "github.com/proullon/ramsql/driver"
)

//go:embed testdata/script.js
var script string

func TestRunScript(t *testing.T) {
t.Parallel()

sql.RegisterModule("ramsql")

sqltest.RunScript(t, "ramsql", "testdb", script)
}
24 changes: 24 additions & 0 deletions sqltest/testdata/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const db = sql.open(driver, connection);

db.exec("CREATE TABLE test_table (id integer PRIMARY KEY AUTOINCREMENT, name varchar NOT NULL, value varchar);");

for (let i = 0; i < 5; i++) {
db.exec("INSERT INTO test_table (name, value) VALUES ('name-" + i + "', 'value-" + i + "');");
}

let all_rows = db.query("SELECT * FROM test_table;");
if (all_rows.length != 5) {
throw new Error("Expected all five rows to be returned; got " + all_rows.length);
}

let one_row = db.query("SELECT * FROM test_table WHERE name = $1;", "name-2");
if (one_row.length != 1) {
throw new Error("Expected single row to be returned; got " + one_row.length);
}

let no_rows = db.query("SELECT * FROM test_table WHERE name = $1;", "bogus-name");
if (no_rows.length != 0) {
throw new Error("Expected no rows to be returned; got " + no_rows.length);
}

db.close();
Loading