merge

package
v0.0.0-...-4dcfcdd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 2, 2024 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package merge provides support for three-way merge operations.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConflictError

func ConflictError(con *Conflict) error

ConflictError returns an error that provides details about a Conflict which could not be merged.

func ValidateNoUnmappedColumns

func ValidateNoUnmappedColumns(bag *Bag) error

ValidateNoUnmappedColumns returns an error message if the bag contains any unmapped properties.

func ValidatePK

func ValidatePK(bag *Bag) error

ValidatePK ensures that the Bag has non-nil values for each primary key defined in its schema. This function will also return an error if the Bag has no schema.

This function assumes that the primary key columns will be sorted first in the Bag's column data.

Types

type Bag

type Bag struct {
	*BagSpec // Common metadata about property structure.

	// Mapped contains an Entry for each known column. This makes it
	// simple to identify whether any given API call to a Bag should act
	// on a mapped or an unmapped property.  If it is a mapped property,
	// there will already be an entry in this map.
	//
	// The Entry type has a Valid flag which allows callers to
	// distinguish unset properties from ones that are explicitly set to
	// nil. The methods on Bag will automatically filter out mapped,
	// invalid properties.
	Mapped   *ident.Map[*Entry]
	Meta     map[string]any  // External metadata, derived from from decoded Mutation.
	Unmapped *ident.Map[any] // Properties not present in Columns.
}

A Bag is a loosely-typed map of named properties that are associated with schema data. Properties defined within in a bag are either mapped (associated with a column mapping) or unmapped (loose).

Bag also supports transparent renaming of properties.

A Bag is not internally synchronized.

func NewBag

func NewBag(spec *BagSpec) *Bag

NewBag creates an empty Bag for the given columns.

func NewBagFrom

func NewBagFrom(b *Bag) *Bag

NewBagFrom returns an empty Bag whose schema information is copied from the given source.

func NewBagOf

func NewBagOf(colData []types.ColData, rename *ident.Map[ident.Ident], args ...any) *Bag

NewBagOf is a test helper to construct a Bag from a varargs consisting of keys and values.

func (*Bag) CopyInto

func (b *Bag) CopyInto(dest cmap.Map[ident.Ident, any])

CopyInto implements cmap.Map.

func (*Bag) Delete

func (b *Bag) Delete(key ident.Ident)

Delete implements cmap.Map.

func (*Bag) Entries

func (b *Bag) Entries() []cmap.Entry[ident.Ident, any]

Entries implements cmap.Map.

func (*Bag) Get

func (b *Bag) Get(key ident.Ident) (_ any, ok bool)

Get implements cmap.Map.

func (*Bag) GetZero

func (b *Bag) GetZero(key ident.Ident) any

GetZero implements cmap.Map.

func (*Bag) Len

func (b *Bag) Len() int

Len implements cmap.Map and reports the number of properties with valid values.

func (*Bag) MarshalJSON

func (b *Bag) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler and serializes the contents of the Bag, but not its schema, as a JSON object.

func (*Bag) Match

func (b *Bag) Match(key ident.Ident) (_ ident.Ident, _ any, ok bool)

Match implements cmap.Map

func (*Bag) Put

func (b *Bag) Put(key ident.Ident, value any)

Put implements cmap.Map.

func (*Bag) Range

func (b *Bag) Range(fn func(k ident.Ident, v any) error) error

Range implements cmap.Map. It will emit the values of all valid properties, which could be nil.

func (*Bag) UnmarshalJSON

func (b *Bag) UnmarshalJSON(data []byte) error

UnmarshalJSON appends a JSON object to the contents of the Bag.

type BagSpec

type BagSpec struct {
	Columns []types.ColData         // Schema data that defines the Bag.
	Rename  *ident.Map[ident.Ident] // (Optional) Mapping applied to all keys passed to API.
}

A BagSpec holds common metadata about property structures.

type Conflict

type Conflict struct {
	Before   *Bag // May be nil if only 2-way merge.
	Proposed *Bag // The proposed end state of the mutation.

	// Target will be populated with the values that were present in the
	// target database. That is, the result of the merge should be to
	// apply the difference between Before and Proposed to Target.
	Target *Bag

	// Unmerged is populated by [Standard.Merge] and can be presented
	// to its fallback merge function. This slice will be populated with
	// the properties that could not be automatically merged. That is:
	//   Before[prop] != Target[prop] && Before[prop] != Proposed[prop]
	Unmerged []ident.Ident
}

A Conflict contains a mutation that was attempted and the existing data which blocked it. The maps in this type contain reified JSON representation of the values that one would expect to see from the json package.

type Entry

type Entry struct {
	Column *types.ColData
	Valid  bool // Tri-state to indicate that Value has been set, possibly to nil.
	Value  any  // Prefer checking Valid instead of comping Value to nil.
}

An Entry associates a column with some reified value.

type Func

type Func func(ctx context.Context, conflict *Conflict) (*Resolution, error)

Func adapts a function type to implement Merger.

func (Func) MarshalText

func (fn Func) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler and is provided so that the Func will play nicely in the Diagnostics interface.

func (Func) Merge

func (fn Func) Merge(ctx context.Context, conflict *Conflict) (*Resolution, error)

Merge implements Merger.

type Merger

type Merger interface {
	// Merge resolves a data conflict and returns a mutation that should
	// be unconditionally applied. If the returned boolean value is
	// false, the conflict should be ignored. It is the responsibility
	// of the Merger to ensure that the conflicted value arrived
	// somewhere.
	Merge(context.Context, *Conflict) (*Resolution, error)
}

Merger resolves data conflicts.

func DLQ

func DLQ(name string) Merger

DLQ returns a Merger that sends all values to the named dead-letter queue. This can be used as the final stage of a merge pipeline.

type Resolution

type Resolution struct {
	Apply *Bag   // The contents of the mutation to apply.
	DLQ   string // Write the incoming mutation to the named queue.
	Drop  bool   // Discard the mutation.
}

A Resolution contains the contents of a mutation after the Merger has resolved the data conflicts. Exactly one of the fields in this struct should be non-zero.

type Standard

type Standard struct {
	// The Fallback will be invoked if there were properties that could
	// not be merged.
	Fallback Merger
}

Standard implements a basic three-way merge operator.

func (*Standard) Merge

func (s *Standard) Merge(ctx context.Context, con *Conflict) (*Resolution, error)

Merge implements Merger.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL