<commit_before>package auth

import (
	"context"
	"database/sql"
	"strings"
	"time"

	"github.com/rs/xid"

	"github.com/gilcrest/go-API-template/env"
	"github.com/gilcrest/go-API-template/errors"
)

// CreateClientRequest is used for the client service
type CreateClientRequest struct {
	ClientName        string `json:"client_name"`
	ClientHomeURL     string `json:"homepage_url"`
	ClientDescription string `json:"client_description"`
	RedirectURI       string `json:"redirect_uri"`
	Username          string `json:"username"`
}

// Client is used for the client service and response
type Client struct {
	id            string
	Name          string
	HomeURL       string
	Description   string
	RedirectURI   string
	PrimaryUserID string
	secret        string
	DMLTime       time.Time
}

// grant_types     VARCHAR(80),
// scope           VARCHAR(4000),

// ID is a getter for Client.id
func (c *Client) ID() string {
	return c.id
}

// SetID is a setter for Client.id
func (c *Client) SetID() {
	c.id = xid.New().String()
}

// Secret is a getter for Client.secret
func (c *Client) Secret() string {
	return c.secret
}

// SetSecret is a setter for Client.secret
func (c *Client) SetSecret() {
	c.secret = strings.Join([]string{xid.New().String(), xid.New().String()}, "-")
}

// NewClient is a constructor for the Client struct
func NewClient(ctx context.Context, env *env.Env, c *CreateClientRequest) (*Client, error) {
	const op errors.Op = "auth.CreateClient"

	client := new(Client)

	client.Name = c.ClientName
	client.HomeURL = c.ClientHomeURL
	client.Description = c.ClientDescription
	client.RedirectURI = c.RedirectURI
	client.PrimaryUserID = c.Username

	client.SetID()
	client.SetSecret()

	return client, nil
}

// CreateClientDB creates a client/app in the database
func (c *Client) CreateClientDB(ctx context.Context, tx *sql.Tx) (*sql.Tx, error) {
	const op errors.Op = "auth.CreateClientDB"

	var dmlTime time.Time

	// Prepare the sql statement using bind variables
	stmt, err := tx.PrepareContext(ctx, `select demo.create_client (
		p_client_id => $1,
		p_client_name => $2,
		p_homepage_url => $3,
		p_app_description => $4,
		p_redirect_uri => $5,
		p_client_secret => $6,
		p_user_id => $7)`)

	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		c.id,            //$1
		c.Name,          //$2
		c.HomeURL,       //$3
		c.Description,   //$4
		c.RedirectURI,   //$5
		c.secret,        //$6
		c.PrimaryUserID) //$7

	if err != nil {
		return nil, err
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&dmlTime); err != nil {
			return nil, err
		}
	}

	if err := rows.Err(); err != nil {
		return nil, err
	}

	// set the DMLTime field to the create_date set as part of the insert in
	// the stored function call above
	c.DMLTime = dmlTime

	return tx, nil

}<commit_msg>error handling changes<commit_after>package auth

import (
	"context"
	"database/sql"
	"strings"
	"time"

	"github.com/rs/xid"

	"github.com/gilcrest/go-API-template/env"
	"github.com/gilcrest/go-API-template/errors"
)

// CreateClientRequest is used for the client service
type CreateClientRequest struct {
	ClientName        string `json:"client_name"`
	ClientHomeURL     string `json:"homepage_url"`
	ClientDescription string `json:"client_description"`
	RedirectURI       string `json:"redirect_uri"`
	Username          string `json:"username"`
}

// Client is used for the client service and response
type Client struct {
	id            string
	Name          string
	HomeURL       string
	Description   string
	RedirectURI   string
	PrimaryUserID string
	secret        string
	DMLTime       time.Time
}

// grant_types     VARCHAR(80),
// scope           VARCHAR(4000),

// ID is a getter for Client.id
func (c *Client) ID() string {
	return c.id
}

// SetID is a setter for Client.id
func (c *Client) SetID() {
	c.id = xid.New().String()
}

// Secret is a getter for Client.secret
func (c *Client) Secret() string {
	return c.secret
}

// SetSecret is a setter for Client.secret
func (c *Client) SetSecret() {
	c.secret = strings.Join([]string{xid.New().String(), xid.New().String()}, "-")
}

// NewClient is a constructor for the Client struct
func NewClient(ctx context.Context, env *env.Env, c *CreateClientRequest) (*Client, error) {
	const op errors.Op = "auth.CreateClient"

	client := new(Client)

	client.Name = c.ClientName
	client.HomeURL = c.ClientHomeURL
	client.Description = c.ClientDescription
	client.RedirectURI = c.RedirectURI
	client.PrimaryUserID = c.Username

	client.SetID()
	client.SetSecret()

	return client, nil
}

// CreateClientDB creates a client/app in the database
func (c *Client) CreateClientDB(ctx context.Context, tx *sql.Tx) (*sql.Tx, error) {
	const op errors.Op = "auth.CreateClientDB"

	var dmlTime time.Time

	// Prepare the sql statement using bind variables
	stmt, err := tx.PrepareContext(ctx, `select demo.create_client (
		p_client_id => $1,
		p_client_name => $2,
		p_homepage_url => $3,
		p_app_description => $4,
		p_redirect_uri => $5,
		p_client_secret => $6,
		p_user_id => $7)`)

	if err != nil {
		return nil, errors.E(op, err)
	}
	defer stmt.Close()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		c.id,            //$1
		c.Name,          //$2
		c.HomeURL,       //$3
		c.Description,   //$4
		c.RedirectURI,   //$5
		c.secret,        //$6
		c.PrimaryUserID) //$7

	if err != nil {
		return nil, errors.E(op, err)
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&dmlTime); err != nil {
			return nil, errors.E(op, err)
		}
	}

	if err := rows.Err(); err != nil {
		return nil, errors.E(op, err)
	}

	// set the DMLTime field to the create_date set as part of the insert in
	// the stored function call above
	c.DMLTime = dmlTime

	return tx, nil

}
{'fraction_non_alphanumeric': 0.12378919717616155, 'fraction_numerical': 0.006567066163191594, 'mean_word_length': 3.124576844955992, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7098526', 'n_tokens_mistral': 2145, 'n_tokens_neox': 2057, 'n_words': 608}