first commit
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"git.aiterp.net/rpdata2/rpdata2-take2/ports/mysql/mysqlgen"
|
||||
"git.aiterp.net/rpdata2/rpdata2-take2/tag"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
db *sql.DB
|
||||
q *mysqlgen.Queries
|
||||
}
|
||||
|
||||
func (db *Database) Tags() tag.Repository {
|
||||
return &tagRepository{
|
||||
db: db.db,
|
||||
q: db.q,
|
||||
}
|
||||
}
|
||||
|
||||
func Connect(host string, port int, username, password, database string) (*Database, error) {
|
||||
db, err := sql.Open("mysql", fmt.Sprintf(
|
||||
"%s:%s@(%s:%d)/%s?parseTime=true", username, password, host, port, database,
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db.SetMaxOpenConns(10)
|
||||
db.SetMaxIdleConns(10)
|
||||
db.SetConnMaxIdleTime(time.Minute)
|
||||
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
q, err := mysqlgen.Prepare(context.Background(), db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Database{db: db, q: q}, nil
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
CREATE TABLE tag
|
||||
(
|
||||
`id` CHAR(8) NOT NULL PRIMARY KEY,
|
||||
`parent_id` CHAR(8) NULL,
|
||||
`owner_id` VARCHAR(255) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`kind` INT NOT NULL,
|
||||
`description` TEXT NOT NULL,
|
||||
`listed` BOOL NOT NULL,
|
||||
`secret` BOOL NOT NULL
|
||||
);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
DROP TABLE tag;
|
||||
-- +goose StatementEnd
|
||||
@@ -0,0 +1,128 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.13.0
|
||||
|
||||
package mysqlgen
|
||||
|
||||
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.deleteTagStmt, err = db.PrepareContext(ctx, deleteTag); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query DeleteTag: %w", err)
|
||||
}
|
||||
if q.findTagStmt, err = db.PrepareContext(ctx, findTag); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query FindTag: %w", err)
|
||||
}
|
||||
if q.listListedTagsStmt, err = db.PrepareContext(ctx, listListedTags); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query ListListedTags: %w", err)
|
||||
}
|
||||
if q.listTagsStmt, err = db.PrepareContext(ctx, listTags); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query ListTags: %w", err)
|
||||
}
|
||||
if q.replaceTagStmt, err = db.PrepareContext(ctx, replaceTag); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query ReplaceTag: %w", err)
|
||||
}
|
||||
return &q, nil
|
||||
}
|
||||
|
||||
func (q *Queries) Close() error {
|
||||
var err error
|
||||
if q.deleteTagStmt != nil {
|
||||
if cerr := q.deleteTagStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing deleteTagStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
if q.findTagStmt != nil {
|
||||
if cerr := q.findTagStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing findTagStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
if q.listListedTagsStmt != nil {
|
||||
if cerr := q.listListedTagsStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing listListedTagsStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
if q.listTagsStmt != nil {
|
||||
if cerr := q.listTagsStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing listTagsStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
if q.replaceTagStmt != nil {
|
||||
if cerr := q.replaceTagStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing replaceTagStmt: %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
|
||||
deleteTagStmt *sql.Stmt
|
||||
findTagStmt *sql.Stmt
|
||||
listListedTagsStmt *sql.Stmt
|
||||
listTagsStmt *sql.Stmt
|
||||
replaceTagStmt *sql.Stmt
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||
return &Queries{
|
||||
db: tx,
|
||||
tx: tx,
|
||||
deleteTagStmt: q.deleteTagStmt,
|
||||
findTagStmt: q.findTagStmt,
|
||||
listListedTagsStmt: q.listListedTagsStmt,
|
||||
listTagsStmt: q.listTagsStmt,
|
||||
replaceTagStmt: q.replaceTagStmt,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.13.0
|
||||
|
||||
package mysqlgen
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
type Tag struct {
|
||||
ID string
|
||||
ParentID sql.NullString
|
||||
OwnerID string
|
||||
Name string
|
||||
Kind int
|
||||
Description string
|
||||
Listed bool
|
||||
Secret bool
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.13.0
|
||||
// source: tag.sql
|
||||
|
||||
package mysqlgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
const deleteTag = `-- name: DeleteTag :exec
|
||||
DELETE FROM tag WHERE id = ?
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteTag(ctx context.Context, id string) error {
|
||||
_, err := q.exec(ctx, q.deleteTagStmt, deleteTag, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const findTag = `-- name: FindTag :one
|
||||
SELECT id, parent_id, owner_id, name, kind, description, listed, secret
|
||||
FROM tag
|
||||
WHERE id = ?
|
||||
`
|
||||
|
||||
func (q *Queries) FindTag(ctx context.Context, id string) (Tag, error) {
|
||||
row := q.queryRow(ctx, q.findTagStmt, findTag, id)
|
||||
var i Tag
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ParentID,
|
||||
&i.OwnerID,
|
||||
&i.Name,
|
||||
&i.Kind,
|
||||
&i.Description,
|
||||
&i.Listed,
|
||||
&i.Secret,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const listListedTags = `-- name: ListListedTags :many
|
||||
SELECT id, parent_id, owner_id, name, kind, description, listed, secret
|
||||
FROM tag
|
||||
WHERE listed = 1
|
||||
`
|
||||
|
||||
func (q *Queries) ListListedTags(ctx context.Context) ([]Tag, error) {
|
||||
rows, err := q.query(ctx, q.listListedTagsStmt, listListedTags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []Tag{}
|
||||
for rows.Next() {
|
||||
var i Tag
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ParentID,
|
||||
&i.OwnerID,
|
||||
&i.Name,
|
||||
&i.Kind,
|
||||
&i.Description,
|
||||
&i.Listed,
|
||||
&i.Secret,
|
||||
); 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 listTags = `-- name: ListTags :many
|
||||
SELECT id, parent_id, owner_id, name, kind, description, listed, secret
|
||||
FROM tag
|
||||
`
|
||||
|
||||
func (q *Queries) ListTags(ctx context.Context) ([]Tag, error) {
|
||||
rows, err := q.query(ctx, q.listTagsStmt, listTags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []Tag{}
|
||||
for rows.Next() {
|
||||
var i Tag
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ParentID,
|
||||
&i.OwnerID,
|
||||
&i.Name,
|
||||
&i.Kind,
|
||||
&i.Description,
|
||||
&i.Listed,
|
||||
&i.Secret,
|
||||
); 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 replaceTag = `-- name: ReplaceTag :exec
|
||||
REPLACE INTO tag (id, parent_id, owner_id, name, kind, description, listed, secret)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`
|
||||
|
||||
type ReplaceTagParams struct {
|
||||
ID string
|
||||
ParentID sql.NullString
|
||||
OwnerID string
|
||||
Name string
|
||||
Kind int
|
||||
Description string
|
||||
Listed bool
|
||||
Secret bool
|
||||
}
|
||||
|
||||
func (q *Queries) ReplaceTag(ctx context.Context, arg ReplaceTagParams) error {
|
||||
_, err := q.exec(ctx, q.replaceTagStmt, replaceTag,
|
||||
arg.ID,
|
||||
arg.ParentID,
|
||||
arg.OwnerID,
|
||||
arg.Name,
|
||||
arg.Kind,
|
||||
arg.Description,
|
||||
arg.Listed,
|
||||
arg.Secret,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"git.aiterp.net/rpdata2-take2/rpdata2/internal/genutils"
|
||||
)
|
||||
|
||||
func toNullString(s *string) sql.NullString {
|
||||
if s != nil {
|
||||
return sql.NullString{Valid: true, String: *s}
|
||||
} else {
|
||||
return sql.NullString{Valid: false}
|
||||
}
|
||||
}
|
||||
|
||||
func fromNullString(ns sql.NullString) *string {
|
||||
if ns.Valid {
|
||||
return genutils.Ptr(ns.String)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
-- name: FindTag :one
|
||||
SELECT *
|
||||
FROM tag
|
||||
WHERE id = ?;
|
||||
|
||||
-- name: ListTags :many
|
||||
SELECT *
|
||||
FROM tag;
|
||||
|
||||
-- name: ListListedTags :many
|
||||
SELECT *
|
||||
FROM tag
|
||||
WHERE listed = 1;
|
||||
|
||||
-- name: ReplaceTag :exec
|
||||
REPLACE INTO tag (id, parent_id, owner_id, name, kind, description, listed, secret)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
||||
|
||||
-- name: DeleteTag :exec
|
||||
DELETE FROM tag WHERE id = ?;
|
||||
@@ -0,0 +1,20 @@
|
||||
version: "1"
|
||||
packages:
|
||||
- name: "mysqlgen"
|
||||
path: "./mysqlgen"
|
||||
queries: "./queries"
|
||||
schema: "./migrations"
|
||||
engine: "mysql"
|
||||
emit_prepared_queries: true
|
||||
emit_interface: false
|
||||
emit_exact_table_names: false
|
||||
emit_empty_slices: true
|
||||
emit_json_tags: false
|
||||
overrides:
|
||||
- go_type: "float64"
|
||||
db_type: "float"
|
||||
- go_type: "float64"
|
||||
db_type: "float"
|
||||
nullable: true
|
||||
- go_type: "int"
|
||||
db_type: "int"
|
||||
@@ -0,0 +1,125 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"git.aiterp.net/rpdata2-take2/rpdata2"
|
||||
"git.aiterp.net/rpdata2-take2/rpdata2/ports/mysql/mysqlgen"
|
||||
"git.aiterp.net/rpdata2-take2/rpdata2/tag"
|
||||
"github.com/Masterminds/squirrel"
|
||||
)
|
||||
|
||||
type tagRepository struct {
|
||||
db *sql.DB
|
||||
q *mysqlgen.Queries
|
||||
}
|
||||
|
||||
func (r *tagRepository) FindOne(ctx context.Context, id string) (*tag.Tag, error) {
|
||||
row, err := r.q.FindTag(ctx, id)
|
||||
if err != sql.ErrNoRows {
|
||||
return nil, rpdata2.NotFound("Tag")
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tag.Tag{
|
||||
ID: row.ID,
|
||||
ParentID: fromNullString(row.ParentID),
|
||||
OwnerID: row.OwnerID,
|
||||
Name: row.Name,
|
||||
Kind: tag.Kind(row.Kind),
|
||||
Description: row.Description,
|
||||
Listed: row.Listed,
|
||||
Secret: row.Secret,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *tagRepository) FindRecursive(ctx context.Context, id string) ([]tag.Tag, error) {
|
||||
return r.findRecursive(ctx, make([]tag.Tag, 0, 32), []string{id})
|
||||
}
|
||||
|
||||
func (r *tagRepository) findRecursive(ctx context.Context, tags []tag.Tag, parentIDs []string) ([]tag.Tag, error) {
|
||||
query, args, err := squirrel.Select("id,parent_id,owner_id,name,kind,description,listed,secret").
|
||||
From("tag").
|
||||
Where(squirrel.Eq{"parent_id": parentIDs}).
|
||||
ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := r.db.QueryContext(ctx, query, args...)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
nextParentIDs := make([]string, 0, 8)
|
||||
for rows.Next() {
|
||||
var t tag.Tag
|
||||
var ns sql.NullString
|
||||
|
||||
err = rows.Scan(&t.ID, &ns, &t.OwnerID, &t.Name, &t.Kind, &t.Description, &t.Listed, &t.Secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.ParentID = fromNullString(ns)
|
||||
nextParentIDs = append(nextParentIDs, t.ID)
|
||||
|
||||
tags = append(tags, t)
|
||||
}
|
||||
|
||||
if len(nextParentIDs) > 0 {
|
||||
return r.findRecursive(ctx, tags, nextParentIDs)
|
||||
} else {
|
||||
return tags, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (r *tagRepository) List(ctx context.Context, full bool) ([]tag.Tag, error) {
|
||||
var rows []mysqlgen.Tag
|
||||
var err error
|
||||
if full {
|
||||
rows, err = r.q.ListTags(ctx)
|
||||
} else {
|
||||
rows, err = r.q.ListListedTags(ctx)
|
||||
}
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return []tag.Tag{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]tag.Tag, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
res = append(res, tag.Tag{
|
||||
ID: row.ID,
|
||||
ParentID: fromNullString(row.ParentID),
|
||||
OwnerID: row.OwnerID,
|
||||
Name: row.Name,
|
||||
Kind: tag.Kind(row.Kind),
|
||||
Description: row.Description,
|
||||
Listed: row.Listed,
|
||||
Secret: row.Secret,
|
||||
})
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (r *tagRepository) Save(ctx context.Context, tag tag.Tag) error {
|
||||
return r.q.ReplaceTag(ctx, mysqlgen.ReplaceTagParams{
|
||||
ID: tag.ID,
|
||||
ParentID: toNullString(tag.ParentID),
|
||||
OwnerID: tag.OwnerID,
|
||||
Name: tag.Name,
|
||||
Kind: int(tag.Kind),
|
||||
Description: tag.Description,
|
||||
Listed: tag.Listed,
|
||||
Secret: tag.Secret,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *tagRepository) Delete(ctx context.Context, tag tag.Tag) error {
|
||||
return r.q.DeleteTag(ctx, tag.ID)
|
||||
}
|
||||
Reference in New Issue
Block a user