Files
dolthub--doltgresql/core/sequences/root_object.go
T
2026-07-13 12:32:25 +08:00

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")
}