363 lines
12 KiB
Go
363 lines
12 KiB
Go
// Copyright 2025 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 sequences
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/cockroachdb/errors"
|
|
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
|
|
|
|
"github.com/dolthub/doltgresql/core/id"
|
|
pgmerge "github.com/dolthub/doltgresql/core/merge"
|
|
"github.com/dolthub/doltgresql/core/rootobject/objinterface"
|
|
pgtypes "github.com/dolthub/doltgresql/server/types"
|
|
)
|
|
|
|
const (
|
|
FIELD_NAME_DATA_TYPE = "data_type"
|
|
FIELD_NAME_PERSISTENCE = "persistence"
|
|
FIELD_NAME_START = "start"
|
|
FIELD_NAME_CURRENT = "current"
|
|
FIELD_NAME_INCREMENT = "increment"
|
|
FIELD_NAME_MINIMUM = "minimum"
|
|
FIELD_NAME_MAXIMUM = "maximum"
|
|
FIELD_NAME_CACHE = "cache"
|
|
FIELD_NAME_CYCLE = "cycle"
|
|
FIELD_NAME_IS_AT_END = "is_at_end"
|
|
FIELD_NAME_HAS_BEEN_CALLED = "has_been_called"
|
|
FIELD_NAME_OWNER_TABLE = "owner_table"
|
|
FIELD_NAME_OWNER_COLUMN = "owner_column"
|
|
)
|
|
|
|
// DeserializeRootObject implements the interface objinterface.Collection.
|
|
func (pgs *Collection) DeserializeRootObject(ctx context.Context, data []byte) (objinterface.RootObject, error) {
|
|
return DeserializeSequence(ctx, data)
|
|
}
|
|
|
|
// DiffRootObjects implements the interface objinterface.Collection.
|
|
func (pgs *Collection) DiffRootObjects(ctx context.Context, fromHash string, o objinterface.RootObject, t objinterface.RootObject, a objinterface.RootObject) ([]objinterface.RootObjectDiff, objinterface.RootObject, error) {
|
|
ours := o.(*Sequence)
|
|
{
|
|
copiedOurs := *ours
|
|
ours = &copiedOurs
|
|
}
|
|
theirs := t.(*Sequence)
|
|
var ancestor Sequence
|
|
hasAncestor := false
|
|
if ancestorPtr, ok := a.(*Sequence); ok {
|
|
ancestor = *ancestorPtr
|
|
hasAncestor = true
|
|
}
|
|
var diffs []objinterface.RootObjectDiff
|
|
if ours.DataTypeID != theirs.DataTypeID {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Text,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_DATA_TYPE,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.DataTypeID.TypeName(), theirs.DataTypeID.TypeName(), ancestor.DataTypeID.TypeName(), hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.DataTypeID = id.NewType(ours.DataTypeID.SchemaName(), diff.OurValue.(string))
|
|
}
|
|
}
|
|
if ours.Persistence != theirs.Persistence {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Int32,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_PERSISTENCE,
|
|
}
|
|
if pgmerge.DiffValues(&diff, int32(ours.Persistence), int32(theirs.Persistence), int32(ancestor.Persistence), hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.Persistence = Persistence(diff.OurValue.(int32))
|
|
}
|
|
}
|
|
if ours.Start != theirs.Start {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Int64,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_START,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.Start, theirs.Start, ancestor.Start, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.Start = diff.OurValue.(int64)
|
|
}
|
|
}
|
|
if ours.Current != theirs.Current {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Int64,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_CURRENT,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.Current, theirs.Current, ancestor.Current, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.Current = diff.OurValue.(int64)
|
|
}
|
|
}
|
|
if ours.HasBeenCalled != theirs.HasBeenCalled {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Bool,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_HAS_BEEN_CALLED,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.HasBeenCalled, theirs.HasBeenCalled, ancestor.HasBeenCalled, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.HasBeenCalled = diff.OurValue.(bool)
|
|
}
|
|
}
|
|
if ours.Increment != theirs.Increment {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Int64,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_INCREMENT,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.Increment, theirs.Increment, ancestor.Increment, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.Increment = diff.OurValue.(int64)
|
|
}
|
|
}
|
|
if ours.Minimum != theirs.Minimum {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Int64,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_MINIMUM,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.Minimum, theirs.Minimum, ancestor.Minimum, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.Minimum = diff.OurValue.(int64)
|
|
}
|
|
}
|
|
if ours.Maximum != theirs.Maximum {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Int64,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_MAXIMUM,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.Maximum, theirs.Maximum, ancestor.Maximum, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.Maximum = diff.OurValue.(int64)
|
|
}
|
|
}
|
|
if ours.Cache != theirs.Cache {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Int64,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_CACHE,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.Cache, theirs.Cache, ancestor.Cache, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.Cache = diff.OurValue.(int64)
|
|
}
|
|
}
|
|
if ours.Cycle != theirs.Cycle {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Bool,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_CYCLE,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.Cycle, theirs.Cycle, ancestor.Cycle, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.Cycle = diff.OurValue.(bool)
|
|
}
|
|
}
|
|
if ours.IsAtEnd != theirs.IsAtEnd {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Bool,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_IS_AT_END,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.IsAtEnd, theirs.IsAtEnd, ancestor.IsAtEnd, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.IsAtEnd = diff.OurValue.(bool)
|
|
}
|
|
}
|
|
if ours.OwnerTable != theirs.OwnerTable {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Text,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_OWNER_TABLE,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.OwnerTable.TableName(), theirs.OwnerTable.TableName(), ancestor.OwnerTable.TableName(), hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.OwnerTable = id.NewTable(ours.OwnerTable.SchemaName(), diff.OurValue.(string))
|
|
}
|
|
}
|
|
if ours.OwnerColumn != theirs.OwnerColumn {
|
|
diff := objinterface.RootObjectDiff{
|
|
Type: pgtypes.Text,
|
|
FromHash: fromHash,
|
|
FieldName: FIELD_NAME_OWNER_COLUMN,
|
|
}
|
|
if pgmerge.DiffValues(&diff, ours.OwnerColumn, theirs.OwnerColumn, ancestor.OwnerColumn, hasAncestor) {
|
|
diffs = append(diffs, diff)
|
|
} else {
|
|
ours.OwnerColumn = diff.OurValue.(string)
|
|
}
|
|
}
|
|
return diffs, ours, nil
|
|
}
|
|
|
|
// DropRootObject implements the interface objinterface.Collection.
|
|
func (pgs *Collection) DropRootObject(ctx context.Context, identifier id.Id) error {
|
|
if identifier.Section() != id.Section_Sequence {
|
|
return errors.Errorf(`sequence %s does not exist`, identifier.String())
|
|
}
|
|
return pgs.DropSequence(ctx, id.Sequence(identifier))
|
|
}
|
|
|
|
// GetFieldType implements the interface objinterface.Collection.
|
|
func (pgs *Collection) GetFieldType(ctx context.Context, fieldName string) *pgtypes.DoltgresType {
|
|
switch fieldName {
|
|
case FIELD_NAME_DATA_TYPE:
|
|
return pgtypes.Text
|
|
case FIELD_NAME_PERSISTENCE:
|
|
return pgtypes.Int32
|
|
case FIELD_NAME_START:
|
|
return pgtypes.Int64
|
|
case FIELD_NAME_CURRENT:
|
|
return pgtypes.Int64
|
|
case FIELD_NAME_INCREMENT:
|
|
return pgtypes.Int64
|
|
case FIELD_NAME_MINIMUM:
|
|
return pgtypes.Int64
|
|
case FIELD_NAME_MAXIMUM:
|
|
return pgtypes.Int64
|
|
case FIELD_NAME_CACHE:
|
|
return pgtypes.Int64
|
|
case FIELD_NAME_CYCLE:
|
|
return pgtypes.Bool
|
|
case FIELD_NAME_IS_AT_END:
|
|
return pgtypes.Bool
|
|
case FIELD_NAME_HAS_BEEN_CALLED:
|
|
return pgtypes.Bool
|
|
case FIELD_NAME_OWNER_TABLE:
|
|
return pgtypes.Text
|
|
case FIELD_NAME_OWNER_COLUMN:
|
|
return pgtypes.Text
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// GetID implements the interface objinterface.Collection.
|
|
func (pgs *Collection) GetID() objinterface.RootObjectID {
|
|
return objinterface.RootObjectID_Sequences
|
|
}
|
|
|
|
// GetRootObject implements the interface objinterface.Collection.
|
|
func (pgs *Collection) GetRootObject(ctx context.Context, identifier id.Id) (objinterface.RootObject, bool, error) {
|
|
if identifier.Section() != id.Section_Sequence {
|
|
return nil, false, nil
|
|
}
|
|
seq, err := pgs.GetSequence(ctx, id.Sequence(identifier))
|
|
return seq, err == nil && seq != nil, err
|
|
}
|
|
|
|
// HasRootObject implements the interface objinterface.Collection.
|
|
func (pgs *Collection) HasRootObject(ctx context.Context, identifier id.Id) (bool, error) {
|
|
if identifier.Section() != id.Section_Sequence {
|
|
return false, nil
|
|
}
|
|
return pgs.HasSequence(ctx, id.Sequence(identifier)), nil
|
|
}
|
|
|
|
// IDToTableName implements the interface objinterface.Collection.
|
|
func (pgs *Collection) IDToTableName(identifier id.Id) doltdb.TableName {
|
|
if identifier.Section() != id.Section_Sequence {
|
|
return doltdb.TableName{}
|
|
}
|
|
seqID := id.Sequence(identifier)
|
|
return doltdb.TableName{
|
|
Name: seqID.SequenceName(),
|
|
Schema: seqID.SchemaName(),
|
|
}
|
|
}
|
|
|
|
// IterAll implements the interface objinterface.Collection.
|
|
func (pgs *Collection) IterAll(ctx context.Context, callback func(rootObj objinterface.RootObject) (stop bool, err error)) error {
|
|
return pgs.IterateSequences(ctx, func(seq *Sequence) (stop bool, err error) {
|
|
return callback(seq)
|
|
})
|
|
}
|
|
|
|
// IterIDs implements the interface objinterface.Collection.
|
|
func (pgs *Collection) IterIDs(ctx context.Context, callback func(identifier id.Id) (stop bool, err error)) error {
|
|
return pgs.iterateIDs(ctx, func(seqID id.Sequence) (stop bool, err error) {
|
|
return callback(seqID.AsId())
|
|
})
|
|
}
|
|
|
|
// PutRootObject implements the interface objinterface.Collection.
|
|
func (pgs *Collection) PutRootObject(ctx context.Context, rootObj objinterface.RootObject) error {
|
|
seq, ok := rootObj.(*Sequence)
|
|
if !ok {
|
|
return errors.Newf("invalid sequence root object: %T", rootObj)
|
|
}
|
|
return pgs.CreateSequence(ctx, seq)
|
|
}
|
|
|
|
// RenameRootObject implements the interface objinterface.Collection.
|
|
func (pgs *Collection) RenameRootObject(ctx context.Context, oldName id.Id, newName id.Id) error {
|
|
if !oldName.IsValid() || !newName.IsValid() || oldName.Section() != newName.Section() || oldName.Section() != id.Section_Sequence {
|
|
return errors.New("cannot rename sequence due to invalid name")
|
|
}
|
|
oldSeqName := id.Sequence(oldName)
|
|
newSeqName := id.Sequence(newName)
|
|
seq, err := pgs.GetSequence(ctx, oldSeqName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = pgs.DropSequence(ctx, oldSeqName); err != nil {
|
|
return err
|
|
}
|
|
newSeq := *seq
|
|
newSeq.Id = newSeqName
|
|
return pgs.CreateSequence(ctx, &newSeq)
|
|
}
|
|
|
|
// ResolveName implements the interface objinterface.Collection.
|
|
func (pgs *Collection) ResolveName(ctx context.Context, name doltdb.TableName) (doltdb.TableName, id.Id, error) {
|
|
rawID, err := pgs.resolveName(ctx, name.Schema, name.Name)
|
|
if err != nil || !rawID.IsValid() {
|
|
return doltdb.TableName{}, id.Null, err
|
|
}
|
|
return doltdb.TableName{
|
|
Name: rawID.SequenceName(),
|
|
Schema: rawID.SchemaName(),
|
|
}, rawID.AsId(), nil
|
|
}
|
|
|
|
// TableNameToID implements the interface objinterface.Collection.
|
|
func (pgs *Collection) TableNameToID(name doltdb.TableName) id.Id {
|
|
return id.NewSequence(name.Schema, name.Name).AsId()
|
|
}
|
|
|
|
// UpdateField implements the interface objinterface.Collection.
|
|
func (pgs *Collection) UpdateField(ctx context.Context, rootObject objinterface.RootObject, fieldName string, newValue any) (objinterface.RootObject, error) {
|
|
return nil, errors.New("updating through the conflicts table for this object type is not yet supported")
|
|
}
|