diff --git a/examples/authors/sqlc.json b/examples/authors/sqlc.json index 58feec2d4c..b482424b71 100644 --- a/examples/authors/sqlc.json +++ b/examples/authors/sqlc.json @@ -22,6 +22,17 @@ "out": "mysql" } } + }, + { + "schema": "sqlite/schema.sql", + "queries": "sqlite/query.sql", + "engine": "_lemon", + "gen": { + "go": { + "package": "authors", + "out": "sqlite" + } + } } ] -} +} \ No newline at end of file diff --git a/examples/authors/sqlite/db.go b/examples/authors/sqlite/db.go new file mode 100644 index 0000000000..c78f28adbd --- /dev/null +++ b/examples/authors/sqlite/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package authors + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/examples/authors/sqlite/db_test.go b/examples/authors/sqlite/db_test.go new file mode 100644 index 0000000000..db5326b79d --- /dev/null +++ b/examples/authors/sqlite/db_test.go @@ -0,0 +1,48 @@ +//go:build examples +// +build examples + +package authors + +import ( + "context" + "database/sql" + "testing" + + "github.com/kyleconroy/sqlc/internal/sqltest" +) + +func TestAuthors(t *testing.T) { + sdb, cleanup := sqltest.SQLite(t, []string{"schema.sql"}) + defer cleanup() + + ctx := context.Background() + db := New(sdb) + + // list all authors + authors, err := db.ListAuthors(ctx) + if err != nil { + t.Fatal(err) + } + t.Log(authors) + + // create an author + result, err := db.CreateAuthor(ctx, CreateAuthorParams{ + Name: "Brian Kernighan", + Bio: sql.NullString{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true}, + }) + if err != nil { + t.Fatal(err) + } + authorID, err := result.LastInsertId() + if err != nil { + t.Fatal(err) + } + t.Log(authorID) + + // get the author we just inserted + fetchedAuthor, err := db.GetAuthor(ctx, authorID) + if err != nil { + t.Fatal(err) + } + t.Log(fetchedAuthor) +} diff --git a/examples/authors/sqlite/models.go b/examples/authors/sqlite/models.go new file mode 100644 index 0000000000..f1aefb0be2 --- /dev/null +++ b/examples/authors/sqlite/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package authors + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} diff --git a/examples/authors/sqlite/query.sql b/examples/authors/sqlite/query.sql new file mode 100644 index 0000000000..c3b5866149 --- /dev/null +++ b/examples/authors/sqlite/query.sql @@ -0,0 +1,18 @@ +/* name: GetAuthor :one */ +SELECT * FROM authors +WHERE id = ? LIMIT 1; + +/* name: ListAuthors :many */ +SELECT * FROM authors +ORDER BY name; + +/* name: CreateAuthor :execresult */ +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +); + +/* name: DeleteAuthor :exec */ +DELETE FROM authors +WHERE id = ?; diff --git a/examples/authors/sqlite/query.sql.go b/examples/authors/sqlite/query.sql.go new file mode 100644 index 0000000000..6247b79ecb --- /dev/null +++ b/examples/authors/sqlite/query.sql.go @@ -0,0 +1,78 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package authors + +import ( + "context" + "database/sql" +) + +const createAuthor = `-- name: CreateAuthor :execresult +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +) +` + +type CreateAuthorParams struct { + Name string + Bio sql.NullString +} + +func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createAuthor, arg.Name, arg.Bio) +} + +const deleteAuthor = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ? +` + +func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, deleteAuthor, id) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = ? LIMIT 1 +` + +func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const listAuthors = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name +` + +func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { + rows, err := q.db.QueryContext(ctx, listAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Author + for rows.Next() { + var i Author + if err := rows.Scan(&i.ID, &i.Name, &i.Bio); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/examples/authors/sqlite/schema.sql b/examples/authors/sqlite/schema.sql new file mode 100644 index 0000000000..9b81ece0e4 --- /dev/null +++ b/examples/authors/sqlite/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE authors ( + id integer PRIMARY KEY AUTOINCREMENT, + name text NOT NULL, + bio text +); diff --git a/examples/booktest/sqlc.json b/examples/booktest/sqlc.json index 419a759f19..4514428845 100644 --- a/examples/booktest/sqlc.json +++ b/examples/booktest/sqlc.json @@ -14,6 +14,13 @@ "schema": "mysql/schema.sql", "queries": "mysql/query.sql", "engine": "mysql" + }, + { + "name": "booktest", + "path": "sqlite", + "schema": "sqlite/schema.sql", + "queries": "sqlite/query.sql", + "engine": "_lemon" } ] -} +} \ No newline at end of file diff --git a/examples/booktest/sqlite/db.go b/examples/booktest/sqlite/db.go new file mode 100644 index 0000000000..89be65c809 --- /dev/null +++ b/examples/booktest/sqlite/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package booktest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/examples/booktest/sqlite/db_test.go b/examples/booktest/sqlite/db_test.go new file mode 100644 index 0000000000..da4a4ac025 --- /dev/null +++ b/examples/booktest/sqlite/db_test.go @@ -0,0 +1,174 @@ +//go:build examples +// +build examples + +package booktest + +import ( + "context" + "testing" + "time" + + "github.com/kyleconroy/sqlc/internal/sqltest" +) + +// TODO: Enum is not yet supported +const ( + BooksBookTypeFICTION string = "FICTION" + BooksBookTypeNONFICTION string = "NONFICTION" +) + +func TestBooks(t *testing.T) { + db, cleanup := sqltest.SQLite(t, []string{"schema.sql"}) + defer cleanup() + + ctx := context.Background() + dq := New(db) + + // create an author + result, err := dq.CreateAuthor(ctx, "Unknown Master") + if err != nil { + t.Fatal(err) + } + authorID, err := result.LastInsertId() + if err != nil { + t.Fatal(err) + } + + // create transaction + tx, err := db.Begin() + if err != nil { + t.Fatal(err) + } + + tq := dq.WithTx(tx) + + // save first book + now := time.Now() + _, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: int64(authorID), + Isbn: "1", + Title: "my book title", + BookType: BooksBookTypeFICTION, + Yr: 2016, + Available: now, + }) + if err != nil { + t.Fatal(err) + } + + // save second book + result, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: int64(authorID), + Isbn: "2", + Title: "the second book", + BookType: BooksBookTypeFICTION, + Yr: 2016, + Available: now, + Tags: "cool,unique", + }) + if err != nil { + t.Fatal(err) + } + bookOneID, err := result.LastInsertId() + if err != nil { + t.Fatal(err) + } + + // update the title and tags + err = tq.UpdateBook(ctx, UpdateBookParams{ + BookID: int64(bookOneID), + Title: "changed second title", + Tags: "cool,disastor", + }) + if err != nil { + t.Fatal(err) + } + + // save third book + _, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: int64(authorID), + Isbn: "3", + Title: "the third book", + BookType: BooksBookTypeFICTION, + Yr: 2001, + Available: now, + Tags: "cool", + }) + if err != nil { + t.Fatal(err) + } + + // save fourth book + result, err = tq.CreateBook(ctx, CreateBookParams{ + AuthorID: int64(authorID), + Isbn: "4", + Title: "4th place finisher", + BookType: BooksBookTypeFICTION, + Yr: 2011, + Available: now, + Tags: "other", + }) + if err != nil { + t.Fatal(err) + } + bookThreeID, err := result.LastInsertId() + if err != nil { + t.Fatal(err) + } + + // tx commit + err = tx.Commit() + if err != nil { + t.Fatal(err) + } + + // upsert, changing ISBN and title + err = dq.UpdateBookISBN(ctx, UpdateBookISBNParams{ + BookID: int64(bookThreeID), + Isbn: "NEW ISBN", + Title: "never ever gonna finish, a quatrain", + Tags: "someother", + }) + if err != nil { + t.Fatal(err) + } + + // retrieve first book + books0, err := dq.BooksByTitleYear(ctx, BooksByTitleYearParams{ + Title: "my book title", + Yr: 2016, + }) + if err != nil { + t.Fatal(err) + } + for _, book := range books0 { + t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Format(time.RFC822Z)) + author, err := dq.GetAuthor(ctx, book.AuthorID) + if err != nil { + t.Fatal(err) + } + t.Logf("Book %d author: %s\n", book.BookID, author.Name) + } + + // find a book with either "cool" or "other" tag + t.Logf("---------\nTag search results:\n") + res, err := dq.BooksByTags(ctx, "cool") + if err != nil { + t.Fatal(err) + } + for _, ab := range res { + t.Logf("Book %d: '%s', Author: '%s', ISBN: '%s' Tags: '%v'\n", ab.BookID, ab.Title, ab.Name, ab.Isbn, ab.Tags) + } + + // TODO: call say_hello(varchar) + + // get book 4 and delete + b5, err := dq.GetBook(ctx, int64(bookThreeID)) + if err != nil { + t.Fatal(err) + } + if err := dq.DeleteBook(ctx, b5.BookID); err != nil { + t.Fatal(err) + } + +} diff --git a/examples/booktest/sqlite/models.go b/examples/booktest/sqlite/models.go new file mode 100644 index 0000000000..c9b8e96bcc --- /dev/null +++ b/examples/booktest/sqlite/models.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package booktest + +import ( + "time" +) + +type Author struct { + AuthorID int64 + Name string +} + +type Book struct { + BookID int64 + AuthorID int64 + Isbn string + BookType string + Title string + Yr int64 + Available time.Time + Tags string +} diff --git a/examples/booktest/sqlite/query.sql b/examples/booktest/sqlite/query.sql new file mode 100644 index 0000000000..dd4f304ffd --- /dev/null +++ b/examples/booktest/sqlite/query.sql @@ -0,0 +1,62 @@ +/* name: GetAuthor :one */ +SELECT * FROM authors +WHERE author_id = ?; + +/* name: GetBook :one */ +SELECT * FROM books +WHERE book_id = ?; + +/* name: DeleteBook :exec */ +DELETE FROM books +WHERE book_id = ?; + +/* name: BooksByTitleYear :many */ +SELECT * FROM books +WHERE title = ? AND yr = ?; + +/* name: BooksByTags :many */ +SELECT + book_id, + title, + name, + isbn, + tags +FROM books +LEFT JOIN authors ON books.author_id = authors.author_id +WHERE tags = ?; + +/* name: CreateAuthor :execresult */ +INSERT INTO authors (name) VALUES (?); + +/* name: CreateBook :execresult */ +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + yr, + available, + tags +) VALUES ( + ?, + ?, + ?, + ?, + ?, + ?, + ? +); + +/* name: UpdateBook :exec */ +UPDATE books +SET title = ?, tags = ? +WHERE book_id = ?; + +/* name: UpdateBookISBN :exec */ +UPDATE books +SET title = ?, tags = ?, isbn = ? +WHERE book_id = ?; + +/* name: DeleteAuthorBeforeYear :exec */ +DELETE FROM books +WHERE yr < ? AND author_id = ?; diff --git a/examples/booktest/sqlite/query.sql.go b/examples/booktest/sqlite/query.sql.go new file mode 100644 index 0000000000..9a7b85f07b --- /dev/null +++ b/examples/booktest/sqlite/query.sql.go @@ -0,0 +1,251 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package booktest + +import ( + "context" + "database/sql" + "time" +) + +const booksByTags = `-- name: BooksByTags :many +SELECT + book_id, + title, + name, + isbn, + tags +FROM books +LEFT JOIN authors ON books.author_id = authors.author_id +WHERE tags = ? +` + +type BooksByTagsRow struct { + BookID int64 + Title string + Name string + Isbn string + Tags string +} + +func (q *Queries) BooksByTags(ctx context.Context, tags string) ([]BooksByTagsRow, error) { + rows, err := q.db.QueryContext(ctx, booksByTags, tags) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BooksByTagsRow + for rows.Next() { + var i BooksByTagsRow + if err := rows.Scan( + &i.BookID, + &i.Title, + &i.Name, + &i.Isbn, + &i.Tags, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const booksByTitleYear = `-- name: BooksByTitleYear :many +SELECT book_id, author_id, isbn, book_type, title, yr, available, tags FROM books +WHERE title = ? AND yr = ? +` + +type BooksByTitleYearParams struct { + Title string + Yr int64 +} + +func (q *Queries) BooksByTitleYear(ctx context.Context, arg BooksByTitleYearParams) ([]Book, error) { + rows, err := q.db.QueryContext(ctx, booksByTitleYear, arg.Title, arg.Yr) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Book + for rows.Next() { + var i Book + if err := rows.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Yr, + &i.Available, + &i.Tags, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const createAuthor = `-- name: CreateAuthor :execresult +INSERT INTO authors (name) VALUES (?) +` + +func (q *Queries) CreateAuthor(ctx context.Context, name string) (sql.Result, error) { + return q.db.ExecContext(ctx, createAuthor, name) +} + +const createBook = `-- name: CreateBook :execresult +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + yr, + available, + tags +) VALUES ( + ?, + ?, + ?, + ?, + ?, + ?, + ? +) +` + +type CreateBookParams struct { + AuthorID int64 + Isbn string + BookType string + Title string + Yr int64 + Available time.Time + Tags string +} + +func (q *Queries) CreateBook(ctx context.Context, arg CreateBookParams) (sql.Result, error) { + return q.db.ExecContext(ctx, createBook, + arg.AuthorID, + arg.Isbn, + arg.BookType, + arg.Title, + arg.Yr, + arg.Available, + arg.Tags, + ) +} + +const deleteAuthorBeforeYear = `-- name: DeleteAuthorBeforeYear :exec +DELETE FROM books +WHERE yr < ? AND author_id = ? +` + +type DeleteAuthorBeforeYearParams struct { + Yr int64 + AuthorID int64 +} + +func (q *Queries) DeleteAuthorBeforeYear(ctx context.Context, arg DeleteAuthorBeforeYearParams) error { + _, err := q.db.ExecContext(ctx, deleteAuthorBeforeYear, arg.Yr, arg.AuthorID) + return err +} + +const deleteBook = `-- name: DeleteBook :exec +DELETE FROM books +WHERE book_id = ? +` + +func (q *Queries) DeleteBook(ctx context.Context, bookID int64) error { + _, err := q.db.ExecContext(ctx, deleteBook, bookID) + return err +} + +const getAuthor = `-- name: GetAuthor :one +SELECT author_id, name FROM authors +WHERE author_id = ? +` + +func (q *Queries) GetAuthor(ctx context.Context, authorID int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthor, authorID) + var i Author + err := row.Scan(&i.AuthorID, &i.Name) + return i, err +} + +const getBook = `-- name: GetBook :one +SELECT book_id, author_id, isbn, book_type, title, yr, available, tags FROM books +WHERE book_id = ? +` + +func (q *Queries) GetBook(ctx context.Context, bookID int64) (Book, error) { + row := q.db.QueryRowContext(ctx, getBook, bookID) + var i Book + err := row.Scan( + &i.BookID, + &i.AuthorID, + &i.Isbn, + &i.BookType, + &i.Title, + &i.Yr, + &i.Available, + &i.Tags, + ) + return i, err +} + +const updateBook = `-- name: UpdateBook :exec +UPDATE books +SET title = ?, tags = ? +WHERE book_id = ? +` + +type UpdateBookParams struct { + Title string + Tags string + BookID int64 +} + +func (q *Queries) UpdateBook(ctx context.Context, arg UpdateBookParams) error { + _, err := q.db.ExecContext(ctx, updateBook, arg.Title, arg.Tags, arg.BookID) + return err +} + +const updateBookISBN = `-- name: UpdateBookISBN :exec +UPDATE books +SET title = ?, tags = ?, isbn = ? +WHERE book_id = ? +` + +type UpdateBookISBNParams struct { + Title string + Tags string + Isbn string + BookID int64 +} + +func (q *Queries) UpdateBookISBN(ctx context.Context, arg UpdateBookISBNParams) error { + _, err := q.db.ExecContext(ctx, updateBookISBN, + arg.Title, + arg.Tags, + arg.Isbn, + arg.BookID, + ) + return err +} diff --git a/examples/booktest/sqlite/schema.sql b/examples/booktest/sqlite/schema.sql new file mode 100644 index 0000000000..1176dcef28 --- /dev/null +++ b/examples/booktest/sqlite/schema.sql @@ -0,0 +1,20 @@ +CREATE TABLE authors ( + author_id integer NOT NULL PRIMARY KEY AUTOINCREMENT, + name text NOT NULL +); + +CREATE INDEX authors_name_idx ON authors(name); + +CREATE TABLE books ( + book_id integer NOT NULL PRIMARY KEY AUTOINCREMENT, + author_id integer NOT NULL, + isbn varchar(255) NOT NULL DEFAULT '' UNIQUE, + book_type text NOT NULL DEFAULT 'FICTION', + title text NOT NULL, + yr integer NOT NULL DEFAULT 2000, + available datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + tags text NOT NULL, + CHECK (book_type = 'FICTION' OR book_type = 'NONFICTION') +); + +CREATE INDEX books_title_idx ON books(title, yr); diff --git a/examples/ondeck/sqlc.json b/examples/ondeck/sqlc.json index 31f8e821b0..f45419823f 100644 --- a/examples/ondeck/sqlc.json +++ b/examples/ondeck/sqlc.json @@ -20,6 +20,16 @@ "emit_json_tags": true, "emit_prepared_queries": true, "emit_interface": true + }, + { + "path": "sqlite", + "name": "ondeck", + "schema": "sqlite/schema", + "queries": "sqlite/query", + "engine": "_lemon", + "emit_json_tags": true, + "emit_prepared_queries": true, + "emit_interface": true } ] -} +} \ No newline at end of file diff --git a/examples/ondeck/sqlite/city.sql.go b/examples/ondeck/sqlite/city.sql.go new file mode 100644 index 0000000000..5fdeb516f9 --- /dev/null +++ b/examples/ondeck/sqlite/city.sql.go @@ -0,0 +1,88 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: city.sql + +package ondeck + +import ( + "context" +) + +const createCity = `-- name: CreateCity :exec +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +) +` + +type CreateCityParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) error { + _, err := q.exec(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug) + return err +} + +const getCity = `-- name: GetCity :one +SELECT slug, name +FROM city +WHERE slug = ? +` + +func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) { + row := q.queryRow(ctx, q.getCityStmt, getCity, slug) + var i City + err := row.Scan(&i.Slug, &i.Name) + return i, err +} + +const listCities = `-- name: ListCities :many +SELECT slug, name +FROM city +ORDER BY name +` + +func (q *Queries) ListCities(ctx context.Context) ([]City, error) { + rows, err := q.query(ctx, q.listCitiesStmt, listCities) + if err != nil { + return nil, err + } + defer rows.Close() + var items []City + for rows.Next() { + var i City + if err := rows.Scan(&i.Slug, &i.Name); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateCityName = `-- name: UpdateCityName :exec +UPDATE city +SET name = ? +WHERE slug = ? +` + +type UpdateCityNameParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error { + _, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Name, arg.Slug) + return err +} diff --git a/examples/ondeck/sqlite/db.go b/examples/ondeck/sqlite/db.go new file mode 100644 index 0000000000..4a40ff0fa4 --- /dev/null +++ b/examples/ondeck/sqlite/db.go @@ -0,0 +1,178 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package ondeck + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.createCityStmt, err = db.PrepareContext(ctx, createCity); err != nil { + return nil, fmt.Errorf("error preparing query CreateCity: %w", err) + } + if q.createVenueStmt, err = db.PrepareContext(ctx, createVenue); err != nil { + return nil, fmt.Errorf("error preparing query CreateVenue: %w", err) + } + if q.deleteVenueStmt, err = db.PrepareContext(ctx, deleteVenue); err != nil { + return nil, fmt.Errorf("error preparing query DeleteVenue: %w", err) + } + if q.getCityStmt, err = db.PrepareContext(ctx, getCity); err != nil { + return nil, fmt.Errorf("error preparing query GetCity: %w", err) + } + if q.getVenueStmt, err = db.PrepareContext(ctx, getVenue); err != nil { + return nil, fmt.Errorf("error preparing query GetVenue: %w", err) + } + if q.listCitiesStmt, err = db.PrepareContext(ctx, listCities); err != nil { + return nil, fmt.Errorf("error preparing query ListCities: %w", err) + } + if q.listVenuesStmt, err = db.PrepareContext(ctx, listVenues); err != nil { + return nil, fmt.Errorf("error preparing query ListVenues: %w", err) + } + if q.updateCityNameStmt, err = db.PrepareContext(ctx, updateCityName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateCityName: %w", err) + } + if q.updateVenueNameStmt, err = db.PrepareContext(ctx, updateVenueName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateVenueName: %w", err) + } + if q.venueCountByCityStmt, err = db.PrepareContext(ctx, venueCountByCity); err != nil { + return nil, fmt.Errorf("error preparing query VenueCountByCity: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.createCityStmt != nil { + if cerr := q.createCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createCityStmt: %w", cerr) + } + } + if q.createVenueStmt != nil { + if cerr := q.createVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createVenueStmt: %w", cerr) + } + } + if q.deleteVenueStmt != nil { + if cerr := q.deleteVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteVenueStmt: %w", cerr) + } + } + if q.getCityStmt != nil { + if cerr := q.getCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getCityStmt: %w", cerr) + } + } + if q.getVenueStmt != nil { + if cerr := q.getVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getVenueStmt: %w", cerr) + } + } + if q.listCitiesStmt != nil { + if cerr := q.listCitiesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listCitiesStmt: %w", cerr) + } + } + if q.listVenuesStmt != nil { + if cerr := q.listVenuesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listVenuesStmt: %w", cerr) + } + } + if q.updateCityNameStmt != nil { + if cerr := q.updateCityNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateCityNameStmt: %w", cerr) + } + } + if q.updateVenueNameStmt != nil { + if cerr := q.updateVenueNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateVenueNameStmt: %w", cerr) + } + } + if q.venueCountByCityStmt != nil { + if cerr := q.venueCountByCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing venueCountByCityStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + createCityStmt *sql.Stmt + createVenueStmt *sql.Stmt + deleteVenueStmt *sql.Stmt + getCityStmt *sql.Stmt + getVenueStmt *sql.Stmt + listCitiesStmt *sql.Stmt + listVenuesStmt *sql.Stmt + updateCityNameStmt *sql.Stmt + updateVenueNameStmt *sql.Stmt + venueCountByCityStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + createCityStmt: q.createCityStmt, + createVenueStmt: q.createVenueStmt, + deleteVenueStmt: q.deleteVenueStmt, + getCityStmt: q.getCityStmt, + getVenueStmt: q.getVenueStmt, + listCitiesStmt: q.listCitiesStmt, + listVenuesStmt: q.listVenuesStmt, + updateCityNameStmt: q.updateCityNameStmt, + updateVenueNameStmt: q.updateVenueNameStmt, + venueCountByCityStmt: q.venueCountByCityStmt, + } +} diff --git a/examples/ondeck/sqlite/db_test.go b/examples/ondeck/sqlite/db_test.go new file mode 100644 index 0000000000..4c73d13787 --- /dev/null +++ b/examples/ondeck/sqlite/db_test.go @@ -0,0 +1,170 @@ +//go:build examples +// +build examples + +package ondeck + +import ( + "context" + "database/sql" + "strings" + "testing" + + "github.com/kyleconroy/sqlc/internal/sqltest" + + "github.com/google/go-cmp/cmp" +) + +// TODO: Enum is not yet supported +const ( + VenuesStatusOpen string = "open" + VenuesStatusClosed string = "closed" +) + +func join(vals ...string) sql.NullString { + if len(vals) == 0 { + return sql.NullString{} + } + return sql.NullString{ + Valid: true, + String: strings.Join(vals, ","), + } +} + +func runOnDeckQueries(t *testing.T, q *Queries) { + ctx := context.Background() + + err := q.CreateCity(ctx, CreateCityParams{ + Slug: "san-francisco", + Name: "San Francisco", + }) + if err != nil { + t.Fatal(err) + } + + city, err := q.GetCity(ctx, "san-francisco") + if err != nil { + t.Fatal(err) + } + + venueResult, err := q.CreateVenue(ctx, CreateVenueParams{ + Slug: "the-fillmore", + Name: "The Fillmore", + City: city.Slug, + SpotifyPlaylist: "spotify:uri", + Status: VenuesStatusOpen, + Statuses: join(string(VenuesStatusOpen), string(VenuesStatusClosed)), + Tags: join("rock", "punk"), + }) + if err != nil { + t.Fatal(err) + } + venueID, err := venueResult.LastInsertId() + if err != nil { + t.Fatal(err) + } + + venue, err := q.GetVenue(ctx, GetVenueParams{ + Slug: "the-fillmore", + City: city.Slug, + }) + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(venue.ID, venueID); diff != "" { + t.Errorf("venue ID mismatch:\n%s", diff) + } + + { + actual, err := q.VenueCountByCity(ctx) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []VenueCountByCityRow{ + {city.Slug, int64(1)}, + }); diff != "" { + t.Errorf("venue count mismatch:\n%s", diff) + } + } + + { + actual, err := q.ListCities(ctx) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []City{city}); diff != "" { + t.Errorf("list city mismatch:\n%s", diff) + } + } + + { + actual, err := q.ListVenues(ctx, city.Slug) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(actual, []Venue{venue}); diff != "" { + t.Errorf("list venue mismatch:\n%s", diff) + } + } + + { + err := q.UpdateCityName(ctx, UpdateCityNameParams{ + Slug: city.Slug, + Name: "SF", + }) + if err != nil { + t.Error(err) + } + } + + { + expected := "Fillmore" + err := q.UpdateVenueName(ctx, UpdateVenueNameParams{ + Slug: venue.Slug, + Name: expected, + }) + if err != nil { + t.Error(err) + } + fresh, err := q.GetVenue(ctx, GetVenueParams{ + Slug: venue.Slug, + City: city.Slug, + }) + if diff := cmp.Diff(expected, fresh.Name); diff != "" { + t.Errorf("update venue mismatch:\n%s", diff) + } + } + + { + err := q.DeleteVenue(ctx, DeleteVenueParams{ + Slug: venue.Slug, + Slug_2: venue.Slug, + }) + if err != nil { + t.Error(err) + } + } +} + +func TestPrepared(t *testing.T) { + t.Parallel() + + sdb, cleanup := sqltest.SQLite(t, []string{"schema"}) + defer cleanup() + + q, err := Prepare(context.Background(), sdb) + if err != nil { + t.Fatal(err) + } + + runOnDeckQueries(t, q) +} + +func TestQueries(t *testing.T) { + t.Parallel() + + sdb, cleanup := sqltest.SQLite(t, []string{"schema"}) + defer cleanup() + + runOnDeckQueries(t, New(sdb)) +} diff --git a/examples/ondeck/sqlite/models.go b/examples/ondeck/sqlite/models.go new file mode 100644 index 0000000000..16804087d0 --- /dev/null +++ b/examples/ondeck/sqlite/models.go @@ -0,0 +1,28 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package ondeck + +import ( + "database/sql" + "time" +) + +type City struct { + Slug string `json:"slug"` + Name string `json:"name"` +} + +type Venue struct { + ID int64 `json:"id"` + Status string `json:"status"` + Statuses sql.NullString `json:"statuses"` + Slug string `json:"slug"` + Name string `json:"name"` + City string `json:"city"` + SpotifyPlaylist string `json:"spotify_playlist"` + SongkickID sql.NullString `json:"songkick_id"` + Tags sql.NullString `json:"tags"` + CreatedAt time.Time `json:"created_at"` +} diff --git a/examples/ondeck/sqlite/querier.go b/examples/ondeck/sqlite/querier.go new file mode 100644 index 0000000000..244b24cb17 --- /dev/null +++ b/examples/ondeck/sqlite/querier.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package ondeck + +import ( + "context" + "database/sql" +) + +type Querier interface { + CreateCity(ctx context.Context, arg CreateCityParams) error + CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) + DeleteVenue(ctx context.Context, arg DeleteVenueParams) error + GetCity(ctx context.Context, slug string) (City, error) + GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) + ListCities(ctx context.Context) ([]City, error) + ListVenues(ctx context.Context, city string) ([]Venue, error) + UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error + UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error + VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/examples/ondeck/sqlite/query/city.sql b/examples/ondeck/sqlite/query/city.sql new file mode 100644 index 0000000000..c387e9d000 --- /dev/null +++ b/examples/ondeck/sqlite/query/city.sql @@ -0,0 +1,23 @@ +/* name: ListCities :many */ +SELECT * +FROM city +ORDER BY name; + +/* name: GetCity :one */ +SELECT * +FROM city +WHERE slug = ?; + +/* name: CreateCity :exec */ +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +); + +/* name: UpdateCityName :exec */ +UPDATE city +SET name = ? +WHERE slug = ?; diff --git a/examples/ondeck/sqlite/query/venue.sql b/examples/ondeck/sqlite/query/venue.sql new file mode 100644 index 0000000000..b4f5fd4071 --- /dev/null +++ b/examples/ondeck/sqlite/query/venue.sql @@ -0,0 +1,48 @@ +/* name: ListVenues :many */ +SELECT * +FROM venue +WHERE city = ? +ORDER BY name; + +/* name: DeleteVenue :exec */ +DELETE FROM venue +WHERE slug = ? AND slug = ?; + +/* name: GetVenue :one */ +SELECT * +FROM venue +WHERE slug = ? AND city = ?; + +/* name: CreateVenue :execresult */ +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + CURRENT_TIMESTAMP, + ?, + ?, + ?, + ? +); + +/* name: UpdateVenueName :exec */ +UPDATE venue +SET name = ? +WHERE slug = ?; + +/* name: VenueCountByCity :many */ +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1; diff --git a/examples/ondeck/sqlite/schema/0001_city.sql b/examples/ondeck/sqlite/schema/0001_city.sql new file mode 100644 index 0000000000..6be35d16bf --- /dev/null +++ b/examples/ondeck/sqlite/schema/0001_city.sql @@ -0,0 +1,4 @@ +CREATE TABLE city ( + slug varchar(255) PRIMARY KEY, + name text NOT NULL +) diff --git a/examples/ondeck/sqlite/schema/0002_venue.sql b/examples/ondeck/sqlite/schema/0002_venue.sql new file mode 100644 index 0000000000..e57166e4c0 --- /dev/null +++ b/examples/ondeck/sqlite/schema/0002_venue.sql @@ -0,0 +1,13 @@ +CREATE TABLE venues ( + id integer primary key AUTOINCREMENT, + dropped text, + status text not null, + statuses text, -- status[] + slug text not null, + name varchar(255) not null, + city text not null references city(slug), + spotify_playlist varchar(255) not null, + songkick_id text, + tags text, -- tags[] + CHECK (status = 'open' OR status = 'closed') +); diff --git a/examples/ondeck/sqlite/schema/0003_add_column.sql b/examples/ondeck/sqlite/schema/0003_add_column.sql new file mode 100644 index 0000000000..7d7a6443b4 --- /dev/null +++ b/examples/ondeck/sqlite/schema/0003_add_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE venues RENAME TO venue; +ALTER TABLE venue ADD COLUMN created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP; +ALTER TABLE venue DROP COLUMN dropped; diff --git a/examples/ondeck/sqlite/venue.sql.go b/examples/ondeck/sqlite/venue.sql.go new file mode 100644 index 0000000000..7ee4a9098c --- /dev/null +++ b/examples/ondeck/sqlite/venue.sql.go @@ -0,0 +1,193 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: venue.sql + +package ondeck + +import ( + "context" + "database/sql" +) + +const createVenue = `-- name: CreateVenue :execresult +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + CURRENT_TIMESTAMP, + ?, + ?, + ?, + ? +) +` + +type CreateVenueParams struct { + Slug string `json:"slug"` + Name string `json:"name"` + City string `json:"city"` + SpotifyPlaylist string `json:"spotify_playlist"` + Status string `json:"status"` + Statuses sql.NullString `json:"statuses"` + Tags sql.NullString `json:"tags"` +} + +func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) { + return q.exec(ctx, q.createVenueStmt, createVenue, + arg.Slug, + arg.Name, + arg.City, + arg.SpotifyPlaylist, + arg.Status, + arg.Statuses, + arg.Tags, + ) +} + +const deleteVenue = `-- name: DeleteVenue :exec +DELETE FROM venue +WHERE slug = ? AND slug = ? +` + +type DeleteVenueParams struct { + Slug string `json:"slug"` + Slug_2 string `json:"slug_2"` +} + +func (q *Queries) DeleteVenue(ctx context.Context, arg DeleteVenueParams) error { + _, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, arg.Slug, arg.Slug_2) + return err +} + +const getVenue = `-- name: GetVenue :one +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE slug = ? AND city = ? +` + +type GetVenueParams struct { + Slug string `json:"slug"` + City string `json:"city"` +} + +func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) { + row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City) + var i Venue + err := row.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ) + return i, err +} + +const listVenues = `-- name: ListVenues :many +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE city = ? +ORDER BY name +` + +func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) { + rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Venue + for rows.Next() { + var i Venue + if err := rows.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateVenueName = `-- name: UpdateVenueName :exec +UPDATE venue +SET name = ? +WHERE slug = ? +` + +type UpdateVenueNameParams struct { + Name string `json:"name"` + Slug string `json:"slug"` +} + +func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error { + _, err := q.exec(ctx, q.updateVenueNameStmt, updateVenueName, arg.Name, arg.Slug) + return err +} + +const venueCountByCity = `-- name: VenueCountByCity :many +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1 +` + +type VenueCountByCityRow struct { + City string `json:"city"` + Count int64 `json:"count"` +} + +func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) { + rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VenueCountByCityRow + for rows.Next() { + var i VenueCountByCityRow + if err := rows.Scan(&i.City, &i.Count); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/go.mod b/go.mod index a0782bec66..037ec9b094 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/jackc/pgx/v4 v4.16.1 github.com/jinzhu/inflection v1.0.0 github.com/lib/pq v1.10.6 + github.com/mattn/go-sqlite3 v1.14.13 github.com/pganalyze/pg_query_go/v2 v2.1.0 github.com/pingcap/parser v0.0.0-20210914110036-002913dd28ec github.com/spf13/cobra v1.4.0 diff --git a/go.sum b/go.sum index 7c62716fcb..7404f39b62 100644 --- a/go.sum +++ b/go.sum @@ -119,6 +119,8 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I= +github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/pganalyze/pg_query_go/v2 v2.1.0 h1:donwPZ4G/X+kMs7j5eYtKjdziqyOLVp3pkUrzb9lDl8= github.com/pganalyze/pg_query_go/v2 v2.1.0/go.mod h1:XAxmVqz1tEGqizcQ3YSdN90vCOHBWjJi8URL1er5+cA= github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg= diff --git a/internal/codegen/golang/sqlite_type.go b/internal/codegen/golang/sqlite_type.go index f26e533522..3667367b83 100644 --- a/internal/codegen/golang/sqlite_type.go +++ b/internal/codegen/golang/sqlite_type.go @@ -14,7 +14,7 @@ func sqliteType(req *plugin.CodeGenRequest, col *plugin.Column) string { switch dt { - case "int", "integer", "tinyint", "smallint", "mediumint", "bigint", "unsignedbigint", "int2", "int8", "numeric", "decimal": + case "int", "integer", "tinyint", "smallint", "mediumint", "bigint", "unsignedbigint", "int2", "int8": if notNull { return "int64" } @@ -32,7 +32,7 @@ func sqliteType(req *plugin.CodeGenRequest, col *plugin.Column) string { } return "sql.NullFloat64" - case "boolean": + case "boolean", "bool": if notNull { return "bool" } @@ -64,6 +64,12 @@ func sqliteType(req *plugin.CodeGenRequest, col *plugin.Column) string { } return "sql.NullString" + case strings.HasPrefix(dt, "decimal"), dt == "numeric": + if notNull { + return "float64" + } + return "sql.NullFloat64" + default: log.Printf("unknown SQLite type: %s\n", dt) return "interface{}" diff --git a/internal/endtoend/testdata/alias/sqlite/go/db.go b/internal/endtoend/testdata/alias/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/alias/sqlite/go/models.go b/internal/endtoend/testdata/alias/sqlite/go/models.go new file mode 100644 index 0000000000..a3136ad600 --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/alias/sqlite/go/query.sql.go b/internal/endtoend/testdata/alias/sqlite/go/query.sql.go new file mode 100644 index 0000000000..d42e767bd5 --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/go/query.sql.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const aliasBar = `-- name: AliasBar :exec +DELETE FROM bar AS b +WHERE b.id = ? +` + +func (q *Queries) AliasBar(ctx context.Context, id int64) error { + _, err := q.db.ExecContext(ctx, aliasBar, id) + return err +} diff --git a/internal/endtoend/testdata/alias/sqlite/query.sql b/internal/endtoend/testdata/alias/sqlite/query.sql new file mode 100644 index 0000000000..aa69308cd2 --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/query.sql @@ -0,0 +1,5 @@ +CREATE TABLE bar (id integer NOT NULL PRIMARY KEY AUTOINCREMENT); + +-- name: AliasBar :exec +DELETE FROM bar AS b +WHERE b.id = ?; diff --git a/internal/endtoend/testdata/alias/sqlite/sqlc.json b/internal/endtoend/testdata/alias/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/alias/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/coalesce/sqlite/go/db.go b/internal/endtoend/testdata/coalesce/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/coalesce/sqlite/go/models.go b/internal/endtoend/testdata/coalesce/sqlite/go/models.go new file mode 100644 index 0000000000..5379ec6980 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Bat string +} diff --git a/internal/endtoend/testdata/coalesce/sqlite/go/query.sql.go b/internal/endtoend/testdata/coalesce/sqlite/go/query.sql.go new file mode 100644 index 0000000000..d32f3560de --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/go/query.sql.go @@ -0,0 +1,73 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const coalesce = `-- name: Coalesce :many +SELECT coalesce(bar, '') as login +FROM foo +` + +func (q *Queries) Coalesce(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, coalesce) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceColumns = `-- name: CoalesceColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo +` + +type CoalesceColumnsRow struct { + Bar sql.NullString + Bat string + Bar_2 string +} + +func (q *Queries) CoalesceColumns(ctx context.Context) ([]CoalesceColumnsRow, error) { + rows, err := q.db.QueryContext(ctx, coalesceColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceColumnsRow + for rows.Next() { + var i CoalesceColumnsRow + if err := rows.Scan(&i.Bar, &i.Bat, &i.Bar_2); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/coalesce/sqlite/query.sql b/internal/endtoend/testdata/coalesce/sqlite/query.sql new file mode 100644 index 0000000000..022c1fb653 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/query.sql @@ -0,0 +1,9 @@ +CREATE TABLE foo (bar text, bat text not null); + +-- name: Coalesce :many +SELECT coalesce(bar, '') as login +FROM foo; + +-- name: CoalesceColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo; diff --git a/internal/endtoend/testdata/coalesce/sqlite/sqlc.json b/internal/endtoend/testdata/coalesce/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/coalesce/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/coalesce_as/sqlite/go/db.go b/internal/endtoend/testdata/coalesce_as/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/coalesce_as/sqlite/go/models.go b/internal/endtoend/testdata/coalesce_as/sqlite/go/models.go new file mode 100644 index 0000000000..2e1941497e --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Baz sql.NullInt64 +} diff --git a/internal/endtoend/testdata/coalesce_as/sqlite/go/query.sql.go b/internal/endtoend/testdata/coalesce_as/sqlite/go/query.sql.go new file mode 100644 index 0000000000..44b78937f6 --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/go/query.sql.go @@ -0,0 +1,45 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const sumBaz = `-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1 +` + +type SumBazRow struct { + Bar sql.NullString + Quantity interface{} +} + +func (q *Queries) SumBaz(ctx context.Context) ([]SumBazRow, error) { + rows, err := q.db.QueryContext(ctx, sumBaz) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SumBazRow + for rows.Next() { + var i SumBazRow + if err := rows.Scan(&i.Bar, &i.Quantity); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/coalesce_as/sqlite/query.sql b/internal/endtoend/testdata/coalesce_as/sqlite/query.sql new file mode 100644 index 0000000000..b4e64b0bdd --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/query.sql @@ -0,0 +1,9 @@ +CREATE TABLE foo ( + bar text, + baz integer +); + +-- name: SumBaz :many +SELECT bar, coalesce(sum(baz), 0) as quantity +FROM foo +GROUP BY 1; diff --git a/internal/endtoend/testdata/coalesce_as/sqlite/sqlc.json b/internal/endtoend/testdata/coalesce_as/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/coalesce_as/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/column_as/sqlite/go/db.go b/internal/endtoend/testdata/column_as/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/column_as/sqlite/go/models.go b/internal/endtoend/testdata/column_as/sqlite/go/models.go new file mode 100644 index 0000000000..893d9520c6 --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Foo struct { + Email string +} diff --git a/internal/endtoend/testdata/column_as/sqlite/go/query.sql.go b/internal/endtoend/testdata/column_as/sqlite/go/query.sql.go new file mode 100644 index 0000000000..5f0c926423 --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const columnAs = `-- name: ColumnAs :many +SELECT email AS id FROM foo +` + +func (q *Queries) ColumnAs(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, columnAs) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + return nil, err + } + items = append(items, id) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/column_as/sqlite/query.sql b/internal/endtoend/testdata/column_as/sqlite/query.sql new file mode 100644 index 0000000000..4b055cc896 --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/query.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (email text not null); + +/* name: ColumnAs :many */ +SELECT email AS id FROM foo; diff --git a/internal/endtoend/testdata/column_as/sqlite/sqlc.json b/internal/endtoend/testdata/column_as/sqlite/sqlc.json new file mode 100644 index 0000000000..9aea94d599 --- /dev/null +++ b/internal/endtoend/testdata/column_as/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "_lemon", + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/go/db.go b/internal/endtoend/testdata/comment_syntax/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/go/models.go b/internal/endtoend/testdata/comment_syntax/sqlite/go/models.go new file mode 100644 index 0000000000..523a17be93 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString +} diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/go/query.sql.go b/internal/endtoend/testdata/comment_syntax/sqlite/go/query.sql.go new file mode 100644 index 0000000000..f7f3dd1371 --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/go/query.sql.go @@ -0,0 +1,33 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const doubleDash = `-- name: DoubleDash :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) DoubleDash(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, doubleDash) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} + +const slashStar = `-- name: SlashStar :one +SELECT bar FROM foo LIMIT 1 +` + +func (q *Queries) SlashStar(ctx context.Context) (sql.NullString, error) { + row := q.db.QueryRowContext(ctx, slashStar) + var bar sql.NullString + err := row.Scan(&bar) + return bar, err +} diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/query.sql b/internal/endtoend/testdata/comment_syntax/sqlite/query.sql new file mode 100644 index 0000000000..2efd5e5a1c --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/query.sql @@ -0,0 +1,7 @@ +CREATE TABLE foo (bar text); + +-- name: DoubleDash :one +SELECT * FROM foo LIMIT 1; + +/* name: SlashStar :one */ +SELECT * FROM foo LIMIT 1; diff --git a/internal/endtoend/testdata/comment_syntax/sqlite/sqlc.json b/internal/endtoend/testdata/comment_syntax/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/comment_syntax/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/comparisons/sqlite/go/db.go b/internal/endtoend/testdata/comparisons/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/comparisons/sqlite/go/models.go b/internal/endtoend/testdata/comparisons/sqlite/go/models.go new file mode 100644 index 0000000000..a3136ad600 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Bar struct { + ID int64 +} diff --git a/internal/endtoend/testdata/comparisons/sqlite/go/query.sql.go b/internal/endtoend/testdata/comparisons/sqlite/go/query.sql.go new file mode 100644 index 0000000000..ee96df81e7 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/go/query.sql.go @@ -0,0 +1,199 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const alsoNotEqual = `-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar +` + +func (q *Queries) AlsoNotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, alsoNotEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const equal = `-- name: Equal :many +SELECT count(*) = 0 FROM bar +` + +func (q *Queries) Equal(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, equal) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThan = `-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar +` + +func (q *Queries) GreaterThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, greaterThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const greaterThanOrEqual = `-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar +` + +func (q *Queries) GreaterThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, greaterThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThan = `-- name: LessThan :many +SELECT count(*) < 0 FROM bar +` + +func (q *Queries) LessThan(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, lessThan) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const lessThanOrEqual = `-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar +` + +func (q *Queries) LessThanOrEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, lessThanOrEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const notEqual = `-- name: NotEqual :many +SELECT count(*) != 0 FROM bar +` + +func (q *Queries) NotEqual(ctx context.Context) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, notEqual) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var column_1 bool + if err := rows.Scan(&column_1); err != nil { + return nil, err + } + items = append(items, column_1) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/comparisons/sqlite/query.sql b/internal/endtoend/testdata/comparisons/sqlite/query.sql new file mode 100644 index 0000000000..27d7741d02 --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/query.sql @@ -0,0 +1,31 @@ +-- Comparison Functions and Operators +-- https://www.postgresql.org/docs/current/functions-comparison.html + +CREATE TABLE bar (id integer not null primary key autoincrement); + +-- name: GreaterThan :many +SELECT count(*) > 0 FROM bar; + +-- name: LessThan :many +SELECT count(*) < 0 FROM bar; + +-- name: GreaterThanOrEqual :many +SELECT count(*) >= 0 FROM bar; + +-- name: LessThanOrEqual :many +SELECT count(*) <= 0 FROM bar; + +-- name: NotEqual :many +SELECT count(*) != 0 FROM bar; + +-- name: AlsoNotEqual :many +SELECT count(*) <> 0 FROM bar; + +-- name: Equal :many +SELECT count(*) = 0 FROM bar; + + + + + + diff --git a/internal/endtoend/testdata/comparisons/sqlite/sqlc.json b/internal/endtoend/testdata/comparisons/sqlite/sqlc.json new file mode 100644 index 0000000000..d1c5d38e4b --- /dev/null +++ b/internal/endtoend/testdata/comparisons/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "_lemon", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/create_view/sqlite/go/db.go b/internal/endtoend/testdata/create_view/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/create_view/sqlite/go/models.go b/internal/endtoend/testdata/create_view/sqlite/go/models.go new file mode 100644 index 0000000000..a881e640dd --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/go/models.go @@ -0,0 +1,23 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type FirstView struct { + Val string +} + +type Foo struct { + Val string + Val2 sql.NullInt64 +} + +type SecondView struct { + Val string + Val2 sql.NullInt64 +} diff --git a/internal/endtoend/testdata/create_view/sqlite/go/query.sql.go b/internal/endtoend/testdata/create_view/sqlite/go/query.sql.go new file mode 100644 index 0000000000..6da2185eb1 --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/go/query.sql.go @@ -0,0 +1,65 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getFirst = `-- name: GetFirst :many +SELECT val FROM first_view +` + +func (q *Queries) GetFirst(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getFirst) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var val string + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSecond = `-- name: GetSecond :many +SELECT val, val2 FROM second_view WHERE val2 = ? +` + +func (q *Queries) GetSecond(ctx context.Context, val2 sql.NullInt64) ([]SecondView, error) { + rows, err := q.db.QueryContext(ctx, getSecond, val2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SecondView + for rows.Next() { + var i SecondView + if err := rows.Scan(&i.Val, &i.Val2); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/create_view/sqlite/query.sql b/internal/endtoend/testdata/create_view/sqlite/query.sql new file mode 100644 index 0000000000..c94fc58556 --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/query.sql @@ -0,0 +1,5 @@ +-- name: GetFirst :many +SELECT * FROM first_view; + +-- name: GetSecond :many +SELECT * FROM second_view WHERE val2 = ?; diff --git a/internal/endtoend/testdata/create_view/sqlite/schema.sql b/internal/endtoend/testdata/create_view/sqlite/schema.sql new file mode 100644 index 0000000000..246f73e0b7 --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE foo (val text not null); + +CREATE VIEW first_view AS SELECT * FROM foo; +CREATE VIEW second_view AS SELECT * FROM foo; +CREATE VIEW third_view AS SELECT * FROM foo; + +ALTER TABLE foo ADD COLUMN val2 integer; +DROP VIEW second_view; +CREATE VIEW second_view AS SELECT * FROM foo; + +DROP VIEW third_view; diff --git a/internal/endtoend/testdata/create_view/sqlite/sqlc.json b/internal/endtoend/testdata/create_view/sqlite/sqlc.json new file mode 100644 index 0000000000..39d417df7f --- /dev/null +++ b/internal/endtoend/testdata/create_view/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "_lemon", + "path": "go", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/data_type_boolean/sqlite/db/db.go b/internal/endtoend/testdata/data_type_boolean/sqlite/db/db.go new file mode 100644 index 0000000000..f30b89ec02 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/db/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package db + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/data_type_boolean/sqlite/db/models.go b/internal/endtoend/testdata/data_type_boolean/sqlite/db/models.go new file mode 100644 index 0000000000..0a87ab09f6 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/db/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package db + +import ( + "database/sql" +) + +type Bar struct { + ColA sql.NullBool + ColB sql.NullBool +} + +type Foo struct { + ColA bool + ColB bool +} diff --git a/internal/endtoend/testdata/data_type_boolean/sqlite/db/query.sql.go b/internal/endtoend/testdata/data_type_boolean/sqlite/db/query.sql.go new file mode 100644 index 0000000000..6b890e5079 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/db/query.sql.go @@ -0,0 +1,64 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package db + +import ( + "context" +) + +const listBar = `-- name: ListBar :many +SELECT col_a, col_b FROM bar +` + +func (q *Queries) ListBar(ctx context.Context) ([]Bar, error) { + rows, err := q.db.QueryContext(ctx, listBar) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Bar + for rows.Next() { + var i Bar + if err := rows.Scan(&i.ColA, &i.ColB); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listFoo = `-- name: ListFoo :many +SELECT col_a, col_b FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.ColA, &i.ColB); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/data_type_boolean/sqlite/query.sql b/internal/endtoend/testdata/data_type_boolean/sqlite/query.sql new file mode 100644 index 0000000000..53ad078373 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/query.sql @@ -0,0 +1,17 @@ +CREATE TABLE foo +( + col_a BOOL NOT NULL, + col_b BOOLEAN NOT NULL +); + +-- name: ListFoo :many +SELECT * FROM foo; + +CREATE TABLE bar +( + col_a BOOL, + col_b BOOLEAN +); + +-- name: ListBar :many +SELECT * FROM bar; diff --git a/internal/endtoend/testdata/data_type_boolean/sqlite/sqlc.json b/internal/endtoend/testdata/data_type_boolean/sqlite/sqlc.json new file mode 100644 index 0000000000..5499ab0a68 --- /dev/null +++ b/internal/endtoend/testdata/data_type_boolean/sqlite/sqlc.json @@ -0,0 +1,11 @@ +{ + "version": "1", + "packages": [ + { + "path": "db", + "engine": "_lemon", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/datatype/sqlite/go/db.go b/internal/endtoend/testdata/datatype/sqlite/go/db.go new file mode 100644 index 0000000000..8fbb3c811f --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package datatype + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/datatype/sqlite/go/models.go b/internal/endtoend/testdata/datatype/sqlite/go/models.go new file mode 100644 index 0000000000..65180c48ad --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/go/models.go @@ -0,0 +1,80 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package datatype + +import ( + "database/sql" + "time" +) + +type DtCharacter struct { + A sql.NullString + B sql.NullString + C sql.NullString + D sql.NullString + E sql.NullString + F sql.NullString + G sql.NullString + H sql.NullString +} + +type DtCharacterNotNull struct { + A string + B string + C string + D string + E string + F string + G string + H string +} + +type DtDatetime struct { + A sql.NullTime + B sql.NullTime + C sql.NullTime +} + +type DtDatetimeNotNull struct { + A time.Time + B time.Time + C time.Time +} + +type DtNumeric struct { + A sql.NullInt64 + B sql.NullInt64 + C sql.NullInt64 + D sql.NullInt64 + E sql.NullInt64 + F sql.NullInt64 + G sql.NullInt64 + H sql.NullInt64 + I sql.NullInt64 + J sql.NullFloat64 + K sql.NullFloat64 + L sql.NullFloat64 + M sql.NullFloat64 + N sql.NullFloat64 + O sql.NullFloat64 +} + +type DtNumericNotNull struct { + A int64 + B int64 + C int64 + D int64 + E int64 + F int64 + G int64 + H int64 + I int64 + J float64 + K float64 + L float64 + M float64 + N float64 + O float64 +} diff --git a/internal/endtoend/testdata/datatype/sqlite/sql/character.sql b/internal/endtoend/testdata/datatype/sqlite/sql/character.sql new file mode 100644 index 0000000000..d4b728bdab --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sql/character.sql @@ -0,0 +1,23 @@ +-- Character Types +-- https://www.sqlite.org/datatype3.html +CREATE TABLE dt_character ( + a CHARACTER(32), + b VARCHAR(32), + c VARYING CHARACTER(32), + d NCHAR(32), + e NATIVE CHARACTER(32), + f NVARCHAR(32), + g TEXT, + h CLOB +); + +CREATE TABLE dt_character_not_null ( + a CHARACTER(32) NOT NULL, + b VARCHAR(32) NOT NULL, + c VARYING CHARACTER(32) NOT NULL, + d NCHAR(32) NOT NULL, + e NATIVE CHARACTER(32) NOT NULL, + f NVARCHAR(32) NOT NULL, + g TEXT NOT NULL, + h CLOB NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/sqlite/sql/datetime.sql b/internal/endtoend/testdata/datatype/sqlite/sql/datetime.sql new file mode 100644 index 0000000000..6008cf6ae6 --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sql/datetime.sql @@ -0,0 +1,13 @@ +-- Date/Time Types +-- https://www.sqlite.org/datatype3.html +CREATE TABLE dt_datetime ( + a DATE, + b DATETIME, + c TIMESTAMP +); + +CREATE TABLE dt_datetime_not_null ( + a DATE NOT NULL, + b DATETIME NOT NULL, + c TIMESTAMP NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/sqlite/sql/numeric.sql b/internal/endtoend/testdata/datatype/sqlite/sql/numeric.sql new file mode 100644 index 0000000000..a85b4f295b --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sql/numeric.sql @@ -0,0 +1,37 @@ +-- Numeric Types +-- https://www.sqlite.org/datatype3.html +CREATE TABLE dt_numeric ( + a INT, + b INTEGER, + c TINYINT, + d SMALLINT, + e MEDIUMINT, + f BIGINT, + g UNSIGNED BIG INT, + h INT2, + i INT8, + j REAL, + k DOUBLE, + l DOUBLE PRECISION, + m FLOAT, + n NUMERIC, + o DECIMAL(10,5) +); + +CREATE TABLE dt_numeric_not_null ( + a INT NOT NULL, + b INTEGER NOT NULL, + c TINYINT NOT NULL, + d SMALLINT NOT NULL, + e MEDIUMINT NOT NULL, + f BIGINT NOT NULL, + g UNSIGNED BIG INT NOT NULL, + h INT2 NOT NULL, + i INT8 NOT NULL, + j REAL NOT NULL, + k DOUBLE NOT NULL, + l DOUBLE PRECISION NOT NULL, + m FLOAT NOT NULL, + n NUMERIC NOT NULL, + o DECIMAL(10,5) NOT NULL +); diff --git a/internal/endtoend/testdata/datatype/sqlite/sql/query.sql b/internal/endtoend/testdata/datatype/sqlite/sql/query.sql new file mode 100644 index 0000000000..e0ac49d1ec --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sql/query.sql @@ -0,0 +1 @@ +SELECT 1; diff --git a/internal/endtoend/testdata/datatype/sqlite/sqlc.json b/internal/endtoend/testdata/datatype/sqlite/sqlc.json new file mode 100644 index 0000000000..8b6fbfd05a --- /dev/null +++ b/internal/endtoend/testdata/datatype/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "datatype", + "schema": "sql/", + "queries": "sql/" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/models.go b/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/models.go index c1c9a4d337..fd0a7ad229 100644 --- a/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/models.go +++ b/internal/endtoend/testdata/ddl_create_trigger/sqlite/go/models.go @@ -13,3 +13,8 @@ type Customer struct { CustName sql.NullString CustAddr sql.NullString } + +type CustomerAddress struct { + CustID int64 + CustAddr sql.NullString +} diff --git a/internal/endtoend/testdata/identical_tables/sqlite/go/db.go b/internal/endtoend/testdata/identical_tables/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/identical_tables/sqlite/go/models.go b/internal/endtoend/testdata/identical_tables/sqlite/go/models.go new file mode 100644 index 0000000000..5a99c0db9a --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Bar struct { + ID string +} + +type Foo struct { + ID string +} diff --git a/internal/endtoend/testdata/identical_tables/sqlite/go/query.sql.go b/internal/endtoend/testdata/identical_tables/sqlite/go/query.sql.go new file mode 100644 index 0000000000..40605b12a5 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const identicalTable = `-- name: IdenticalTable :many +SELECT id FROM foo +` + +func (q *Queries) IdenticalTable(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, identicalTable) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + return nil, err + } + items = append(items, id) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/identical_tables/sqlite/query.sql b/internal/endtoend/testdata/identical_tables/sqlite/query.sql new file mode 100644 index 0000000000..c995d0f183 --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/query.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo (id text not null); +CREATE TABLE bar (id text not null); + +-- name: IdenticalTable :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/identical_tables/sqlite/sqlc.json b/internal/endtoend/testdata/identical_tables/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/identical_tables/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/inflection/sqlite/go/db.go b/internal/endtoend/testdata/inflection/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/inflection/sqlite/go/models.go b/internal/endtoend/testdata/inflection/sqlite/go/models.go new file mode 100644 index 0000000000..5a25cada01 --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Campus struct { + ID string +} + +type ProductMetum struct { + ID string +} + +type Student struct { + ID string +} diff --git a/internal/endtoend/testdata/inflection/sqlite/go/query.sql.go b/internal/endtoend/testdata/inflection/sqlite/go/query.sql.go new file mode 100644 index 0000000000..1b551497a8 --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/go/query.sql.go @@ -0,0 +1,91 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const listCampuses = `-- name: ListCampuses :many +SELECT id FROM campus +` + +func (q *Queries) ListCampuses(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listCampuses) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + return nil, err + } + items = append(items, id) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listMetadata = `-- name: ListMetadata :many +SELECT id FROM product_meta +` + +func (q *Queries) ListMetadata(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listMetadata) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + return nil, err + } + items = append(items, id) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listStudents = `-- name: ListStudents :many +SELECT id FROM students +` + +func (q *Queries) ListStudents(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, listStudents) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + return nil, err + } + items = append(items, id) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/inflection/sqlite/query.sql b/internal/endtoend/testdata/inflection/sqlite/query.sql new file mode 100644 index 0000000000..23f1cb26d9 --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/query.sql @@ -0,0 +1,12 @@ +CREATE TABLE campus (id text not null); +CREATE TABLE students (id text not null); +CREATE TABLE product_meta (id text not null); + +/* name: ListCampuses :many */ +SELECT * FROM campus; + +/* name: ListStudents :many */ +SELECT * FROM students; + +/* name: ListMetadata :many */ +SELECT * FROM product_meta; diff --git a/internal/endtoend/testdata/inflection/sqlite/sqlc.json b/internal/endtoend/testdata/inflection/sqlite/sqlc.json new file mode 100644 index 0000000000..9aea94d599 --- /dev/null +++ b/internal/endtoend/testdata/inflection/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "_lemon", + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select/sqlite/go/db.go b/internal/endtoend/testdata/insert_select/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/insert_select/sqlite/go/models.go b/internal/endtoend/testdata/insert_select/sqlite/go/models.go new file mode 100644 index 0000000000..ac408cae57 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/go/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Bar struct { + Name string + Ready bool +} + +type Foo struct { + Name string + Meta string +} diff --git a/internal/endtoend/testdata/insert_select/sqlite/go/query.sql.go b/internal/endtoend/testdata/insert_select/sqlite/go/query.sql.go new file mode 100644 index 0000000000..a287db7c9f --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertSelect = `-- name: InsertSelect :exec +INSERT INTO foo (name, meta) +SELECT name, ? +FROM bar WHERE ready = ? +` + +type InsertSelectParams struct { + Meta string + Ready bool +} + +func (q *Queries) InsertSelect(ctx context.Context, arg InsertSelectParams) error { + _, err := q.db.ExecContext(ctx, insertSelect, arg.Meta, arg.Ready) + return err +} diff --git a/internal/endtoend/testdata/insert_select/sqlite/query.sql b/internal/endtoend/testdata/insert_select/sqlite/query.sql new file mode 100644 index 0000000000..69aee7f0e9 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/query.sql @@ -0,0 +1,7 @@ +CREATE TABLE bar (name text not null, ready bool not null); +CREATE TABLE foo (name text not null, meta text not null); + +/* name: InsertSelect :exec */ +INSERT INTO foo (name, meta) +SELECT name, ? +FROM bar WHERE ready = ?; diff --git a/internal/endtoend/testdata/insert_select/sqlite/sqlc.json b/internal/endtoend/testdata/insert_select/sqlite/sqlc.json new file mode 100644 index 0000000000..9aea94d599 --- /dev/null +++ b/internal/endtoend/testdata/insert_select/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "_lemon", + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/sqlite/query.sql b/internal/endtoend/testdata/insert_select_invalid/sqlite/query.sql new file mode 100644 index 0000000000..cfd90fe55d --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/sqlite/query.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo (bar text); + +-- name: InsertFoo :exec +INSERT INTO foo (bar) +SELECT 1, ?, ?; diff --git a/internal/endtoend/testdata/insert_select_invalid/sqlite/sqlc.json b/internal/endtoend/testdata/insert_select_invalid/sqlite/sqlc.json new file mode 100644 index 0000000000..9aea94d599 --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "_lemon", + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/insert_select_invalid/sqlite/stderr.txt b/internal/endtoend/testdata/insert_select_invalid/sqlite/stderr.txt new file mode 100644 index 0000000000..063b2a149a --- /dev/null +++ b/internal/endtoend/testdata/insert_select_invalid/sqlite/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:4:1: INSERT has more expressions than target columns diff --git a/internal/endtoend/testdata/insert_values/sqlite/go/db.go b/internal/endtoend/testdata/insert_values/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/insert_values/sqlite/go/models.go b/internal/endtoend/testdata/insert_values/sqlite/go/models.go new file mode 100644 index 0000000000..dfa095d2fb --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString + B sql.NullInt64 +} diff --git a/internal/endtoend/testdata/insert_values/sqlite/go/query.sql.go b/internal/endtoend/testdata/insert_values/sqlite/go/query.sql.go new file mode 100644 index 0000000000..40e1842df0 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/go/query.sql.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const insertValues = `-- name: InsertValues :exec +INSERT INTO foo (a, b) VALUES (?, ?) +` + +type InsertValuesParams struct { + A sql.NullString + B sql.NullInt64 +} + +func (q *Queries) InsertValues(ctx context.Context, arg InsertValuesParams) error { + _, err := q.db.ExecContext(ctx, insertValues, arg.A, arg.B) + return err +} diff --git a/internal/endtoend/testdata/insert_values/sqlite/query.sql b/internal/endtoend/testdata/insert_values/sqlite/query.sql new file mode 100644 index 0000000000..78a29ccd39 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/query.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (a text, b integer); + +/* name: InsertValues :exec */ +INSERT INTO foo (a, b) VALUES (?, ?); diff --git a/internal/endtoend/testdata/insert_values/sqlite/sqlc.json b/internal/endtoend/testdata/insert_values/sqlite/sqlc.json new file mode 100644 index 0000000000..9aea94d599 --- /dev/null +++ b/internal/endtoend/testdata/insert_values/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "_lemon", + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_group_by_reference/sqlite/query.sql b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/query.sql new file mode 100644 index 0000000000..41ed0cf32c --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/query.sql @@ -0,0 +1,11 @@ +CREATE TABLE authors ( + id integer NOT NULL PRIMARY KEY AUTOINCREMENT, + name text NOT NULL, + bio text, + UNIQUE(name) +); + +-- name: ListAuthors :many +SELECT * +FROM authors +GROUP BY invalid_reference; diff --git a/internal/endtoend/testdata/invalid_group_by_reference/sqlite/sqlc.json b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_group_by_reference/sqlite/stderr.txt b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/stderr.txt new file mode 100644 index 0000000000..18a7d6bd0f --- /dev/null +++ b/internal/endtoend/testdata/invalid_group_by_reference/sqlite/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:9:1: column reference "invalid_reference" not found diff --git a/internal/endtoend/testdata/invalid_table_alias/sqlite/query.sql b/internal/endtoend/testdata/invalid_table_alias/sqlite/query.sql new file mode 100644 index 0000000000..4c06fa07a0 --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/sqlite/query.sql @@ -0,0 +1,12 @@ +-- https://github.com/kyleconroy/sqlc/issues/437 +CREATE TABLE authors ( + id INT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + bio text +); + +-- name: GetAuthor :one +SELECT * +FROM authors a +WHERE p.id = ? +LIMIT 1; diff --git a/internal/endtoend/testdata/invalid_table_alias/sqlite/sqlc.json b/internal/endtoend/testdata/invalid_table_alias/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/invalid_table_alias/sqlite/stderr.txt b/internal/endtoend/testdata/invalid_table_alias/sqlite/stderr.txt new file mode 100644 index 0000000000..d4c26d650f --- /dev/null +++ b/internal/endtoend/testdata/invalid_table_alias/sqlite/stderr.txt @@ -0,0 +1,2 @@ +# package querytest +query.sql:9:1: table alias "p" does not exist diff --git a/internal/endtoend/testdata/join_alias/sqlite/go/db.go b/internal/endtoend/testdata/join_alias/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/join_alias/sqlite/go/models.go b/internal/endtoend/testdata/join_alias/sqlite/go/models.go new file mode 100644 index 0000000000..063b519683 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int64 + Title sql.NullString +} + +type Foo struct { + ID int64 +} diff --git a/internal/endtoend/testdata/join_alias/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_alias/sqlite/go/query.sql.go new file mode 100644 index 0000000000..6bfd3eb914 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/go/query.sql.go @@ -0,0 +1,82 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const aliasExpand = `-- name: AliasExpand :many +SELECT f.id, b.id, title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = ? +` + +type AliasExpandRow struct { + ID int64 + ID_2 int64 + Title sql.NullString +} + +func (q *Queries) AliasExpand(ctx context.Context, id int64) ([]AliasExpandRow, error) { + rows, err := q.db.QueryContext(ctx, aliasExpand, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasExpandRow + for rows.Next() { + var i AliasExpandRow + if err := rows.Scan(&i.ID, &i.ID_2, &i.Title); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const aliasJoin = `-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = ? +` + +type AliasJoinRow struct { + ID int64 + Title sql.NullString +} + +func (q *Queries) AliasJoin(ctx context.Context, id int64) ([]AliasJoinRow, error) { + rows, err := q.db.QueryContext(ctx, aliasJoin, id) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AliasJoinRow + for rows.Next() { + var i AliasJoinRow + if err := rows.Scan(&i.ID, &i.Title); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/join_alias/sqlite/query.sql b/internal/endtoend/testdata/join_alias/sqlite/query.sql new file mode 100644 index 0000000000..c8d3044460 --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/query.sql @@ -0,0 +1,14 @@ +CREATE TABLE foo (id integer not null); +CREATE TABLE bar (id integer not null references foo(id), title text); + +-- name: AliasJoin :many +SELECT f.id, b.title +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = ?; + +-- name: AliasExpand :many +SELECT * +FROM foo f +JOIN bar b ON b.id = f.id +WHERE f.id = ?; diff --git a/internal/endtoend/testdata/join_alias/sqlite/sqlc.json b/internal/endtoend/testdata/join_alias/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/join_alias/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_from/sqlite/go/db.go b/internal/endtoend/testdata/join_from/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/join_from/sqlite/go/models.go b/internal/endtoend/testdata/join_from/sqlite/go/models.go new file mode 100644 index 0000000000..6c251d6aab --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Bar struct { + Login string +} + +type Foo struct { + Email string +} diff --git a/internal/endtoend/testdata/join_from/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_from/sqlite/go/query.sql.go new file mode 100644 index 0000000000..80a09c4220 --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const multiFrom = `-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = ? +` + +func (q *Queries) MultiFrom(ctx context.Context, login string) ([]string, error) { + rows, err := q.db.QueryContext(ctx, multiFrom, login) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var email string + if err := rows.Scan(&email); err != nil { + return nil, err + } + items = append(items, email) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/join_from/sqlite/query.sql b/internal/endtoend/testdata/join_from/sqlite/query.sql new file mode 100644 index 0000000000..588d859578 --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/query.sql @@ -0,0 +1,5 @@ +CREATE TABLE foo (email text not null); +CREATE TABLE bar (login text not null); + +-- name: MultiFrom :many +SELECT email FROM bar, foo WHERE login = ?; diff --git a/internal/endtoend/testdata/join_from/sqlite/sqlc.json b/internal/endtoend/testdata/join_from/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/join_from/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_left/sqlite/go/db.go b/internal/endtoend/testdata/join_left/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/join_left/sqlite/go/models.go b/internal/endtoend/testdata/join_left/sqlite/go/models.go new file mode 100644 index 0000000000..725603c989 --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/go/models.go @@ -0,0 +1,60 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" + "time" +) + +type Author struct { + ID int64 + Name string + ParentID sql.NullInt64 +} + +type City struct { + CityID int64 + MayorID int64 +} + +type Mayor struct { + MayorID int64 + FullName string +} + +type Medium struct { + MediaID int64 + MediaCreatedAt time.Time + MediaHash string + MediaDirectory string + MediaAuthorID int64 + MediaWidth int64 + MediaHeight int64 +} + +type SuperAuthor struct { + SuperID int64 + SuperName string + SuperParentID sql.NullInt64 +} + +type User struct { + UserID int64 + CityID sql.NullInt64 +} + +type Users2 struct { + UserID int64 + UserNickname string + UserEmail string + UserDisplayName string + UserPassword sql.NullString + UserGoogleID sql.NullString + UserAppleID sql.NullString + UserBio string + UserCreatedAt time.Time + UserAvatarID sql.NullInt64 +} diff --git a/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go new file mode 100644 index 0000000000..4624ae78ff --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go @@ -0,0 +1,433 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + "time" +) + +const allAuthors = `-- name: AllAuthors :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors AS a + LEFT JOIN authors AS p + ON a.parent_id = p.id +` + +type AllAuthorsRow struct { + ID int64 + Name string + ParentID sql.NullInt64 + ID_2 int64 + Name_2 string + ParentID_2 sql.NullInt64 +} + +func (q *Queries) AllAuthors(ctx context.Context) ([]AllAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsRow + for rows.Next() { + var i AllAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const allAuthorsAliases = `-- name: AllAuthorsAliases :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors AS a + LEFT JOIN authors AS p + ON a.parent_id = p.id +` + +type AllAuthorsAliasesRow struct { + ID int64 + Name string + ParentID sql.NullInt64 + ID_2 int64 + Name_2 string + ParentID_2 sql.NullInt64 +} + +func (q *Queries) AllAuthorsAliases(ctx context.Context) ([]AllAuthorsAliasesRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthorsAliases) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsAliasesRow + for rows.Next() { + var i AllAuthorsAliasesRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const allAuthorsAliases2 = `-- name: AllAuthorsAliases2 :many +SELECT a.id, a.name, a.parent_id, p.id, p.name, p.parent_id +FROM authors AS a + LEFT JOIN authors AS p + ON a.parent_id = p.id +` + +type AllAuthorsAliases2Row struct { + ID int64 + Name string + ParentID sql.NullInt64 + ID_2 int64 + Name_2 string + ParentID_2 sql.NullInt64 +} + +func (q *Queries) AllAuthorsAliases2(ctx context.Context) ([]AllAuthorsAliases2Row, error) { + rows, err := q.db.QueryContext(ctx, allAuthorsAliases2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsAliases2Row + for rows.Next() { + var i AllAuthorsAliases2Row + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.ID_2, + &i.Name_2, + &i.ParentID_2, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const allSuperAuthors = `-- name: AllSuperAuthors :many +SELECT id, name, parent_id, super_id, super_name, super_parent_id +FROM authors + LEFT JOIN super_authors + ON authors.parent_id = super_authors.super_id +` + +type AllSuperAuthorsRow struct { + ID int64 + Name string + ParentID sql.NullInt64 + SuperID int64 + SuperName string + SuperParentID sql.NullInt64 +} + +func (q *Queries) AllSuperAuthors(ctx context.Context) ([]AllSuperAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsRow + for rows.Next() { + var i AllSuperAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const allSuperAuthorsAliases = `-- name: AllSuperAuthorsAliases :many +SELECT id, name, parent_id, super_id, super_name, super_parent_id +FROM authors AS a + LEFT JOIN super_authors AS sa + ON a.parent_id = sa.super_id +` + +type AllSuperAuthorsAliasesRow struct { + ID int64 + Name string + ParentID sql.NullInt64 + SuperID int64 + SuperName string + SuperParentID sql.NullInt64 +} + +func (q *Queries) AllSuperAuthorsAliases(ctx context.Context) ([]AllSuperAuthorsAliasesRow, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthorsAliases) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsAliasesRow + for rows.Next() { + var i AllSuperAuthorsAliasesRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const allSuperAuthorsAliases2 = `-- name: AllSuperAuthorsAliases2 :many +SELECT a.id, a.name, a.parent_id, sa.super_id, sa.super_name, sa.super_parent_id +FROM authors AS a + LEFT JOIN super_authors AS sa + ON a.parent_id = sa.super_id +` + +type AllSuperAuthorsAliases2Row struct { + ID int64 + Name string + ParentID sql.NullInt64 + SuperID int64 + SuperName string + SuperParentID sql.NullInt64 +} + +func (q *Queries) AllSuperAuthorsAliases2(ctx context.Context) ([]AllSuperAuthorsAliases2Row, error) { + rows, err := q.db.QueryContext(ctx, allSuperAuthorsAliases2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllSuperAuthorsAliases2Row + for rows.Next() { + var i AllSuperAuthorsAliases2Row + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ParentID, + &i.SuperID, + &i.SuperName, + &i.SuperParentID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getMayors = `-- name: GetMayors :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +INNER JOIN mayors USING (mayor_id) +` + +type GetMayorsRow struct { + UserID int64 + FullName string +} + +func (q *Queries) GetMayors(ctx context.Context) ([]GetMayorsRow, error) { + rows, err := q.db.QueryContext(ctx, getMayors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetMayorsRow + for rows.Next() { + var i GetMayorsRow + if err := rows.Scan(&i.UserID, &i.FullName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getMayorsOptional = `-- name: GetMayorsOptional :many +SELECT + user_id, + cities.city_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +LEFT JOIN mayors USING (mayor_id) +` + +type GetMayorsOptionalRow struct { + UserID int64 + CityID int64 + FullName string +} + +func (q *Queries) GetMayorsOptional(ctx context.Context) ([]GetMayorsOptionalRow, error) { + rows, err := q.db.QueryContext(ctx, getMayorsOptional) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetMayorsOptionalRow + for rows.Next() { + var i GetMayorsOptionalRow + if err := rows.Scan(&i.UserID, &i.CityID, &i.FullName); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSuggestedUsersByID = `-- name: GetSuggestedUsersByID :many +SELECT DISTINCT u.user_id, u.user_nickname, u.user_email, u.user_display_name, u.user_password, u.user_google_id, u.user_apple_id, u.user_bio, u.user_created_at, u.user_avatar_id, m.media_id, m.media_created_at, m.media_hash, m.media_directory, m.media_author_id, m.media_width, m.media_height +FROM users_2 AS u + LEFT JOIN media AS m + ON u.user_avatar_id = m.media_id +WHERE u.user_id != @user_id +` + +type GetSuggestedUsersByIDRow struct { + UserID int64 + UserNickname string + UserEmail string + UserDisplayName string + UserPassword sql.NullString + UserGoogleID sql.NullString + UserAppleID sql.NullString + UserBio string + UserCreatedAt time.Time + UserAvatarID sql.NullInt64 + MediaID int64 + MediaCreatedAt time.Time + MediaHash string + MediaDirectory string + MediaAuthorID int64 + MediaWidth int64 + MediaHeight int64 +} + +func (q *Queries) GetSuggestedUsersByID(ctx context.Context, userID int64) ([]GetSuggestedUsersByIDRow, error) { + rows, err := q.db.QueryContext(ctx, getSuggestedUsersByID, userID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetSuggestedUsersByIDRow + for rows.Next() { + var i GetSuggestedUsersByIDRow + if err := rows.Scan( + &i.UserID, + &i.UserNickname, + &i.UserEmail, + &i.UserDisplayName, + &i.UserPassword, + &i.UserGoogleID, + &i.UserAppleID, + &i.UserBio, + &i.UserCreatedAt, + &i.UserAvatarID, + &i.MediaID, + &i.MediaCreatedAt, + &i.MediaHash, + &i.MediaDirectory, + &i.MediaAuthorID, + &i.MediaWidth, + &i.MediaHeight, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/join_left/sqlite/query.sql b/internal/endtoend/testdata/join_left/sqlite/query.sql new file mode 100644 index 0000000000..a88764bf5e --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/query.sql @@ -0,0 +1,110 @@ +-- https://github.com/kyleconroy/sqlc/issues/604 +CREATE TABLE users ( + user_id INT PRIMARY KEY, + city_id INT -- nullable +); +CREATE TABLE cities ( + city_id INT PRIMARY KEY, + mayor_id INT NOT NULL +); +CREATE TABLE mayors ( + mayor_id INT PRIMARY KEY, + full_name TEXT NOT NULL +); + +-- name: GetMayors :many +SELECT + user_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +INNER JOIN mayors USING (mayor_id); + +-- name: GetMayorsOptional :many +SELECT + user_id, + cities.city_id, + mayors.full_name +FROM users +LEFT JOIN cities USING (city_id) +LEFT JOIN mayors USING (mayor_id); + +-- https://github.com/kyleconroy/sqlc/issues/1334 +CREATE TABLE authors ( + id INT PRIMARY KEY, + name TEXT NOT NULL, + parent_id INT -- nullable +); + +CREATE TABLE super_authors ( + super_id INT PRIMARY KEY, + super_name TEXT NOT NULL, + super_parent_id INT -- nullable +); + +-- name: AllAuthors :many +SELECT * +FROM authors AS a + LEFT JOIN authors AS p + ON a.parent_id = p.id; + +-- name: AllAuthorsAliases :many +SELECT * +FROM authors AS a + LEFT JOIN authors AS p + ON a.parent_id = p.id; + +-- name: AllSuperAuthors :many +SELECT * +FROM authors + LEFT JOIN super_authors + ON authors.parent_id = super_authors.super_id; + +-- name: AllAuthorsAliases2 :many +SELECT a.*, p.* +FROM authors AS a + LEFT JOIN authors AS p + ON a.parent_id = p.id; + +-- name: AllSuperAuthorsAliases :many +SELECT * +FROM authors AS a + LEFT JOIN super_authors AS sa + ON a.parent_id = sa.super_id; + +-- name: AllSuperAuthorsAliases2 :many +SELECT a.*, sa.* +FROM authors AS a + LEFT JOIN super_authors AS sa + ON a.parent_id = sa.super_id; + +-- https://github.com/kyleconroy/sqlc/issues/1334 +CREATE TABLE users_2 ( + user_id INT PRIMARY KEY, + user_nickname VARCHAR(30) UNIQUE NOT NULL, + user_email TEXT UNIQUE NOT NULL, + user_display_name TEXT NOT NULL, + user_password TEXT , + user_google_id TEXT UNIQUE , + user_apple_id TEXT UNIQUE , + user_bio VARCHAR(160) NOT NULL DEFAULT '', + user_created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + user_avatar_id INT UNIQUE +); + +CREATE TABLE media ( + media_id INT PRIMARY KEY, + media_created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + media_hash TEXT NOT NULL, + media_directory TEXT NOT NULL, + media_author_id INT NOT NULL, + media_width INT NOT NULL, + media_height INT NOT NULL +); + +-- name: GetSuggestedUsersByID :many +SELECT DISTINCT u.*, m.* +FROM users_2 AS u + LEFT JOIN media AS m + ON u.user_avatar_id = m.media_id +WHERE u.user_id != @user_id; diff --git a/internal/endtoend/testdata/join_left/sqlite/sqlc.json b/internal/endtoend/testdata/join_left/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/join_left/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_left_same_table/sqlite/go/db.go b/internal/endtoend/testdata/join_left_same_table/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/join_left_same_table/sqlite/go/models.go b/internal/endtoend/testdata/join_left_same_table/sqlite/go/models.go new file mode 100644 index 0000000000..8187783ce6 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + ParentID sql.NullInt64 +} diff --git a/internal/endtoend/testdata/join_left_same_table/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_left_same_table/sqlite/go/query.sql.go new file mode 100644 index 0000000000..92dcedd768 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/go/query.sql.go @@ -0,0 +1,55 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const allAuthors = `-- name: AllAuthors :many +SELECT a.id, + a.name, + p.id as alias_id, + p.name as alias_name +FROM authors AS a + LEFT JOIN authors AS p + ON (authors.parent_id = p.id) +` + +type AllAuthorsRow struct { + ID int64 + Name string + AliasID int64 + AliasName string +} + +func (q *Queries) AllAuthors(ctx context.Context) ([]AllAuthorsRow, error) { + rows, err := q.db.QueryContext(ctx, allAuthors) + if err != nil { + return nil, err + } + defer rows.Close() + var items []AllAuthorsRow + for rows.Next() { + var i AllAuthorsRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.AliasID, + &i.AliasName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/join_left_same_table/sqlite/query.sql b/internal/endtoend/testdata/join_left_same_table/sqlite/query.sql new file mode 100644 index 0000000000..56d3757635 --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/query.sql @@ -0,0 +1,14 @@ +CREATE TABLE authors ( + id INT NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + parent_id INT +); + +-- name: AllAuthors :many +SELECT a.id, + a.name, + p.id as alias_id, + p.name as alias_name +FROM authors AS a + LEFT JOIN authors AS p + ON (authors.parent_id = p.id); diff --git a/internal/endtoend/testdata/join_left_same_table/sqlite/sqlc.json b/internal/endtoend/testdata/join_left_same_table/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/join_left_same_table/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_table_name/sqlite/go/db.go b/internal/endtoend/testdata/join_table_name/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/join_table_name/sqlite/go/models.go b/internal/endtoend/testdata/join_table_name/sqlite/go/models.go new file mode 100644 index 0000000000..fad9c78581 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/go/models.go @@ -0,0 +1,18 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Bar struct { + ID int64 +} + +type Foo struct { + ID int64 + Bar sql.NullInt64 +} diff --git a/internal/endtoend/testdata/join_table_name/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_table_name/sqlite/go/query.sql.go new file mode 100644 index 0000000000..bb5702cca7 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/go/query.sql.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const tableName = `-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = ? AND foo.id = ? +` + +type TableNameParams struct { + ID int64 + ID_2 int64 +} + +func (q *Queries) TableName(ctx context.Context, arg TableNameParams) (int64, error) { + row := q.db.QueryRowContext(ctx, tableName, arg.ID, arg.ID_2) + var id int64 + err := row.Scan(&id) + return id, err +} diff --git a/internal/endtoend/testdata/join_table_name/sqlite/query.sql b/internal/endtoend/testdata/join_table_name/sqlite/query.sql new file mode 100644 index 0000000000..b3cb5f12a2 --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/query.sql @@ -0,0 +1,8 @@ +CREATE TABLE bar (id integer not null); +CREATE TABLE foo (id integer not null, bar integer references bar(id)); + +-- name: TableName :one +SELECT foo.id +FROM foo +JOIN bar ON foo.bar = bar.id +WHERE bar.id = ? AND foo.id = ?; diff --git a/internal/endtoend/testdata/join_table_name/sqlite/sqlc.json b/internal/endtoend/testdata/join_table_name/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/join_table_name/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_two_tables/sqlite/go/db.go b/internal/endtoend/testdata/join_two_tables/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/join_two_tables/sqlite/go/models.go b/internal/endtoend/testdata/join_two_tables/sqlite/go/models.go new file mode 100644 index 0000000000..852d86d7c4 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/go/models.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Bar struct { + ID int64 +} + +type Baz struct { + ID int64 +} + +type Foo struct { + BarID int64 + BazID int64 +} diff --git a/internal/endtoend/testdata/join_two_tables/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_two_tables/sqlite/go/query.sql.go new file mode 100644 index 0000000000..fc2d8b30b2 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const twoJoins = `-- name: TwoJoins :many +SELECT foo.bar_id, foo.baz_id +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id +` + +func (q *Queries) TwoJoins(ctx context.Context) ([]Foo, error) { + rows, err := q.db.QueryContext(ctx, twoJoins) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foo + for rows.Next() { + var i Foo + if err := rows.Scan(&i.BarID, &i.BazID); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/join_two_tables/sqlite/query.sql b/internal/endtoend/testdata/join_two_tables/sqlite/query.sql new file mode 100644 index 0000000000..bd5fd19f50 --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/query.sql @@ -0,0 +1,9 @@ +CREATE TABLE foo (bar_id integer not null, baz_id integer not null); +CREATE TABLE bar (id integer not null); +CREATE TABLE baz (id integer not null); + +-- name: TwoJoins :many +SELECT foo.* +FROM foo +JOIN bar ON bar.id = bar_id +JOIN baz ON baz.id = baz_id; diff --git a/internal/endtoend/testdata/join_two_tables/sqlite/sqlc.json b/internal/endtoend/testdata/join_two_tables/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/join_two_tables/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/go/db.go b/internal/endtoend/testdata/join_where_clause/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/go/models.go b/internal/endtoend/testdata/join_where_clause/sqlite/go/models.go new file mode 100644 index 0000000000..b626555450 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/go/models.go @@ -0,0 +1,16 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Bar struct { + ID int64 + Owner string +} + +type Foo struct { + Barid int64 +} diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_where_clause/sqlite/go/query.sql.go new file mode 100644 index 0000000000..07a1db395b --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/go/query.sql.go @@ -0,0 +1,40 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const joinWhereClause = `-- name: JoinWhereClause :many +SELECT foo.barid +FROM foo +JOIN bar ON bar.id = barid +WHERE owner = ? +` + +func (q *Queries) JoinWhereClause(ctx context.Context, owner string) ([]int64, error) { + rows, err := q.db.QueryContext(ctx, joinWhereClause, owner) + if err != nil { + return nil, err + } + defer rows.Close() + var items []int64 + for rows.Next() { + var barid int64 + if err := rows.Scan(&barid); err != nil { + return nil, err + } + items = append(items, barid) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/query.sql b/internal/endtoend/testdata/join_where_clause/sqlite/query.sql new file mode 100644 index 0000000000..1a95284227 --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/query.sql @@ -0,0 +1,8 @@ +CREATE TABLE foo (barid integer not null); +CREATE TABLE bar (id integer not null, owner text not null); + +-- name: JoinWhereClause :many +SELECT foo.* +FROM foo +JOIN bar ON bar.id = barid +WHERE owner = ?; diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/sqlc.json b/internal/endtoend/testdata/join_where_clause/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/join_where_clause/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/limit/sqlite/go/db.go b/internal/endtoend/testdata/limit/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/limit/sqlite/go/models.go b/internal/endtoend/testdata/limit/sqlite/go/models.go new file mode 100644 index 0000000000..0a2313d91e --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Foo struct { + Bar bool +} diff --git a/internal/endtoend/testdata/limit/sqlite/go/query.sql.go b/internal/endtoend/testdata/limit/sqlite/go/query.sql.go new file mode 100644 index 0000000000..ac2d95ddad --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/go/query.sql.go @@ -0,0 +1,37 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const limitMe = `-- name: LimitMe :many +SELECT bar FROM foo LIMIT ? +` + +func (q *Queries) LimitMe(ctx context.Context, limit int64) ([]bool, error) { + rows, err := q.db.QueryContext(ctx, limitMe, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []bool + for rows.Next() { + var bar bool + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/limit/sqlite/query.sql b/internal/endtoend/testdata/limit/sqlite/query.sql new file mode 100644 index 0000000000..e7e373d13b --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/query.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (bar bool not null); + +-- name: LimitMe :many +SELECT bar FROM foo LIMIT ?; diff --git a/internal/endtoend/testdata/limit/sqlite/sqlc.json b/internal/endtoend/testdata/limit/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/limit/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/select_limit/sqlite/go/db.go b/internal/endtoend/testdata/select_limit/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/select_limit/sqlite/go/models.go b/internal/endtoend/testdata/select_limit/sqlite/go/models.go new file mode 100644 index 0000000000..1628a7e8fe --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/go/models.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + A sql.NullString +} diff --git a/internal/endtoend/testdata/select_limit/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_limit/sqlite/go/query.sql.go new file mode 100644 index 0000000000..98252e140b --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/go/query.sql.go @@ -0,0 +1,72 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const fooLimit = `-- name: FooLimit :many +SELECT a FROM foo +LIMIT ? +` + +func (q *Queries) FooLimit(ctx context.Context, limit int64) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, fooLimit, limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const fooLimitOffset = `-- name: FooLimitOffset :many +SELECT a FROM foo +LIMIT ? OFFSET ? +` + +type FooLimitOffsetParams struct { + Limit int64 + Offset int64 +} + +func (q *Queries) FooLimitOffset(ctx context.Context, arg FooLimitOffsetParams) ([]sql.NullString, error) { + rows, err := q.db.QueryContext(ctx, fooLimitOffset, arg.Limit, arg.Offset) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var a sql.NullString + if err := rows.Scan(&a); err != nil { + return nil, err + } + items = append(items, a) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_limit/sqlite/query.sql b/internal/endtoend/testdata/select_limit/sqlite/query.sql new file mode 100644 index 0000000000..4b5e81997f --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/query.sql @@ -0,0 +1,9 @@ +CREATE TABLE foo (a text); + +/* name: FooLimit :many */ +SELECT a FROM foo +LIMIT ?; + +/* name: FooLimitOffset :many */ +SELECT a FROM foo +LIMIT ? OFFSET ?; diff --git a/internal/endtoend/testdata/select_limit/sqlite/sqlc.json b/internal/endtoend/testdata/select_limit/sqlite/sqlc.json new file mode 100644 index 0000000000..9aea94d599 --- /dev/null +++ b/internal/endtoend/testdata/select_limit/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "_lemon", + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/select_nested_count/sqlite/go/db.go b/internal/endtoend/testdata/select_nested_count/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/select_nested_count/sqlite/go/models.go b/internal/endtoend/testdata/select_nested_count/sqlite/go/models.go new file mode 100644 index 0000000000..edc67365cb --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/go/models.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type Book struct { + ID int64 + AuthorID int64 + Title string +} diff --git a/internal/endtoend/testdata/select_nested_count/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_nested_count/sqlite/go/query.sql.go new file mode 100644 index 0000000000..d65c4cff12 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/go/query.sql.go @@ -0,0 +1,54 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const getAuthorsWithBooksCount = `-- name: GetAuthorsWithBooksCount :many +SELECT id, name, bio, ( + SELECT COUNT(id) FROM books + WHERE books.author_id = id +) AS books_count +FROM authors +` + +type GetAuthorsWithBooksCountRow struct { + ID int64 + Name string + Bio sql.NullString + BooksCount int64 +} + +func (q *Queries) GetAuthorsWithBooksCount(ctx context.Context) ([]GetAuthorsWithBooksCountRow, error) { + rows, err := q.db.QueryContext(ctx, getAuthorsWithBooksCount) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAuthorsWithBooksCountRow + for rows.Next() { + var i GetAuthorsWithBooksCountRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Bio, + &i.BooksCount, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/select_nested_count/sqlite/query.sql b/internal/endtoend/testdata/select_nested_count/sqlite/query.sql new file mode 100644 index 0000000000..fb9d37dfa1 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/query.sql @@ -0,0 +1,19 @@ +CREATE TABLE authors ( + id bigint PRIMARY KEY, + name text NOT NULL, + bio text +); + +CREATE TABLE books ( + id bigint PRIMARY KEY, + author_id bigint NOT NULL + REFERENCES authors(id), + title text NOT NULL +); + +-- name: GetAuthorsWithBooksCount :many +SELECT *, ( + SELECT COUNT(id) FROM books + WHERE books.author_id = id +) AS books_count +FROM authors; diff --git a/internal/endtoend/testdata/select_nested_count/sqlite/sqlc.json b/internal/endtoend/testdata/select_nested_count/sqlite/sqlc.json new file mode 100644 index 0000000000..9b0e5b8391 --- /dev/null +++ b/internal/endtoend/testdata/select_nested_count/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql", + "engine": "_lemon" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/go/db.go b/internal/endtoend/testdata/single_param_conflict/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/go/models.go b/internal/endtoend/testdata/single_param_conflict/sqlite/go/models.go new file mode 100644 index 0000000000..e51f413f35 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/go/models.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "database/sql" +) + +type Author struct { + ID int64 + Name string + Bio sql.NullString +} + +type User struct { + Sub string +} diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/go/query.sql.go b/internal/endtoend/testdata/single_param_conflict/sqlite/go/query.sql.go new file mode 100644 index 0000000000..85f24715e6 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/go/query.sql.go @@ -0,0 +1,50 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAuthorByID = `-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = ? +LIMIT 1 +` + +func (q *Queries) GetAuthorByID(ctx context.Context, id int64) (Author, error) { + row := q.db.QueryRowContext(ctx, getAuthorByID, id) + var i Author + err := row.Scan(&i.ID, &i.Name, &i.Bio) + return i, err +} + +const getAuthorIDByID = `-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = ? +LIMIT 1 +` + +func (q *Queries) GetAuthorIDByID(ctx context.Context, id int64) (int64, error) { + row := q.db.QueryRowContext(ctx, getAuthorIDByID, id) + err := row.Scan(&id) + return id, err +} + +const getUser = `-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = ? +LIMIT 1 +` + +func (q *Queries) GetUser(ctx context.Context, sub string) (string, error) { + row := q.db.QueryRowContext(ctx, getUser, sub) + err := row.Scan(&sub) + return sub, err +} diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/query.sql b/internal/endtoend/testdata/single_param_conflict/sqlite/query.sql new file mode 100644 index 0000000000..f5b577e27f --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/query.sql @@ -0,0 +1,29 @@ +-- Example queries for sqlc +CREATE TABLE authors ( + id BIGINT PRIMARY KEY, + name TEXT NOT NULL, + bio text +); + +-- name: GetAuthorIDByID :one +SELECT id +FROM authors +WHERE id = ? +LIMIT 1; + +-- name: GetAuthorByID :one +SELECT id, name, bio +FROM authors +WHERE id = ? +LIMIT 1; + +-- https://github.com/kyleconroy/sqlc/issues/1290 +CREATE TABLE users ( + sub TEXT PRIMARY KEY +); + +-- name: GetUser :one +SELECT sub +FROM users +WHERE sub = ? +LIMIT 1; diff --git a/internal/endtoend/testdata/single_param_conflict/sqlite/sqlc.json b/internal/endtoend/testdata/single_param_conflict/sqlite/sqlc.json new file mode 100644 index 0000000000..9aea94d599 --- /dev/null +++ b/internal/endtoend/testdata/single_param_conflict/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "_lemon", + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/update_set/sqlite/go/db.go b/internal/endtoend/testdata/update_set/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/update_set/sqlite/go/models.go b/internal/endtoend/testdata/update_set/sqlite/go/models.go new file mode 100644 index 0000000000..891700ec8e --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set/sqlite/go/query.sql.go b/internal/endtoend/testdata/update_set/sqlite/go/query.sql.go new file mode 100644 index 0000000000..cf6e11b8a9 --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSet = `-- name: UpdateSet :exec +UPDATE foo SET name = ? WHERE slug = ? +` + +type UpdateSetParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateSet(ctx context.Context, arg UpdateSetParams) error { + _, err := q.db.ExecContext(ctx, updateSet, arg.Name, arg.Slug) + return err +} diff --git a/internal/endtoend/testdata/update_set/sqlite/query.sql b/internal/endtoend/testdata/update_set/sqlite/query.sql new file mode 100644 index 0000000000..5b2fb0e625 --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/query.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (name text not null, slug text not null); + +/* name: UpdateSet :exec */ +UPDATE foo SET name = ? WHERE slug = ?; diff --git a/internal/endtoend/testdata/update_set/sqlite/sqlc.json b/internal/endtoend/testdata/update_set/sqlite/sqlc.json new file mode 100644 index 0000000000..9aea94d599 --- /dev/null +++ b/internal/endtoend/testdata/update_set/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "engine": "_lemon", + "path": "go", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/go/db.go b/internal/endtoend/testdata/update_set_multiple/sqlite/go/db.go new file mode 100644 index 0000000000..19557a6a5a --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/go/models.go b/internal/endtoend/testdata/update_set_multiple/sqlite/go/models.go new file mode 100644 index 0000000000..891700ec8e --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 + +package querytest + +import () + +type Foo struct { + Name string + Slug string +} diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/go/query.sql.go b/internal/endtoend/testdata/update_set_multiple/sqlite/go/query.sql.go new file mode 100644 index 0000000000..fd82519eef --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/go/query.sql.go @@ -0,0 +1,24 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.14.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const updateSetMultiple = `-- name: UpdateSetMultiple :exec +UPDATE foo SET name = ?, slug = ? +` + +type UpdateSetMultipleParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateSetMultiple(ctx context.Context, arg UpdateSetMultipleParams) error { + _, err := q.db.ExecContext(ctx, updateSetMultiple, arg.Name, arg.Slug) + return err +} diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/query.sql b/internal/endtoend/testdata/update_set_multiple/sqlite/query.sql new file mode 100644 index 0000000000..a049f90c05 --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/query.sql @@ -0,0 +1,4 @@ +CREATE TABLE foo (name text not null, slug text not null); + +-- name: UpdateSetMultiple :exec +UPDATE foo SET name = ?, slug = ?; diff --git a/internal/endtoend/testdata/update_set_multiple/sqlite/sqlc.json b/internal/endtoend/testdata/update_set_multiple/sqlite/sqlc.json new file mode 100644 index 0000000000..2ef8a6a81d --- /dev/null +++ b/internal/endtoend/testdata/update_set_multiple/sqlite/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "_lemon", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} \ No newline at end of file diff --git a/internal/engine/sqlite/convert.go b/internal/engine/sqlite/convert.go index bde50cafac..99d66c7e12 100644 --- a/internal/engine/sqlite/convert.go +++ b/internal/engine/sqlite/convert.go @@ -1,45 +1,66 @@ package sqlite import ( - "github.com/antlr/antlr4/runtime/Go/antlr" + "log" "strconv" "strings" + "github.com/antlr/antlr4/runtime/Go/antlr" + + "github.com/kyleconroy/sqlc/internal/debug" "github.com/kyleconroy/sqlc/internal/engine/sqlite/parser" "github.com/kyleconroy/sqlc/internal/sql/ast" ) +type cc struct { + paramCount int +} + type node interface { GetParser() antlr.Parser } -func convertAlter_table_stmtContext(c *parser.Alter_table_stmtContext) ast.Node { +func todo(n node) *ast.TODO { + if debug.Active { + log.Printf("sqlite.convert: Unknown node type %T\n", n) + } + return &ast.TODO{} +} - if c.RENAME_() != nil { - if newTable, ok := c.New_table_name().(*parser.New_table_nameContext); ok { +func identifier(id string) string { + return strings.ToLower(id) +} + +func NewIdentifer(t string) *ast.String { + return &ast.String{Str: identifier(t)} +} + +func (c *cc) convertAlter_table_stmtContext(n *parser.Alter_table_stmtContext) ast.Node { + if n.RENAME_() != nil { + if newTable, ok := n.New_table_name().(*parser.New_table_nameContext); ok { name := newTable.Any_name().GetText() return &ast.RenameTableStmt{ - Table: parseTableName(c), + Table: parseTableName(n), NewName: &name, } } - if newCol, ok := c.GetNew_column_name().(*parser.Column_nameContext); ok { + if newCol, ok := n.GetNew_column_name().(*parser.Column_nameContext); ok { name := newCol.Any_name().GetText() return &ast.RenameColumnStmt{ - Table: parseTableName(c), + Table: parseTableName(n), Col: &ast.ColumnRef{ - Name: c.GetOld_column_name().GetText(), + Name: n.GetOld_column_name().GetText(), }, NewName: &name, } } } - if c.ADD_() != nil { - if def, ok := c.Column_def().(*parser.Column_defContext); ok { + if n.ADD_() != nil { + if def, ok := n.Column_def().(*parser.Column_defContext); ok { stmt := &ast.AlterTableStmt{ - Table: parseTableName(c), + Table: parseTableName(n), Cmds: &ast.List{}, } name := def.Column_name().GetText() @@ -51,19 +72,19 @@ func convertAlter_table_stmtContext(c *parser.Alter_table_stmtContext) ast.Node TypeName: &ast.TypeName{ Name: def.Type_name().GetText(), }, + IsNotNull: hasNotNullConstraint(def.AllColumn_constraint()), }, }) return stmt } } - if c.DROP_() != nil { + if n.DROP_() != nil { stmt := &ast.AlterTableStmt{ - Table: parseTableName(c), + Table: parseTableName(n), Cmds: &ast.List{}, } - name := c.Column_name(0).GetText() - //fmt.Printf("column: %s", name) + name := n.Column_name(0).GetText() stmt.Cmds.Items = append(stmt.Cmds.Items, &ast.AlterTableCmd{ Name: &name, Subtype: ast.AT_DropColumn, @@ -71,22 +92,22 @@ func convertAlter_table_stmtContext(c *parser.Alter_table_stmtContext) ast.Node return stmt } - return &ast.TODO{} + return todo(n) } -func convertAttach_stmtContext(c *parser.Attach_stmtContext) ast.Node { - name := c.Schema_name().GetText() +func (c *cc) convertAttach_stmtContext(n *parser.Attach_stmtContext) ast.Node { + name := n.Schema_name().GetText() return &ast.CreateSchemaStmt{ Name: &name, } } -func convertCreate_table_stmtContext(c *parser.Create_table_stmtContext) ast.Node { +func (c *cc) convertCreate_table_stmtContext(n *parser.Create_table_stmtContext) ast.Node { stmt := &ast.CreateTableStmt{ - Name: parseTableName(c), - IfNotExists: c.EXISTS_() != nil, + Name: parseTableName(n), + IfNotExists: n.EXISTS_() != nil, } - for _, idef := range c.AllColumn_def() { + for _, idef := range n.AllColumn_def() { if def, ok := idef.(*parser.Column_defContext); ok { stmt.Cols = append(stmt.Cols, &ast.ColumnDef{ Colname: identifier(def.Column_name().GetText()), @@ -98,8 +119,29 @@ func convertCreate_table_stmtContext(c *parser.Create_table_stmtContext) ast.Nod return stmt } -func convertDelete_stmtContext(c *parser.Delete_stmtContext) ast.Node { - if qualifiedName, ok := c.Qualified_table_name().(*parser.Qualified_table_nameContext); ok { +func (c *cc) convertCreate_view_stmtContext(n *parser.Create_view_stmtContext) ast.Node { + viewName := n.View_name().GetText() + relation := &ast.RangeVar{ + Relname: &viewName, + } + + if n.Schema_name() != nil { + schemaName := n.Schema_name().GetText() + relation.Schemaname = &schemaName + } + + return &ast.ViewStmt{ + View: relation, + Aliases: &ast.List{}, + Query: c.convert(n.Select_stmt()), + Replace: false, + Options: &ast.List{}, + WithCheckOption: ast.ViewCheckOption(0), + } +} + +func (c *cc) convertDelete_stmtContext(n *parser.Delete_stmtContext) ast.Node { + if qualifiedName, ok := n.Qualified_table_name().(*parser.Qualified_table_nameContext); ok { tableName := qualifiedName.Table_name().GetText() relation := &ast.RangeVar{ @@ -122,93 +164,87 @@ func convertDelete_stmtContext(c *parser.Delete_stmtContext) ast.Node { WithClause: nil, } - if c.WHERE_() != nil { - if c.Expr() != nil { - delete.WhereClause = convert(c.Expr()) - } + if n.WHERE_() != nil && n.Expr() != nil { + delete.WhereClause = c.convert(n.Expr()) } return delete } - return &ast.TODO{} + return todo(n) } -func convertDrop_stmtContext(c *parser.Drop_stmtContext) ast.Node { - if c.TABLE_() != nil { +func (c *cc) convertDrop_stmtContext(n *parser.Drop_stmtContext) ast.Node { + if n.TABLE_() != nil || n.VIEW_() != nil { name := ast.TableName{ - Name: c.Any_name().GetText(), + Name: n.Any_name().GetText(), } - if c.Schema_name() != nil { - name.Schema = c.Schema_name().GetText() + if n.Schema_name() != nil { + name.Schema = n.Schema_name().GetText() } return &ast.DropTableStmt{ - IfExists: c.EXISTS_() != nil, + IfExists: n.EXISTS_() != nil, Tables: []*ast.TableName{&name}, } - } else { - return &ast.TODO{} } + return todo(n) } -func identifier(id string) string { - return strings.ToLower(id) -} - -func NewIdentifer(t string) *ast.String { - return &ast.String{Str: identifier(t)} -} - -func convertFuncContext(c *parser.Expr_functionContext) ast.Node { - if name, ok := c.Function_name().(*parser.Function_nameContext); ok { +func (c *cc) convertFuncContext(n *parser.Expr_functionContext) ast.Node { + if name, ok := n.Function_name().(*parser.Function_nameContext); ok { funcName := strings.ToLower(name.GetText()) - var args []ast.Node - for _, exp := range c.AllExpr() { - args = append(args, convert(exp)) + var argNodes []ast.Node + for _, exp := range n.AllExpr() { + argNodes = append(argNodes, c.convert(exp)) } + args := &ast.List{Items: argNodes} - fn := &ast.FuncCall{ - Func: &ast.FuncName{ - Name: funcName, - }, - Funcname: &ast.List{ - Items: []ast.Node{ - NewIdentifer(funcName), + if funcName == "coalesce" { + return &ast.CoalesceExpr{ + Args: args, + } + } else { + return &ast.FuncCall{ + Func: &ast.FuncName{ + Name: funcName, }, - }, - AggStar: c.STAR() != nil, - Args: &ast.List{Items: args}, - AggOrder: &ast.List{}, - AggDistinct: c.DISTINCT_() != nil, + Funcname: &ast.List{ + Items: []ast.Node{ + NewIdentifer(funcName), + }, + }, + AggStar: n.STAR() != nil, + Args: args, + AggOrder: &ast.List{}, + AggDistinct: n.DISTINCT_() != nil, + } } - - return fn } - return &ast.TODO{} + return todo(n) } -func convertExprContext(c *parser.ExprContext) ast.Node { - return &ast.TODO{} +func (c *cc) convertExprContext(n *parser.ExprContext) ast.Node { + return &ast.Expr{} } -func convertColumnNameExpr(c *parser.Expr_qualified_column_nameContext) *ast.ColumnRef { +func (c *cc) convertColumnNameExpr(n *parser.Expr_qualified_column_nameContext) *ast.ColumnRef { var items []ast.Node - if schema, ok := c.Schema_name().(*parser.Schema_nameContext); ok { + if schema, ok := n.Schema_name().(*parser.Schema_nameContext); ok { schemaText := schema.GetText() if schemaText != "" { items = append(items, NewIdentifer(schemaText)) } } - if table, ok := c.Table_name().(*parser.Table_nameContext); ok { + if table, ok := n.Table_name().(*parser.Table_nameContext); ok { tableName := table.GetText() if tableName != "" { items = append(items, NewIdentifer(tableName)) } } - items = append(items, NewIdentifer(c.Column_name().GetText())) + items = append(items, NewIdentifer(n.Column_name().GetText())) return &ast.ColumnRef{ Fields: &ast.List{ Items: items, @@ -216,73 +252,90 @@ func convertColumnNameExpr(c *parser.Expr_qualified_column_nameContext) *ast.Col } } -func convertComparison(c *parser.Expr_comparisonContext) ast.Node { +func (c *cc) convertComparison(n *parser.Expr_comparisonContext) ast.Node { aExpr := &ast.A_Expr{ Name: &ast.List{ Items: []ast.Node{ &ast.String{Str: "="}, // TODO: add actual comparison }, }, - Lexpr: convert(c.Expr(0)), - Rexpr: convert(c.Expr(1)), + Lexpr: c.convert(n.Expr(0)), + Rexpr: c.convert(n.Expr(1)), } return aExpr } -func convertSimpleSelect_stmtContext(c *parser.Simple_select_stmtContext) ast.Node { - if core, ok := c.Select_core().(*parser.Select_coreContext); ok { - cols := getCols(core) - tables := getTables(core) - - return &ast.SelectStmt{ - FromClause: &ast.List{Items: tables}, - TargetList: &ast.List{Items: cols}, - } - } - - return &ast.TODO{} -} - -func convertMultiSelect_stmtContext(c multiselect) ast.Node { +func (c *cc) convertMultiSelect_stmtContext(n *parser.Select_stmtContext) ast.Node { var tables []ast.Node var cols []ast.Node - for _, icore := range c.AllSelect_core() { + var where ast.Node + var groups = []ast.Node{} + var having ast.Node + + for _, icore := range n.AllSelect_core() { core, ok := icore.(*parser.Select_coreContext) if !ok { continue } - cols = append(cols, getCols(core)...) - tables = append(tables, getTables(core)...) + cols = append(cols, c.getCols(core)...) + tables = append(tables, c.getTables(core)...) + + i := 0 + if core.WHERE_() != nil { + where = c.convert(core.Expr(i)) + i++ + } + + if core.GROUP_() != nil { + l := len(core.AllExpr()) - i + if core.HAVING_() != nil { + having = c.convert(core.Expr(l)) + l-- + } + + for i < l { + groups = append(groups, c.convert(core.Expr(i))) + i++ + } + } } + + window := &ast.List{Items: []ast.Node{}} + if n.Order_by_stmt() != nil { + window.Items = append(window.Items, c.convert(n.Order_by_stmt())) + } + + limitCount, limitOffset := c.convertLimit_stmtContext(n.Limit_stmt()) + return &ast.SelectStmt{ - FromClause: &ast.List{Items: tables}, - TargetList: &ast.List{Items: cols}, + FromClause: &ast.List{Items: tables}, + TargetList: &ast.List{Items: cols}, + WhereClause: where, + GroupClause: &ast.List{Items: groups}, + HavingClause: having, + WindowClause: window, + LimitCount: limitCount, + LimitOffset: limitOffset, + ValuesLists: &ast.List{}, } } -func getTables(core *parser.Select_coreContext) []ast.Node { +func (c *cc) getTables(core *parser.Select_coreContext) []ast.Node { var tables []ast.Node - for _, ifrom := range core.AllTable_or_subquery() { - from, ok := ifrom.(*parser.Table_or_subqueryContext) - if !ok { - continue - } - rel := from.Table_name().GetText() - name := ast.RangeVar{ - Relname: &rel, - Location: from.GetStart().GetStart(), - } - if from.Schema_name() != nil { - text := from.Schema_name().GetText() - name.Schemaname = &text + tables = append(tables, c.convertTablesOrSubquery(core.AllTable_or_subquery())...) + + if core.Join_clause() != nil { + join, ok := core.Join_clause().(*parser.Join_clauseContext) + if ok { + tables = append(tables, c.convertTablesOrSubquery(join.AllTable_or_subquery())...) } - tables = append(tables, &name) } + return tables } -func getCols(core *parser.Select_coreContext) []ast.Node { +func (c *cc) getCols(core *parser.Select_coreContext) []ast.Node { var cols []ast.Node for _, icol := range core.AllResult_column() { col, ok := icol.(*parser.Result_columnContext) @@ -296,16 +349,9 @@ func getCols(core *parser.Select_coreContext) []ast.Node { iexpr := col.Expr() switch { case col.STAR() != nil: - val = &ast.ColumnRef{ - Fields: &ast.List{ - Items: []ast.Node{ - &ast.A_Star{}, - }, - }, - Location: col.GetStart().GetStart(), - } + val = c.convertWildCardField(col) case iexpr != nil: - val = convert(iexpr) + val = c.convert(iexpr) } if val == nil { @@ -323,84 +369,133 @@ func getCols(core *parser.Select_coreContext) []ast.Node { return cols } -func convertSql_stmtContext(n *parser.Sql_stmtContext) ast.Node { +func (c *cc) convertWildCardField(n *parser.Result_columnContext) *ast.ColumnRef { + items := []ast.Node{} + if n.Table_name() != nil { + items = append(items, NewIdentifer(n.Table_name().GetText())) + } + items = append(items, &ast.A_Star{}) + + return &ast.ColumnRef{ + Fields: &ast.List{ + Items: items, + }, + Location: n.GetStart().GetStart(), + } +} + +func (c *cc) convertOrderby_stmtContext(n parser.IOrder_by_stmtContext) ast.Node { + if orderBy, ok := n.(*parser.Order_by_stmtContext); ok { + list := &ast.List{Items: []ast.Node{}} + for _, o := range orderBy.AllOrdering_term() { + term, ok := o.(*parser.Ordering_termContext) + if !ok { + continue + } + list.Items = append(list.Items, &ast.CaseExpr{ + Xpr: c.convert(term.Expr()), + Location: term.Expr().GetStart().GetStart(), + }) + } + return list + } + return todo(n) +} + +func (c *cc) convertLimit_stmtContext(n parser.ILimit_stmtContext) (ast.Node, ast.Node) { + if n == nil { + return nil, nil + } + + var limitCount, limitOffset ast.Node + if limit, ok := n.(*parser.Limit_stmtContext); ok { + limitCount = c.convert(limit.Expr(0)) + if limit.OFFSET_() != nil { + limitOffset = c.convert(limit.Expr(1)) + } + } + + return limitCount, limitOffset +} + +func (c *cc) convertSql_stmtContext(n *parser.Sql_stmtContext) ast.Node { if stmt := n.Alter_table_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Analyze_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Attach_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Begin_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Commit_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Create_index_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Create_table_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Create_trigger_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Create_view_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Create_virtual_table_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Delete_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Delete_stmt_limited(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Detach_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Drop_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Insert_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Pragma_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Reindex_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Release_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Rollback_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Savepoint_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Select_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Update_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Update_stmt_limited(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } if stmt := n.Vacuum_stmt(); stmt != nil { - return convert(stmt) + return c.convert(stmt) } return nil } -func convertLiteral(c *parser.Expr_literalContext) ast.Node { - if literal, ok := c.Literal_value().(*parser.Literal_valueContext); ok { +func (c *cc) convertLiteral(n *parser.Expr_literalContext) ast.Node { + if literal, ok := n.Literal_value().(*parser.Literal_valueContext); ok { if literal.NUMERIC_LITERAL() != nil { i, _ := strconv.ParseInt(literal.GetText(), 10, 64) @@ -425,103 +520,241 @@ func convertLiteral(c *parser.Expr_literalContext) ast.Node { Val: &ast.Integer{Ival: i}, } } - } - return &ast.TODO{} + return todo(n) } -func convertMathOperationNode(c *parser.Expr_math_opContext) ast.Node { +func (c *cc) convertMathOperationNode(n *parser.Expr_math_opContext) ast.Node { return &ast.A_Expr{ Name: &ast.List{ Items: []ast.Node{ &ast.String{Str: "+"}, // todo: Convert operation types }, }, - Lexpr: convert(c.Expr(0)), - Rexpr: convert(c.Expr(1)), + Lexpr: c.convert(n.Expr(0)), + Rexpr: c.convert(n.Expr(1)), } } -func convertBinaryNode(c *parser.Expr_binaryContext) ast.Node { +func (c *cc) convertBinaryNode(n *parser.Expr_binaryContext) ast.Node { return &ast.BoolExpr{ // TODO: Set op Args: &ast.List{ Items: []ast.Node{ - convert(c.Expr(0)), - convert(c.Expr(1)), + c.convert(n.Expr(0)), + c.convert(n.Expr(1)), }, }, } } -func convertParam(c *parser.Expr_bindContext) ast.Node { - if c.BIND_PARAMETER() != nil { - return &ast.ParamRef{ // TODO: Need to count these up instead of always using 0 - Location: c.GetStart().GetStart(), +func (c *cc) convertParam(n *parser.Expr_bindContext) ast.Node { + if n.BIND_PARAMETER() != nil { + // Parameter numbers start at one + c.paramCount += 1 + return &ast.ParamRef{ + Number: c.paramCount, + Location: n.GetStart().GetStart(), } } - return &ast.TODO{} + return todo(n) +} + +func (c *cc) convertInSelectNode(n *parser.Expr_in_selectContext) ast.Node { + return c.convert(n.Select_stmt()) } -func convert(node node) ast.Node { +func (c *cc) convertInsert_stmtContext(n *parser.Insert_stmtContext) ast.Node { + tableName := n.Table_name().GetText() + rel := &ast.RangeVar{ + Relname: &tableName, + } + if n.Schema_name() != nil { + schemaName := n.Schema_name().GetText() + rel.Schemaname = &schemaName + } + if n.Table_alias() != nil { + tableAlias := n.Table_alias().GetText() + rel.Alias = &ast.Alias{ + Aliasname: &tableAlias, + } + } + + insert := &ast.InsertStmt{ + Relation: rel, + Cols: c.convertColumnNames(n.AllColumn_name()), + ReturningList: &ast.List{}, + } + + if ss, ok := c.convert(n.Select_stmt()).(*ast.SelectStmt); ok { + ss.ValuesLists = &ast.List{} + insert.SelectStmt = ss + } else { + insert.SelectStmt = &ast.SelectStmt{ + FromClause: &ast.List{}, + TargetList: &ast.List{}, + ValuesLists: c.convertExprLists(n.AllExpr()), + } + } + + return insert +} + +func (c *cc) convertExprLists(lists []parser.IExprContext) *ast.List { + list := &ast.List{Items: []ast.Node{}} + n := len(lists) + inner := &ast.List{Items: []ast.Node{}} + for i := 0; i < n; i++ { + inner.Items = append(inner.Items, c.convert(lists[i])) + } + list.Items = append(list.Items, inner) + return list +} + +func (c *cc) convertColumnNames(cols []parser.IColumn_nameContext) *ast.List { + list := &ast.List{Items: []ast.Node{}} + for _, c := range cols { + name := c.GetText() + list.Items = append(list.Items, &ast.ResTarget{ + Name: &name, + }) + } + return list +} + +func (c *cc) convertTablesOrSubquery(tableOrSubquery []parser.ITable_or_subqueryContext) []ast.Node { + var tables []ast.Node + for _, ifrom := range tableOrSubquery { + from, ok := ifrom.(*parser.Table_or_subqueryContext) + if !ok { + continue + } + rel := from.Table_name().GetText() + name := ast.RangeVar{ + Relname: &rel, + Location: from.GetStart().GetStart(), + } + if from.Schema_name() != nil { + schema := from.Schema_name().GetText() + name.Schemaname = &schema + } + if from.Table_alias() != nil { + alias := from.Table_alias().GetText() + name.Alias = &ast.Alias{Aliasname: &alias} + } + + tables = append(tables, &name) + } + + return tables +} + +func (c *cc) convertUpdate_stmtContext(n *parser.Update_stmtContext) ast.Node { + if n == nil { + return nil + } + + relations := &ast.List{} + tableName := n.Qualified_table_name().GetText() + rel := ast.RangeVar{ + Relname: &tableName, + Location: n.GetStart().GetStart(), + } + relations.Items = append(relations.Items, &rel) + + list := &ast.List{} + for i, col := range n.AllColumn_name() { + colName := col.GetText() + target := &ast.ResTarget{ + Name: &colName, + Val: c.convert(n.Expr(i)), + } + list.Items = append(list.Items, target) + } + + var where ast.Node = nil + if n.WHERE_() != nil { + where = c.convert(n.Expr(len(n.AllExpr()) - 1)) + } + + return &ast.UpdateStmt{ + Relations: relations, + TargetList: list, + WhereClause: where, + ReturningList: &ast.List{}, + FromClause: &ast.List{}, + WithClause: nil, // TODO: support with clause + } +} + +func (c *cc) convert(node node) ast.Node { switch n := node.(type) { case *parser.Alter_table_stmtContext: - return convertAlter_table_stmtContext(n) + return c.convertAlter_table_stmtContext(n) case *parser.Attach_stmtContext: - return convertAttach_stmtContext(n) + return c.convertAttach_stmtContext(n) case *parser.Create_table_stmtContext: - return convertCreate_table_stmtContext(n) + return c.convertCreate_table_stmtContext(n) + + case *parser.Create_view_stmtContext: + return c.convertCreate_view_stmtContext(n) case *parser.Drop_stmtContext: - return convertDrop_stmtContext(n) + return c.convertDrop_stmtContext(n) case *parser.Delete_stmtContext: - return convertDelete_stmtContext(n) + return c.convertDelete_stmtContext(n) case *parser.ExprContext: - return convertExprContext(n) + return c.convertExprContext(n) case *parser.Expr_functionContext: - return convertFuncContext(n) + return c.convertFuncContext(n) case *parser.Expr_qualified_column_nameContext: - return convertColumnNameExpr(n) + return c.convertColumnNameExpr(n) case *parser.Expr_comparisonContext: - return convertComparison(n) + return c.convertComparison(n) case *parser.Expr_bindContext: - return convertParam(n) + return c.convertParam(n) case *parser.Expr_literalContext: - return convertLiteral(n) + return c.convertLiteral(n) case *parser.Expr_binaryContext: - return convertBinaryNode(n) + return c.convertBinaryNode(n) case *parser.Expr_math_opContext: - return convertMathOperationNode(n) + return c.convertMathOperationNode(n) + + case *parser.Expr_in_selectContext: + return c.convertInSelectNode(n) case *parser.Factored_select_stmtContext: // TODO: need to handle this - return &ast.TODO{} + return todo(n) + + case *parser.Insert_stmtContext: + return c.convertInsert_stmtContext(n) + + case *parser.Order_by_stmtContext: + return c.convertOrderby_stmtContext(n) case *parser.Select_stmtContext: - return convertMultiSelect_stmtContext(n) + return c.convertMultiSelect_stmtContext(n) case *parser.Sql_stmtContext: - return convertSql_stmtContext(n) - - case *parser.Simple_select_stmtContext: - return convertSimpleSelect_stmtContext(n) + return c.convertSql_stmtContext(n) - case *parser.Compound_select_stmtContext: - return convertMultiSelect_stmtContext(n) + case *parser.Update_stmtContext: + return c.convertUpdate_stmtContext(n) default: - return &ast.TODO{} + return todo(n) } } diff --git a/internal/engine/sqlite/parse.go b/internal/engine/sqlite/parse.go index b48d194b68..51e1ffb25c 100644 --- a/internal/engine/sqlite/parse.go +++ b/internal/engine/sqlite/parse.go @@ -67,7 +67,8 @@ func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) { loc := 0 for _, stmt := range list.AllSql_stmt() { - out := convert(stmt) + converter := &cc{} + out := converter.convert(stmt) if _, ok := out.(*ast.TODO); ok { continue } diff --git a/internal/sqltest/sqlite.go b/internal/sqltest/sqlite.go new file mode 100644 index 0000000000..6f8dd10a01 --- /dev/null +++ b/internal/sqltest/sqlite.go @@ -0,0 +1,46 @@ +package sqltest + +import ( + "database/sql" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/kyleconroy/sqlc/internal/sql/sqlpath" + + _ "github.com/mattn/go-sqlite3" +) + +func SQLite(t *testing.T, migrations []string) (*sql.DB, func()) { + t.Helper() + + // For each test, pick a new database name at random. + source, err := ioutil.TempFile("", "sqltest_sqlite_") + if err != nil { + t.Fatal(err) + } + t.Logf("open %s\n", source.Name()) + sdb, err := sql.Open("sqlite3", source.Name()) + if err != nil { + t.Fatal(err) + } + + files, err := sqlpath.Glob(migrations) + if err != nil { + t.Fatal(err) + } + for _, f := range files { + blob, err := os.ReadFile(f) + if err != nil { + t.Fatal(err) + } + if _, err := sdb.Exec(string(blob)); err != nil { + t.Fatalf("%s: %s", filepath.Base(f), err) + } + } + + return sdb, func() { + os.Remove(source.Name()) + } +}