schema/schema.go (100 lines of code) (raw):
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package schema provides a generic representation of database
// schemas. Note that our goal is not to faithfully represent all
// aspects of the schema, but just the relevant components for
// conversion to Spanner and reporting on the quality of the
// conversion (this motivates us to keep partial information about
// some features we will report on but not use in the conversion
// e.g. default values, check constraints).
//
// The current version supports PostgreSQL. Expect it to grow as we
// support other databases. We might eventually support the Spanner
// schema, and potentially get rid of the ddl package.
package schema
import (
"fmt"
"strconv"
"strings"
"github.com/GoogleCloudPlatform/spanner-migration-tool/spanner/ddl"
)
// Table represents a database table.
type Table struct {
Name string
Schema string
ColIds []string // List of column Ids (for predictable iteration order e.g. printing).
ColDefs map[string]Column // Details of columns.
ColNameIdMap map[string]string `json:"-"` // Computed every time just after conv is generated or after any column renaming
PrimaryKeys []Key
ForeignKeys []ForeignKey
CheckConstraints []CheckConstraint
Indexes []Index
Id string
}
// Column represents a database column.
// TODO: add support for foreign keys.
type Column struct {
Name string
Type Type
NotNull bool
Ignored Ignored
Id string
AutoGen ddl.AutoGenCol
DefaultValue ddl.DefaultValue
}
// ForeignKey represents a foreign key.
// Note that the fields onDelete and onUpdate describe actions
// for when keys are deleted or updated. Different source databases
// support different actions. For example, mysql supports RESTRICT,
// CASCADE, SET NULL, NO ACTION, and SET DEFAULT
// (see https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html).
type ForeignKey struct {
Name string
ColIds []string
ColumnNames []string `json:"-"`
ReferTableId string
ReferTableName string `json:"-"`
ReferColumnIds []string // len(ReferColumnIds) must be same as len(ColIds)
ReferColumnNames []string `json:"-"`
OnDelete string
OnUpdate string
Id string
}
// CheckConstraints represents a check constraint defined in the schema.
type CheckConstraint struct {
Name string
Expr string
ExprId string
Id string
}
// Key respresents a primary key or index key.
type Key struct {
ColId string
Desc bool // By default, order is ASC. Set to true to specifiy DESC.
Order int
}
// Index represents a database index.
// The only way we represent unique constraints is via indexes. All source database
// unique constraints will be transformed into this representation, including:
// i) A column level constraint (as part of a CREATE TABLE statement)
// ii) A table level constraint (as part of a CREATE TABLE statement)
// iii) An index (as part of a CREATE TABLE statement)
// iv) Added via an ALTER TABLE constraint (changing column constraints, table constraints or index definitions)
// v) Added via a CREATE UNIQUE INDEX statement (which internally maps to an alter table statement).
// We use this single representation of unique constraints to simplify their processing and avoid having
// to handle lots of cases for the same concept. Our choice of an index representation for unique is largely
// motivated by the fact that databases typically implement UNIQUE via an index.
type Index struct {
Name string
Unique bool
Keys []Key
Id string
StoredColumnIds []string
}
// Type represents the type of a column.
type Type struct {
Name string
Mods []int64 // List of modifiers (aka type parameters e.g. varchar(8) or numeric(6, 4).
ArrayBounds []int64 // Empty for scalar types.
}
// Ignored represents column properties/constraints that are not
// represented. We drop the details, but retain presence/absence for
// reporting purposes.
type Ignored struct {
Check bool
Identity bool
Default bool
Exclusion bool
ForeignKey bool
AutoIncrement bool
}
// Print converts ty to a string suitable for printing.
func (ty Type) Print() string {
s := ty.Name
if len(ty.Mods) > 0 {
var l []string
for _, x := range ty.Mods {
l = append(l, strconv.FormatInt(x, 10))
}
s = fmt.Sprintf("%s(%s)", s, strings.Join(l, ","))
}
if len(ty.ArrayBounds) > 0 {
l := []string{s}
for _, x := range ty.ArrayBounds {
if x == -1 {
l = append(l, "[]")
} else {
l = append(l, fmt.Sprintf("[%d]", x))
}
}
s = strings.Join(l, "")
}
return s
}
func MakeType() Type {
return Type{
Name: "",
Mods: []int64{},
ArrayBounds: []int64{},
}
}