236 lines
5.5 KiB
Go
Executable File
236 lines
5.5 KiB
Go
Executable File
// Copyright 2024 Dolthub, Inc.
|
|
//
|
|
// 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 doltdb
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// TableNameSet is a simple set implementation providing standard set operations for table names.
|
|
type TableNameSet struct {
|
|
items map[TableName]bool
|
|
caseSensitive bool
|
|
}
|
|
|
|
func newTableNameSet(items []TableName, caseSensitive bool) *TableNameSet {
|
|
s := &TableNameSet{
|
|
items: make(map[TableName]bool, len(items)),
|
|
caseSensitive: caseSensitive,
|
|
}
|
|
|
|
for _, item := range items {
|
|
s.items[item] = true
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
func NewTableNameSet(items []TableName) *TableNameSet {
|
|
return newTableNameSet(items, true)
|
|
}
|
|
|
|
func NewCaseInsensitiveTableNameSet(items []TableName) *TableNameSet {
|
|
newItems := make([]TableName, len(items))
|
|
for i, item := range items {
|
|
newItems[i] = item.ToLower()
|
|
}
|
|
return newTableNameSet(newItems, false)
|
|
}
|
|
|
|
// Add adds new items to the set
|
|
func (s *TableNameSet) Add(items ...TableName) {
|
|
for _, item := range items {
|
|
if !s.caseSensitive {
|
|
lowerItem := item.ToLower()
|
|
item = lowerItem
|
|
}
|
|
s.items[item] = true
|
|
}
|
|
}
|
|
|
|
// Remove removes existing items from the set
|
|
func (s *TableNameSet) Remove(items ...TableName) {
|
|
for _, item := range items {
|
|
if !s.caseSensitive {
|
|
item = item.ToLower()
|
|
}
|
|
|
|
delete(s.items, item)
|
|
}
|
|
}
|
|
|
|
// Contains returns true if the item being checked is already in the set.
|
|
func (s *TableNameSet) Contains(item TableName) bool {
|
|
if s == nil {
|
|
return false
|
|
}
|
|
if !s.caseSensitive {
|
|
item = item.ToLower()
|
|
}
|
|
|
|
_, present := s.items[item]
|
|
return present
|
|
}
|
|
|
|
// ContainsAll returns true if all the items being checked are already in the set.
|
|
func (s *TableNameSet) ContainsAll(items []TableName) bool {
|
|
if s == nil {
|
|
return false
|
|
}
|
|
|
|
for _, item := range items {
|
|
if !s.caseSensitive {
|
|
item = item.ToLower()
|
|
}
|
|
if _, present := s.items[item]; !present {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (s *TableNameSet) Equals(other *TableNameSet) bool {
|
|
// two string sets can be equal even if one is sensitive and the other is insensitive as long al the items are a
|
|
// case sensitive match.
|
|
ss := s.AsSlice()
|
|
os := other.AsSlice()
|
|
|
|
if len(ss) != len(os) {
|
|
return false
|
|
}
|
|
|
|
sort.Slice(ss, func(i, j int) bool {
|
|
return ss[i].Less(ss[j])
|
|
})
|
|
sort.Slice(os, func(i, j int) bool {
|
|
return os[i].Less(os[j])
|
|
})
|
|
|
|
for i := range ss {
|
|
if ss[i] != os[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Size returns the number of unique TableNames in the set
|
|
func (s *TableNameSet) Size() int {
|
|
if s == nil {
|
|
return 0
|
|
}
|
|
return len(s.items)
|
|
}
|
|
|
|
// AsSlice converts the set to a slice of strings. If this is an insensitive set the resulting slice will be lowercase
|
|
// regardless of the case that was used when adding the string to the set.
|
|
func (s *TableNameSet) AsSlice() []TableName {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
size := len(s.items)
|
|
sl := make([]TableName, size)
|
|
|
|
i := 0
|
|
for k := range s.items {
|
|
sl[i] = k
|
|
i++
|
|
}
|
|
|
|
return sl
|
|
}
|
|
|
|
// AsStringSlice converts the set to a slice of strings. If this is an insensitive set the resulting slice will be lowercase
|
|
// regardless of the case that was used when adding the string to the set.
|
|
func (s *TableNameSet) AsStringSlice() []string {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
size := len(s.items)
|
|
sl := make([]string, size)
|
|
|
|
i := 0
|
|
for k := range s.items {
|
|
sl[i] = k.String()
|
|
i++
|
|
}
|
|
|
|
return sl
|
|
}
|
|
|
|
// AsSortedSlice converts the set to a slice of strings. If this is an insensitive set the resulting slice will be lowercase
|
|
// regardless of the case that was used when adding the string to the set. The slice is sorted in ascending order.
|
|
func (s *TableNameSet) AsSortedSlice() []TableName {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
slice := s.AsSlice()
|
|
sort.Slice(slice, func(i, j int) bool {
|
|
return slice[i].Less(slice[j])
|
|
})
|
|
return slice
|
|
}
|
|
|
|
// Iterate accepts a callback which will be called once for each TableName in the set until all items have been
|
|
// exhausted or callback returns false.
|
|
func (s *TableNameSet) Iterate(callBack func(TableName) (cont bool)) {
|
|
if s == nil {
|
|
return
|
|
}
|
|
for k := range s.items {
|
|
if !callBack(k) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// LeftIntersectionRight takes a slice of strings and returns a slice of strings containing the intersection with the
|
|
// set, and a slice of strings for the ones missing from the set.
|
|
func (s *TableNameSet) LeftIntersectionRight(other *TableNameSet) (left *TableNameSet, intersection *TableNameSet, right *TableNameSet) {
|
|
left = NewTableNameSet(nil)
|
|
intersection = NewTableNameSet(nil)
|
|
right = NewTableNameSet(nil)
|
|
|
|
for os := range other.items {
|
|
if s.Contains(os) {
|
|
intersection.Add(os)
|
|
} else {
|
|
right.Add(os)
|
|
}
|
|
}
|
|
for ss := range s.items {
|
|
if !intersection.Contains(ss) {
|
|
left.Add(ss)
|
|
}
|
|
}
|
|
|
|
return left, intersection, right
|
|
}
|
|
|
|
// JoinStrings returns the sorted values from the set concatenated with a given sep
|
|
func (s *TableNameSet) JoinStrings(sep string) string {
|
|
slice := s.AsSlice()
|
|
sort.Slice(slice, func(i, j int) bool {
|
|
return slice[i].Less(slice[j])
|
|
})
|
|
ss := make([]string, len(slice))
|
|
for i, v := range slice {
|
|
ss[i] = v.String()
|
|
}
|
|
return strings.Join(ss, sep)
|
|
}
|