summaryrefslogtreecommitdiff
path: root/vendor/github.com/uptrace/bun/migrate/sqlschema/database.go
blob: 3741f0c5d576aceed1eae2975ebc9917fd692cfe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package sqlschema

import (
	"slices"
	"strings"

	"github.com/uptrace/bun/schema"
)

type Database interface {
	GetTables() []Table
	GetForeignKeys() map[ForeignKey]string
}

var _ Database = (*BaseDatabase)(nil)

// BaseDatabase is a base database definition.
//
// Dialects and only dialects can use it to implement the Database interface.
// Other packages must use the Database interface.
type BaseDatabase struct {
	Tables      []Table
	ForeignKeys map[ForeignKey]string
}

func (ds BaseDatabase) GetTables() []Table {
	return ds.Tables
}

func (ds BaseDatabase) GetForeignKeys() map[ForeignKey]string {
	return ds.ForeignKeys
}

type ForeignKey struct {
	From ColumnReference
	To   ColumnReference
}

func NewColumnReference(tableName string, columns ...string) ColumnReference {
	return ColumnReference{
		TableName: tableName,
		Column:    NewColumns(columns...),
	}
}

func (fk ForeignKey) DependsOnTable(tableName string) bool {
	return fk.From.TableName == tableName || fk.To.TableName == tableName
}

func (fk ForeignKey) DependsOnColumn(tableName string, column string) bool {
	return fk.DependsOnTable(tableName) &&
		(fk.From.Column.Contains(column) || fk.To.Column.Contains(column))
}

// Columns is a hashable representation of []string used to define schema constraints that depend on multiple columns.
// Although having duplicated column references in these constraints is illegal, Columns neither validates nor enforces this constraint on the caller.
type Columns string

// NewColumns creates a composite column from a slice of column names.
func NewColumns(columns ...string) Columns {
	slices.Sort(columns)
	return Columns(strings.Join(columns, ","))
}

func (c *Columns) String() string {
	return string(*c)
}

func (c *Columns) AppendQuery(fmter schema.Formatter, b []byte) ([]byte, error) {
	return schema.Safe(*c).AppendQuery(fmter, b)
}

// Split returns a slice of column names that make up the composite.
func (c *Columns) Split() []string {
	return strings.Split(c.String(), ",")
}

// ContainsColumns checks that columns in "other" are a subset of current colums.
func (c *Columns) ContainsColumns(other Columns) bool {
	columns := c.Split()
Outer:
	for _, check := range other.Split() {
		for _, column := range columns {
			if check == column {
				continue Outer
			}
		}
		return false
	}
	return true
}

// Contains checks that a composite column contains the current column.
func (c *Columns) Contains(other string) bool {
	return c.ContainsColumns(Columns(other))
}

// Replace renames a column if it is part of the composite.
// If a composite consists of multiple columns, only one column will be renamed.
func (c *Columns) Replace(oldColumn, newColumn string) bool {
	columns := c.Split()
	for i, column := range columns {
		if column == oldColumn {
			columns[i] = newColumn
			*c = NewColumns(columns...)
			return true
		}
	}
	return false
}

// Unique represents a unique constraint defined on 1 or more columns.
type Unique struct {
	Name    string
	Columns Columns
}

// Equals checks that two unique constraint are the same, assuming both are defined for the same table.
func (u Unique) Equals(other Unique) bool {
	return u.Columns == other.Columns
}

type ColumnReference struct {
	TableName string
	Column    Columns
}