tmpl

package
v1.1.27 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 14, 2025 License: MIT Imports: 0 Imported by: 0

Documentation

Index

Constants

View Source
const ConnectionTemplate = `` /* 3765-byte string literal not displayed */

ConnectionTemplate is the template for the connection functions. This is included in the init template.

View Source
const ErrorsTemplate = `` /* 460-byte string literal not displayed */

ErrorsTemplate is the template for the errors. This is included in the init template.

View Source
const InitStatementTemplate = `` /* 496-byte string literal not displayed */

InitStatementTemplate is the template for the init functions.

View Source
const OptionsTemplate = `` /* 4784-byte string literal not displayed */
View Source
const SingleRepeatedTypesTemplate = `` /* 1134-byte string literal not displayed */
View Source
const StorageTemplate = `` /* 4270-byte string literal not displayed */

StorageTemplate is the template for the storage functions. This is included in the init template.

View Source
const StructureTemplate = `
// {{ structureName }} is a struct for the "{{ tableName }}" table.
type {{ structureName }} struct {
{{ range $field := fields }}
	{{ $field | fieldName }} {{ $field | fieldType }}{{if not ($field | isRelation) }}` + " `db:\"{{ $field | sourceName }}\"`" + `{{end}}{{end}}
}

// TableName returns the table name.
func (t *{{ structureName }}) TableName() string {
	return "{{ tableName }}"
}

// ScanRow scans a row into a {{ structureName }}.
func (t *{{ structureName }}) ScanRow(r *sql.Row) error {
	return r.Scan({{ range $field := fields }} {{if not ($field | isRelation) }} &t.{{ $field | fieldName }}, {{ end }}{{ end }})
}

// ScanRows scans a single row into the {{ structureName }}.
func (t *{{ structureName }}) ScanRows(r *sql.Rows) error {
	return r.Scan(
		{{- range $index, $field := fields }}
		{{- if not ($field | isRelation) }}
		&t.{{ $field | fieldName }},
		{{- end}}
		{{- end }}
	)
}
`
View Source
const TableBatchCreateMethodTemplate = `` /* 3622-byte string literal not displayed */
View Source
const TableConditionFilters = `` /* 10354-byte string literal not displayed */
View Source
const TableConditionsTemplate = `` /* 12985-byte string literal not displayed */
View Source
const TableCountMethodTemplate = `` /* 931-byte string literal not displayed */
View Source
const TableCreateMethodTemplate = `` /* 4456-byte string literal not displayed */
View Source
const TableDeleteMethodTemplate = `` /* 1714-byte string literal not displayed */
View Source
const TableFindManyMethodTemplate = `` /* 1886-byte string literal not displayed */
View Source
const TableFindOneMethodTemplate = `` /* 524-byte string literal not displayed */
View Source
const TableFindWithPaginationMethodTemplate = `` /* 1024-byte string literal not displayed */
View Source
const TableGetByIDMethodTemplate = `` /* 633-byte string literal not displayed */
View Source
const TableLockMethodTemplate = `` /* 1105-byte string literal not displayed */
View Source
const TableRawQueryMethodTemplate = `` /* 988-byte string literal not displayed */
View Source
const TableStorageTemplate = `
// {{ storageName | lowerCamelCase }} is a struct for the "{{ tableName }}" table.
type {{ storageName | lowerCamelCase }} struct {
	config *Config
	queryBuilder sq.StatementBuilderType
}

{{ if .CRUDSchemas }}
// {{structureName}}TableManager is an interface for managing the {{ tableName }} table.
type {{structureName}}TableManager interface {
	CreateTable(ctx context.Context) error
	DropTable(ctx context.Context) error
	TruncateTable(ctx context.Context) error
	UpgradeTable(ctx context.Context) error
}
{{ end }}

// {{structureName}}CRUDOperations is an interface for managing the {{ tableName }} table.
type {{structureName}}CRUDOperations interface {
	{{- if (hasID) }}
	Create(ctx context.Context, model *{{structureName}}, opts ...Option) (*{{IDType}}, error)
	{{- else }} 
	Create(ctx context.Context, model *{{structureName}}, opts ...Option) error
	{{- end }}
	{{ if (hasID) }}BatchCreate(ctx context.Context, models []*{{structureName}}, opts ...Option) ([]string, error)
	{{- else }}
	BatchCreate(ctx context.Context, models []*{{structureName}}, opts ...Option) error
	{{- end }}
	Update(ctx context.Context, id {{IDType}}, updateData *{{structureName}}Update) error
	{{- if (hasPrimaryKey) }}
	DeleteBy{{ getPrimaryKey.GetName | camelCase }}(ctx context.Context, {{getPrimaryKey.GetName}} {{IDType}}, opts ...Option) error
	{{- end }}
	{{- if (hasPrimaryKey) }}
	FindBy{{ getPrimaryKey.GetName | camelCase }}(ctx context.Context, id {{IDType}}, opts ...Option) (*{{ structureName }}, error)
	{{- end }}
}

// {{structureName}}SearchOperations is an interface for searching the {{ tableName }} table.
type {{structureName}}SearchOperations interface {
	FindMany(ctx context.Context, builder ...*QueryBuilder) ([]*{{structureName}}, error)
	FindOne(ctx context.Context, builders ...*QueryBuilder) (*{{structureName}}, error)
	Count(ctx context.Context, builders ...*QueryBuilder) (int64, error)
	SelectForUpdate(ctx context.Context, builders ...*QueryBuilder) (*{{structureName}}, error)
}

// {{structureName}}PaginationOperations is an interface for pagination operations.
type {{structureName}}PaginationOperations interface {
	FindManyWithPagination(ctx context.Context, limit int, page int, builders ...*QueryBuilder) ([]*{{structureName}}, *Paginator, error)
}

// {{structureName}}RelationLoading is an interface for loading relations.
type {{structureName}}RelationLoading interface {
	{{- range $index, $field := fields }}
	{{- if and ($field | isRelation) }}
	Load{{ $field | pluralFieldName }} (ctx context.Context, model *{{structureName}}, builders ...*QueryBuilder) error
	{{- end }}
	{{- end }}
	{{- range $index, $field := fields }}
	{{- if and ($field | isRelation) }}
	LoadBatch{{ $field | pluralFieldName }} (ctx context.Context, items []*{{structureName}}, builders ...*QueryBuilder) error
	{{- end }}
	{{- end }}
}

// {{structureName}}AdvancedDeletion is an interface for advanced deletion operations.
type {{structureName}}AdvancedDeletion interface {
	DeleteMany(ctx context.Context, builders ...*QueryBuilder) error
}

// {{structureName}}RawQueryOperations is an interface for executing raw queries.
type {{structureName}}RawQueryOperations interface {
	Query(ctx context.Context, isWrite bool, query string, args ...interface{}) (sql.Result, error)
	QueryRow(ctx context.Context, isWrite bool, query string, args ...interface{}) *sql.Row
	QueryRows(ctx context.Context, isWrite bool, query string, args ...interface{}) (*sql.Rows, error)
}

// {{ storageName }} is a struct for the "{{ tableName }}" table.
type {{ storageName }} interface {
{{ if .CRUDSchemas }}
    {{structureName}}TableManager
{{ end }}
	{{structureName}}CRUDOperations
	{{structureName}}SearchOperations
	{{structureName}}PaginationOperations
	{{structureName}}RelationLoading
	{{structureName}}AdvancedDeletion
	{{structureName}}RawQueryOperations
}

// New{{ storageName }} returns a new {{ storageName | lowerCamelCase }}.
func New{{ storageName }}(config *Config) ({{ storageName }}, error) {
	if config == nil {
		return nil, fmt.Errorf("config is nil")
	}
	if config.DB == nil {
		return nil, fmt.Errorf("config.DB is nil")
	}
	if config.DB.DBRead == nil {
		return nil, fmt.Errorf("config.DB.DBRead is nil")
	}
	if config.DB.DBWrite == nil {
		config.DB.DBWrite = config.DB.DBRead
	}

	return &{{ storageName | lowerCamelCase }}{
		config: config,
		queryBuilder: sq.StatementBuilder.PlaceholderFormat(sq.Dollar),
	}, nil
}

// logQuery logs the query if query logging is enabled.
func (t *{{ storageName | lowerCamelCase }}) logQuery(ctx context.Context, query string, args ...interface{}) {
	if t.config.QueryLogMethod != nil {
		t.config.QueryLogMethod(ctx, t.TableName(), query, args...)
	}
}

// logError logs the error if error logging is enabled.
func (t *{{ storageName | lowerCamelCase }}) logError(ctx context.Context, err error, message string) {
	if t.config.ErrorLogMethod != nil {
		t.config.ErrorLogMethod(ctx, err, message)
	}
}

// TableName returns the table name.
func (t *{{ storageName | lowerCamelCase }}) TableName() string {
	return "{{ tableName }}"
}

// Columns returns the columns for the table.
func (t *{{ storageName | lowerCamelCase }}) Columns() []string {
	return []string{
		{{ range $field := fields }}{{if not ($field | isRelation) }}"{{ $field | sourceName }}",{{ end }}{{ end }}
	}
}

// DB returns the underlying DB. This is useful for doing transactions.
func (t *{{ storageName | lowerCamelCase }}) DB(ctx context.Context, isWrite bool) QueryExecer {
	var db QueryExecer

	// Check if there is an active transaction in the context.
	if tx, ok := TxFromContext(ctx); ok {
		if tx == nil {
			t.logError(ctx, fmt.Errorf("transaction is nil"), "failed to get transaction from context")
			// set default connection
			return t.config.DB.DBWrite
		}

		return tx
	}

	// Use the appropriate connection based on the operation type.
	if isWrite {
		db = t.config.DB.DBWrite
	} else {
		db = t.config.DB.DBRead
	}

	return db
}

{{ if .CRUDSchemas }}
// createTable creates the table.
func (t *{{ storageName | lowerCamelCase }}) CreateTable(ctx context.Context) error {
	sqlQuery := ` + "`" + `
		{{- range $index, $field := fields }}
		{{- if ($field | isDefaultUUID ) }}
		CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
		{{- end}}
		{{- end}}
		-- Table: {{ tableName }}
		CREATE TABLE IF NOT EXISTS {{ tableName }} (
		{{- range $index, $field := fields }}
		{{- if not ($field | isRelation) }}
		{{ $field | sourceName }} {{if ($field | isAutoIncrement) }} SERIAL{{else}}{{ $field | postgresType }}{{end}}{{if $field | isPrimaryKey }} PRIMARY KEY{{end}}{{ if and (isNotNull $field) (not (isAutoIncrement $field)) }} NOT NULL{{ end }}{{if ($field | getDefaultValue) }} DEFAULT {{$field | getDefaultValue}}{{end}}{{if not ( $field | isLastField )}},{{end}}
		{{- end}}
		{{- end}});
		-- Other entities
		{{- if (comment) }}
		COMMENT ON TABLE {{ tableName }} IS '{{ comment }}';
		{{- end}}
		{{- range $index, $field := fields }}
		{{- if ($field | hasUnique) }}
		CREATE UNIQUE INDEX IF NOT EXISTS {{ tableName }}_{{ $field | sourceName }}_unique_idx ON {{ tableName }} USING btree ({{ $field | sourceName }});
		{{- end}}
		{{- end}}

		{{- range $index, $fields := getStructureUniqueIndexes }}
		CREATE UNIQUE INDEX IF NOT EXISTS {{ tableName }}_unique_idx_{{ $fields | sliceToString }} ON {{ tableName }} USING btree (
        {{- $length := sub (len $fields) 1 }}
        {{- range $i, $field := $fields }}
            {{ $field | sourceName }}{{ if lt $i $length }}, {{ end }}
        {{- end }}
    	);
		{{- end }}


		{{- range $index, $field := fields }}
		{{- if ($field | hasIndex) }}
		CREATE INDEX IF NOT EXISTS {{ tableName }}_{{ $field | sourceName }}_idx ON {{ tableName }} USING btree ({{ $field | sourceName }});
		{{- end}}
		{{- end}}
		{{- range $index, $field := fields }}
		{{- if ($field | isRelation) }}
		{{- if ($field | isForeign) }}
		-- Foreign keys for {{ $field | relationTableName }}
		ALTER TABLE {{ tableName }}
		ADD FOREIGN KEY ({{ $field | getFieldSource }}) REFERENCES {{ $field | relationTableName }}({{ $field | getRefSource }})
		{{- if ($field | isCascade) }}
		ON DELETE CASCADE;
		{{- else }}; 
        {{- end}}
		{{- end}}
		{{- end}}
		{{- end }}
	` + "`" + `

	_, err := t.DB(ctx, true).ExecContext(ctx,sqlQuery)
	return err
}

// DropTable drops the table.
func (t *{{ storageName | lowerCamelCase }}) DropTable(ctx context.Context) error {
	sqlQuery := ` + "`" + `
		DROP TABLE IF EXISTS {{ tableName }};
	` + "`" + `

	_, err := t.DB(ctx, true).ExecContext(ctx,sqlQuery)
	return err
}

// TruncateTable truncates the table.
func (t *{{ storageName | lowerCamelCase }}) TruncateTable(ctx context.Context) error {
	sqlQuery := ` + "`" + `
		TRUNCATE TABLE {{ tableName }};
	` + "`" + `

	_, err := t.DB(ctx, true).ExecContext(ctx,sqlQuery)
	return err
}

// UpgradeTable upgrades the table.
// todo: delete this method 
func (t *{{ storageName | lowerCamelCase }}) UpgradeTable(ctx context.Context) error {
	return nil
}
{{ end }}

{{- range $index, $field := fields }}
{{- if and ($field | isRelation) }}
// Load{{ $field | pluralFieldName }} loads the {{ $field | pluralFieldName }} relation.
func (t *{{ storageName | lowerCamelCase }}) Load{{ $field | pluralFieldName }}(ctx context.Context, model *{{structureName}}, builders ...*QueryBuilder) error {
	if model == nil {
		return fmt.Errorf("{{structureName}} is nil")
	}

	// New{{ $field | relationStorageName }} creates a new {{ $field | relationStorageName }}.
	s, err := New{{ $field | relationStorageName }}(t.config)
	if err != nil {
		return fmt.Errorf("failed to create {{ $field | relationStorageName }}: %w", err)
	}

	{{- if ($field | isOptional) }}
		// Check if the optional field is nil
		if model.{{ $field | getFieldID }} == nil {
			// If nil, do not attempt to load the relation
			return nil
		}
		// Add the filter for the relation with dereferenced value
		builders = append(builders, FilterBuilder({{ $field | relationStructureName }}{{ $field | getRefID }}Eq(*model.{{ $field | getFieldID }})))
	{{- else }}
		// Add the filter for the relation without dereferencing
		builders = append(builders, FilterBuilder({{ $field | relationStructureName }}{{ $field | getRefID }}Eq(model.{{ $field | getFieldID }})))
	{{- end }}

	{{- if ($field | isRepeated) }}
		relationModels, err := s.FindMany(ctx, builders...)
		if err != nil {
			return fmt.Errorf("failed to find many {{ $field | relationStorageName }}: %w", err)
		}

		model.{{ $field | fieldName }} = relationModels
	{{- else }}
		relationModel, err := s.FindOne(ctx, builders...)
		if err != nil {
			return fmt.Errorf("failed to find one {{ $field | relationStorageName }}: %w", err)
		}

		model.{{ $field | fieldName }} = relationModel
	{{- end }}
	return nil
}
{{- end }}
{{- end }}

{{- range $index, $field := fields }}
{{- if and ($field | isRelation) }}
// LoadBatch{{ $field | pluralFieldName }} loads the {{ $field | pluralFieldName }} relation.
func (t *{{ storageName | lowerCamelCase }}) LoadBatch{{ $field | pluralFieldName }}(ctx context.Context, items []*{{structureName}}, builders ...*QueryBuilder) error {
	requestItems := make([]interface{}, 0, len(items))
	for _, item := range items {
		{{- if ($field | isOptional) }}
			// Check if the field is nil for optional fields
			if item.{{ $field | getFieldID }} == nil {
				// Skip nil values for optional fields
				continue
			}
			// Append dereferenced value for optional fields
			requestItems = append(requestItems, *item.{{ $field | getFieldID }})
		{{- else }}
			// Append the value directly for non-optional fields
			requestItems = append(requestItems, item.{{ $field | getFieldID }})
		{{- end }}
	}

	// New{{ $field | relationStorageName }} creates a new {{ $field | relationStorageName }}.
	s, err := New{{ $field | relationStorageName }}(t.config)
	if err != nil {
		return fmt.Errorf("failed to create {{ $field | relationStorageName }}: %w", err)
	}

	// Add the filter for the relation
	{{- if ($field | isOptional) }}
		// Ensure that requestItems are not empty before adding the builder
		if len(requestItems) > 0 {
			builders = append(builders, FilterBuilder({{ $field | relationStructureName }}{{ $field | getRefID }}In(requestItems...)))
		}
	{{- else }}
		builders = append(builders, FilterBuilder({{ $field | relationStructureName }}{{ $field | getRefID }}In(requestItems...)))
	{{- end }}

	results, err := s.FindMany(ctx, builders...)
	if err != nil {
		return fmt.Errorf("failed to find many {{ $field | relationStorageName }}: %w", err)
	}

	{{- if ($field | isRepeated) }}
	resultMap := make(map[interface{}][]*{{ $field | relationStructureName }})
	{{- else }}
	resultMap := make(map[interface{}]*{{ $field | relationStructureName }})
	{{- end }}
	for _, result := range results {
		{{- if ($field | isRepeated) }}
		resultMap[result.{{ $field | getRefID }}] = append(resultMap[result.{{ $field | getRefID }}], result)
		{{- else }}
		resultMap[result.{{ $field | getRefID }}] = result
		{{- end }}
	}

	// Assign {{ $field | relationStructureName }} to items
	for _, item := range items {
		{{- if ($field | isOptional) }}
			// Skip assignment if the field is nil
			if item.{{ $field | getFieldID }} == nil {
				continue
			}
			// Assign the relation if it exists in the resultMap
			if v, ok := resultMap[*item.{{ $field | getFieldID }}]; ok {
				item.{{ $field | fieldName }} = v
			}
		{{- else }}
			// Assign the relation directly for non-optional fields
			if v, ok := resultMap[item.{{ $field | getFieldID }}]; ok {
				item.{{ $field | fieldName }} = v
			}
		{{- end }}
	}

	return nil
}
{{- end }}
{{- end }}
`
View Source
const TableTemplate = `` /* 508-byte string literal not displayed */
View Source
const TableUpdateMethodTemplate = `` /* 3689-byte string literal not displayed */
View Source
const TransactionManagerTemplate = `` /* 3522-byte string literal not displayed */
View Source
const TypesTemplate = `
// NullableJSON represents a JSON field that can be null.
type NullableJSON[T any] struct {
	Data T
	Valid bool // Valid is true if the field is not NULL
}

// NewNullableJSON creates a new NullableJSON with a value.
func NewNullableJSON[T any](v T) NullableJSON[T] {
	return NullableJSON[T]{Data: v, Valid: true}
}

// Scan implements the sql.Scanner interface.
func (n *NullableJSON[T]) Scan(value interface{}) error {
	if value == nil {
		n.Valid = false
		return nil
	}

	bytes, ok := value.([]byte)
	if !ok {
		return fmt.Errorf("failed to convert value to []byte")
	}

	if err := json.Unmarshal(bytes, &n.Data); err != nil {
		n.Valid = false
		return fmt.Errorf("failed to unmarshal json: %w", err)
	}

	n.Valid = true
	return nil
}

func (n *NullableJSON[T]) Value() (driver.Value, error) {
	if !n.Valid {
		return nil, nil
	}

	return json.Marshal(n.Data)
}

// ValueOrZero returns the value if valid, otherwise returns the zero value of type T.
func (n NullableJSON[T]) ValueOrZero() T {
	if !n.Valid {
		var zero T // This declares a variable of type T initialized to its zero value
		return zero
	}
	return n.Data
}

{{ range $key, $field := nestedMessages }}
// {{ $key }} is a JSON type nested in another message.
type {{ $field.StructureName }} struct {
	{{- range $nestedField := $field.Descriptor.GetField }}
	{{ $nestedField | fieldName }} {{ $nestedField | fieldType }}` + " `json:\"{{ $nestedField | sourceName }}\"`" + `
	{{- end }}
}

// Scan implements the sql.Scanner interface for JSON.
func (m *{{ $field.StructureName }}) Scan(src interface{}) error  {
	if bytes, ok := src.([]byte); ok {
		return json.Unmarshal(bytes, m)
	}

	return fmt.Errorf(fmt.Sprintf("can't convert %T", src))
}

// Value implements the driver.Valuer interface for JSON.
func (m *{{ $field.StructureName }}) Value() (driver.Value, error) {
	if m == nil {
		m = &{{ $field.StructureName }}{}
	}
	return json.Marshal(m)
}
{{ end }}
`

Variables

This section is empty.

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL