internal/helpers.go (173 lines of code) (raw):
// Copyright 2022 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 internal
import (
"fmt"
"strconv"
"strings"
"sync"
"github.com/GoogleCloudPlatform/spanner-migration-tool/schema"
"github.com/GoogleCloudPlatform/spanner-migration-tool/spanner/ddl"
)
type Counter struct {
counterMutex sync.Mutex
ObjectId string
}
var Cntr Counter
// Thread safe Counter to generate ids in session file.
func (c *Counter) GenerateIdSuffix() string {
c.counterMutex.Lock()
counter, _ := strconv.Atoi(c.ObjectId)
counter = counter + 1
c.ObjectId = strconv.Itoa(counter)
returnVal := c.ObjectId
c.counterMutex.Unlock()
return returnVal
}
func GenerateId(idPrefix string) string {
idSuffix := Cntr.GenerateIdSuffix()
id := idPrefix + idSuffix
return id
}
func GenerateTableId() string {
return GenerateId("t")
}
func GenerateColumnId() string {
return GenerateId("c")
}
func GenerateForeignkeyId() string {
return GenerateId("f")
}
func GenerateIndexesId() string {
return GenerateId("i")
}
func GenerateCheckConstrainstId() string {
return GenerateId("cc")
}
func GenerateRuleId() string {
return GenerateId("r")
}
func GenerateSequenceId() string {
return GenerateId("s")
}
func GenerateExpressionId() string {
return GenerateId("e")
}
func GenerateStoredProcedureId() string {
return GenerateId("sp")
}
func GenerateTriggerId() string {
return GenerateId("tr")
}
func GenerateFunctionId() string {
return GenerateId("fn")
}
func GenerateViewId() string {
return GenerateId("vw")
}
func GetSrcColNameIdMap(srcs schema.Table) map[string]string {
if len(srcs.ColNameIdMap) > 0 {
return srcs.ColNameIdMap
}
m := make(map[string]string)
for _, v := range srcs.ColDefs {
m[v.Name] = v.Id
}
return m
}
func GetColIdFromSrcName(srcColDef map[string]schema.Column, columnName string) (string, error) {
for _, v := range srcColDef {
if v.Name == columnName {
return v.Id, nil
}
}
return "", fmt.Errorf("column id not found for source-db column %s", columnName)
}
func GetTableIdFromSrcName(srcSchema map[string]schema.Table, tableName string) (string, error) {
for _, v := range srcSchema {
if v.Name == tableName {
return v.Id, nil
}
}
return "", fmt.Errorf("table id not found for source-db table %s", tableName)
}
func GetTableIdFromSpName(spSchema ddl.Schema, tableName string) (string, error) {
for tableId, table := range spSchema {
if tableName == table.Name {
return tableId, nil
}
}
return "", fmt.Errorf("table id not found for spanner table %s", tableName)
}
func GetColIdFromSpName(colDefs map[string]ddl.ColumnDef, colName string) (string, error) {
for colId, col := range colDefs {
if col.Name == colName {
return colId, nil
}
}
return "", fmt.Errorf("column id not found for spanner column %s", colName)
}
func GetSrcFkFromId(fks []schema.ForeignKey, fkId string) (schema.ForeignKey, error) {
for _, v := range fks {
if v.Id == fkId {
return v, nil
}
}
return schema.ForeignKey{}, fmt.Errorf("foreign key not found")
}
func GetSrcIndexFromId(indexes []schema.Index, indexId string) (schema.Index, error) {
for _, v := range indexes {
if v.Id == indexId {
return v, nil
}
}
return schema.Index{}, fmt.Errorf("index not found")
}
func ComputeUsedNames(conv *Conv) map[string]bool {
usedNames := make(map[string]bool)
for _, table := range conv.SpSchema {
usedNames[strings.ToLower(table.Name)] = true
for _, index := range table.Indexes {
usedNames[strings.ToLower(index.Name)] = true
}
for _, fk := range table.ForeignKeys {
usedNames[strings.ToLower(fk.Name)] = true
}
}
return usedNames
}
func GetSrcTableByName(srcSchema map[string]schema.Table, name string) (*schema.Table, bool) {
for _, v := range srcSchema {
if v.Name == name {
return &v, true
}
}
return nil, false
}
func ResolveForeignKeyIds(schema map[string]schema.Table) {
for key, tbl := range schema {
for idx, fk := range tbl.ForeignKeys {
colIds := []string{}
for _, cn := range fk.ColumnNames {
colIds = append(colIds, tbl.ColNameIdMap[cn])
}
schema[key].ForeignKeys[idx].ColIds = colIds
// ColumnNames is used only to fetch the Ids. The collection is not maintained in the application
schema[key].ForeignKeys[idx].ColumnNames = nil
if refTbl, ok := GetSrcTableByName(schema, fk.ReferTableName); ok {
refColIds := []string{}
for _, cn := range fk.ReferColumnNames {
refColIds = append(refColIds, refTbl.ColNameIdMap[cn])
}
schema[key].ForeignKeys[idx].ReferTableId = refTbl.Id
// ReferTableName is used only to fetch the Id. This field is not maintained
schema[key].ForeignKeys[idx].ReferTableName = ""
schema[key].ForeignKeys[idx].ReferColumnIds = refColIds
// ReferColumnNames is used only to fetch the Id. This collection is not maintained
schema[key].ForeignKeys[idx].ReferColumnNames = nil
}
}
}
}
// Checks if target is present in slice
func Contains[T comparable](slice []T, target T) bool {
for _, item := range slice {
if target == item {
return true
}
}
return false
}