first commit

This commit is contained in:
2023-06-27 09:48:33 +02:00
commit 8fc0220e51
29 changed files with 1315 additions and 0 deletions
+47
View File
@@ -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
+128
View File
@@ -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,
}
}
+20
View File
@@ -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
}
+147
View File
@@ -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
}
+22
View File
@@ -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
}
}
+20
View File
@@ -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 = ?;
+20
View File
@@ -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"
+125
View File
@@ -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)
}