// Copyright 2026 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 casts import ( "context" "github.com/cockroachdb/errors" "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" "github.com/dolthub/dolt/go/libraries/doltcore/merge" "github.com/dolthub/dolt/go/store/hash" "github.com/dolthub/dolt/go/store/prolly" "github.com/dolthub/dolt/go/store/prolly/tree" "github.com/dolthub/doltgresql/core/id" "github.com/dolthub/doltgresql/core/rootobject/objinterface" "github.com/dolthub/doltgresql/flatbuffers/gen/serial" ) // storage is used to read from and write to the root. var storage = objinterface.RootObjectSerializer{ Bytes: (*serial.RootValue).CastsBytes, RootValueAdd: serial.RootValueAddCasts, } // HandleMerge implements the interface objinterface.Collection. func (*Collection) HandleMerge(ctx context.Context, mro merge.MergeRootObject) (doltdb.RootObject, *merge.MergeStats, error) { ourCast := mro.OurRootObj.(Cast) theirCast := mro.TheirRootObj.(Cast) // Ensure that they have the same identifier if ourCast.ID != theirCast.ID { return nil, nil, errors.Newf("attempted to merge different casts: `%s` and `%s`", ourCast.Name().String(), theirCast.Name().String()) } ourHash, err := ourCast.HashOf(ctx) if err != nil { return nil, nil, err } theirHash, err := theirCast.HashOf(ctx) if err != nil { return nil, nil, err } if ourHash.Equal(theirHash) { return mro.OurRootObj, &merge.MergeStats{ Operation: merge.TableUnmodified, Adds: 0, Deletes: 0, Modifications: 0, DataConflicts: 0, SchemaConflicts: 0, ConstraintViolations: 0, }, nil } // TODO: figure out a decent merge strategy return nil, nil, errors.Errorf("unable to merge `%s`", theirCast.Name().String()) } // LoadCollection implements the interface objinterface.Collection. func (*Collection) LoadCollection(ctx context.Context, root objinterface.RootValue) (objinterface.Collection, error) { return LoadCasts(ctx, root) } // LoadCollectionHash implements the interface objinterface.Collection. func (*Collection) LoadCollectionHash(ctx context.Context, root objinterface.RootValue) (hash.Hash, error) { m, ok, err := storage.GetProllyMap(ctx, root) if err != nil || !ok { return hash.Hash{}, err } return m.HashOf(), nil } // LoadCasts loads the casts collection from the given root. func LoadCasts(ctx context.Context, root objinterface.RootValue) (*Collection, error) { m, ok, err := storage.GetProllyMap(ctx, root) if err != nil { return nil, err } if !ok { m, err = prolly.NewEmptyAddressMap(root.NodeStore()) if err != nil { return nil, err } } return NewCollection(ctx, m, root.NodeStore()) } // ResolveNameFromObjects implements the interface objinterface.Collection. func (*Collection) ResolveNameFromObjects(ctx context.Context, name doltdb.TableName, rootObjects []objinterface.RootObject) (doltdb.TableName, id.Id, error) { // There are root objects to search through, so we'll create a temporary store ns := tree.NewTestNodeStore() addressMap, err := prolly.NewEmptyAddressMap(ns) if err != nil { return doltdb.TableName{}, id.Null, err } tempCollection, err := NewCollection(ctx, addressMap, ns) if err != nil { return doltdb.TableName{}, id.Null, err } for _, rootObject := range rootObjects { if c, ok := rootObject.(Cast); ok { if err = tempCollection.AddCast(ctx, c); err != nil { return doltdb.TableName{}, id.Null, err } } } return tempCollection.ResolveName(ctx, name) } // Serializer implements the interface objinterface.Collection. func (*Collection) Serializer() objinterface.RootObjectSerializer { return storage } // UpdateRoot implements the interface objinterface.Collection. func (pgc *Collection) UpdateRoot(ctx context.Context, root objinterface.RootValue) (objinterface.RootValue, error) { m, err := pgc.Map(ctx) if err != nil { return nil, err } return storage.WriteProllyMap(ctx, root, m) }