compact

package
v0.6.3 Latest Latest
Warning

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

Go to latest
Published: Feb 14, 2026 License: MIT Imports: 6 Imported by: 0

README

Compact Codec for JSON Patch Operations

The compact codec provides a highly optimized array-based encoding format for JSON Patch operations, achieving 35.9% space savings compared to standard JSON format while maintaining full compatibility with all operation types.

🎯 Key Benefits: Space efficiency, performance optimization, flexible opcode formats, perfect round-trip compatibility.

Format Comparison & Space Savings

Standard Struct API:
{Op: "add", Path: "/foo/bar", Value: 123}
Standard JSON format:
{"op": "add", "path": "/foo/bar", "value": 123}
Compact format (numeric opcodes):
[0, "/foo/bar", 123]
Compact format (string opcodes):
["add", "/foo/bar", 123]

Space Savings: 35.9% reduction in data size with numeric opcodes!

Usage

Basic Operations with Struct API
package main

import (
    "fmt"
    "github.com/kaptinlin/jsonpatch"
    "github.com/kaptinlin/jsonpatch/codec/compact"
)

func main() {
    // Create operations using struct API
    operations := []jsonpatch.Operation{
        {Op: "add", Path: "/foo", Value: "bar"},
        {Op: "replace", Path: "/baz", Value: 42},
        {Op: "inc", Path: "/counter", Inc: 5},
        {Op: "str_ins", Path: "/text", Pos: 0, Str: "Hello "},
    }
    
    // Encode to compact format (numeric opcodes for max space savings)
    encoder := compact.NewEncoder(compact.WithStringOpcode(false))
    encoded, err := encoder.EncodeJSON(operations)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("Compact JSON: %s\n", encoded)
    // Output: [[0,"/foo","bar"],[2,"/baz",42],[9,"/counter",5],[6,"/text",0,"Hello "]]
    
    // Decode back to operations
    decoder := compact.NewDecoder()
    decoded, err := decoder.DecodeJSON(encoded)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("Decoded: %d operations\n", len(decoded))
    // Space savings: ~35.9% compared to standard JSON format
}
String Opcodes
// Use string opcodes instead of numeric ones
encoder := compact.NewEncoder(compact.WithStringOpcode(true))
encoded, err := encoder.Encode(ops)
// Result: [["add" "/foo" "bar"] ["replace" "/baz" 42]]
JSON Marshaling
// Encode to JSON bytes
jsonData, err := compact.EncodeJSON(ops)
if err != nil {
    panic(err)
}

// Decode from JSON bytes
decoded, err := compact.DecodeJSON(jsonData)
if err != nil {
    panic(err)
}

Complete Operation Mapping (From Code Analysis)

Based on decode.go implementation, here are all supported operations:

Standard JSON Patch Operations (RFC 6902)
Operation Numeric Code String Code Compact Format Example
add 0 "add" [0, path, value] [0, "/foo", 123]
remove 1 "remove" [1, path] [1, "/foo"]
replace 2 "replace" [2, path, value] [2, "/foo", 456]
copy 3 "copy" [3, path, from] [3, "/bar", "/foo"]
move 4 "move" [4, path, from] [4, "/bar", "/foo"]
test 5 "test" [5, path, value] [5, "/foo", 123]
String Operations
Operation Numeric Code String Code Compact Format Example
str_ins 6 "str_ins" [6, path, pos, str] [6, "/text", 0, "Hi "]
str_del 7 "str_del" [7, path, pos, len] [7, "/text", 5, 3]
Extended Operations
Operation Numeric Code String Code Compact Format Example
flip 8 "flip" [8, path] [8, "/active"]
inc 9 "inc" [9, path, delta] [9, "/count", 5]
split 10 "split" [10, path, pos, props?] [10, "/obj", 2]
merge 11 "merge" [11, path, pos, props?] [11, "/obj", 0]
extend 12 "extend" [12, path, props, deleteNull?] [12, "/config", {...}]
JSON Predicate Operations
Operation Numeric Code String Code Compact Format Example
contains 30 "contains" [30, path, value, ignoreCase?] [30, "/text", "hello"]
defined 31 "defined" [31, path] [31, "/field"]
ends 32 "ends" [32, path, value, ignoreCase?] [32, "/text", ".com"]
in 33 "in" [33, path, values] [33, "/role", ["admin","user"]]
less 34 "less" [34, path, value] [34, "/age", 30]
matches 35 "matches" [35, path, pattern, ignoreCase?] [35, "/email", ".*@.*"]
more 36 "more" [36, path, value] [36, "/score", 100]
starts 37 "starts" [37, path, value, ignoreCase?] [37, "/text", "Hello"]
undefined 38 "undefined" [38, path] [38, "/optional"]
test_type 39 "test_type" [39, path, types] [39, "/data", ["string","number"]]
test_string 40 "test_string" [40, path, pos, str, not?] [40, "/text", 5, "test"]
test_string_len 41 "test_string_len" [41, path, len, not?] [41, "/text", 10]
type 42 "type" [42, path, type] [42, "/data", "string"]
Second-Order Predicates
Operation Numeric Code String Code Compact Format Example
and 43 "and" [43, path, ops[]] [43, "", [[31,"/a"],[42,"/b","string"]]]
not 44 "not" [44, path, ops[]] [44, "", [[31,"/field"]]]
or 45 "or" [45, path, ops[]] [45, "", [[31,"/a"],[31,"/b"]]]

API Reference

Encoder
type Encoder struct { ... }

// Create a new encoder
func NewEncoder(opts ...EncoderOption) *Encoder

// Encode a single operation
func (e *Encoder) Encode(op internal.Op) (CompactOp, error)

// Encode multiple operations
func (e *Encoder) EncodeSlice(ops []internal.Op) ([]CompactOp, error)
Decoder
type Decoder struct { ... }

// Create a new decoder
func NewDecoder(opts ...DecoderOption) *Decoder

// Decode a single compact operation
func (d *Decoder) Decode(compactOp CompactOp) (internal.Op, error)

// Decode multiple compact operations
func (d *Decoder) DecodeSlice(compactOps []CompactOp) ([]internal.Op, error)
Standalone Functions
// Encode operations using default options
func Encode(ops []internal.Op, opts ...EncoderOption) ([]CompactOp, error)

// Encode operations to JSON bytes
func EncodeJSON(ops []internal.Op, opts ...EncoderOption) ([]byte, error)

// Decode compact operations using default options
func Decode(compactOps []CompactOp, opts ...DecoderOption) ([]internal.Op, error)

// Decode compact operations from JSON bytes
func DecodeJSON(data []byte, opts ...DecoderOption) ([]internal.Op, error)
Options
// Use string opcodes instead of numeric codes
func WithStringOpcode(useString bool) EncoderOption

Features

  • Space Efficient: Significantly smaller than standard JSON format
  • Fast: Optimized encoding and decoding performance
  • Flexible: Supports both numeric and string opcodes
  • Compatible: Works with all existing operation types
  • Type Safe: Full Go type safety and error handling

Supported Operations

The compact codec now supports all JSON Patch operations with full encoding and decoding:

Standard JSON Patch (RFC 6902)

✅ add, remove, replace, move, copy, test

Extended Operations

✅ flip, inc, str_ins, str_del, split, merge, extend

JSON Predicate Operations

✅ defined, undefined, contains, starts, ends, matches, type, test_type, test_string, test_string_len, in, less, more

Second-Order Predicates (Composite Operations)

✅ and, or, not

Documentation

Overview

Package compact implements a compact array-based codec for JSON Patch operations. It uses arrays instead of objects to represent operations, reducing the physical space required for encoding while maintaining readability.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMinLength     = errors.New("compact operation must have at least opcode and path")
	ErrPathNotString = errors.New("compact operation path must be a string")
)

Base errors for compact operation validation.

View Source
var (
	ErrAddMissingValue     = errors.New("add operation requires value")
	ErrReplaceMissingValue = errors.New("replace operation requires value")
	ErrMoveMissingFrom     = errors.New("move operation requires from path")
	ErrMoveFromNotString   = errors.New("move operation from must be a string")
	ErrCopyMissingFrom     = errors.New("copy operation requires from path")
	ErrCopyFromNotString   = errors.New("copy operation from must be a string")
	ErrTestMissingValue    = errors.New("test operation requires value")
)

Core operation (RFC 6902) errors.

View Source
var (
	ErrIncMissingDelta      = errors.New("inc operation requires delta")
	ErrIncDeltaNotNumber    = errors.New("inc operation delta must be a number")
	ErrStrInsMissingFields  = errors.New("str_ins operation requires pos and str")
	ErrStrInsPosNotNumber   = errors.New("str_ins operation pos must be a number")
	ErrStrInsStrNotString   = errors.New("str_ins operation str must be a string")
	ErrStrDelMissingFields  = errors.New("str_del operation requires pos and len")
	ErrStrDelPosNotNumber   = errors.New("str_del operation pos must be a number")
	ErrStrDelLenNotNumber   = errors.New("str_del operation len must be a number")
	ErrSplitMissingPos      = errors.New("split operation requires pos")
	ErrSplitPosNotNumber    = errors.New("split operation pos must be a number")
	ErrMergeMissingPos      = errors.New("merge operation requires pos")
	ErrMergePosNotNumber    = errors.New("merge operation pos must be a number")
	ErrExtendMissingProps   = errors.New("extend operation requires props")
	ErrExtendPropsNotObject = errors.New("extend operation props must be an object")
)

Extended operation errors.

View Source
var (
	ErrContainsMissingValue    = errors.New("contains operation requires value")
	ErrContainsValueNotString  = errors.New("contains operation value must be a string")
	ErrStartsMissingValue      = errors.New("starts operation requires value")
	ErrStartsValueNotString    = errors.New("starts operation value must be a string")
	ErrEndsMissingValue        = errors.New("ends operation requires value")
	ErrEndsValueNotString      = errors.New("ends operation value must be a string")
	ErrTypeMissingType         = errors.New("type operation requires type")
	ErrTypeNotString           = errors.New("type operation type must be a string")
	ErrTestTypeMissingTypes    = errors.New("test_type operation requires types")
	ErrTestTypeTypesNotArray   = errors.New("test_type operation types must be an array")
	ErrTestStringMissingStr    = errors.New("test_string operation requires str")
	ErrTestStringNotString     = errors.New("test_string operation str must be a string")
	ErrTestStringLenMissingLen = errors.New("test_string_len operation requires len")
	ErrTestStringLenNotNumber  = errors.New("test_string_len operation len must be a number")
	ErrInMissingValues         = errors.New("in operation requires values")
	ErrInValuesNotArray        = errors.New("in operation values must be an array")
	ErrLessMissingValue        = errors.New("less operation requires value")
	ErrLessValueNotNumber      = errors.New("less operation value must be a number")
	ErrMoreMissingValue        = errors.New("more operation requires value")
	ErrMoreValueNotNumber      = errors.New("more operation value must be a number")
	ErrMatchesMissingPattern   = errors.New("matches operation requires pattern")
	ErrMatchesPatternNotString = errors.New("matches operation pattern must be a string")
)

Predicate operation errors.

View Source
var (
	ErrAndMissingOps      = errors.New("and operation requires ops")
	ErrOrMissingOps       = errors.New("or operation requires ops")
	ErrNotMissingOps      = errors.New("not operation requires ops")
	ErrPredicateNotArray  = errors.New("predicate ops must be an array")
	ErrPredicateOpInvalid = errors.New("predicate op must be an array")
	ErrNotPredicate       = errors.New("decoded operation is not a predicate")
)

Composite operation errors.

View Source
var (
	ErrUnsupportedOp      = errors.New("unsupported operation type")
	ErrUnknownStringCode  = errors.New("unknown string opcode")
	ErrInvalidCodeType    = errors.New("invalid opcode type")
	ErrUnknownNumericCode = errors.New("unknown numeric opcode")
	ErrNotFloat64         = errors.New("cannot convert to float64")
	ErrExpectedArray      = errors.New("expected array")
	ErrExpectedString     = errors.New("expected string in array")
)

Resolution and conversion errors.

Functions

func Decode

func Decode(ops []Op) ([]internal.Op, error)

Decode decodes compact format operations.

func DecodeJSON

func DecodeJSON(data []byte) ([]internal.Op, error)

DecodeJSON decodes compact format JSON bytes into operations.

func EncodeJSON

func EncodeJSON(ops []internal.Op, opts ...Option) ([]byte, error)

EncodeJSON encodes operations into compact JSON bytes.

Types

type Code added in v0.5.15

type Code int

Code represents a numeric operation code in compact format.

const (
	// JSON Patch (RFC 6902)
	CodeAdd     Code = Code(internal.OpAddCode)
	CodeRemove  Code = Code(internal.OpRemoveCode)
	CodeReplace Code = Code(internal.OpReplaceCode)
	CodeCopy    Code = Code(internal.OpCopyCode)
	CodeMove    Code = Code(internal.OpMoveCode)
	CodeTest    Code = Code(internal.OpTestCode)

	// String editing
	CodeStrIns Code = Code(internal.OpStrInsCode)
	CodeStrDel Code = Code(internal.OpStrDelCode)

	// Extra
	CodeFlip Code = Code(internal.OpFlipCode)
	CodeInc  Code = Code(internal.OpIncCode)

	// Slate.js
	CodeSplit  Code = Code(internal.OpSplitCode)
	CodeMerge  Code = Code(internal.OpMergeCode)
	CodeExtend Code = Code(internal.OpExtendCode)

	// JSON Predicate
	CodeContains      Code = Code(internal.OpContainsCode)
	CodeDefined       Code = Code(internal.OpDefinedCode)
	CodeEnds          Code = Code(internal.OpEndsCode)
	CodeIn            Code = Code(internal.OpInCode)
	CodeLess          Code = Code(internal.OpLessCode)
	CodeMatches       Code = Code(internal.OpMatchesCode)
	CodeMore          Code = Code(internal.OpMoreCode)
	CodeStarts        Code = Code(internal.OpStartsCode)
	CodeUndefined     Code = Code(internal.OpUndefinedCode)
	CodeTestType      Code = Code(internal.OpTestTypeCode)
	CodeTestString    Code = Code(internal.OpTestStringCode)
	CodeTestStringLen Code = Code(internal.OpTestStringLenCode)
	CodeType          Code = Code(internal.OpTypeCode)
	CodeAnd           Code = Code(internal.OpAndCode)
	CodeNot           Code = Code(internal.OpNotCode)
	CodeOr            Code = Code(internal.OpOrCode)
)

Numeric operation codes derived from internal constants.

type Decoder

type Decoder struct{}

Decoder decodes compact format operations.

func NewDecoder

func NewDecoder() *Decoder

NewDecoder creates a new compact decoder.

func (*Decoder) Decode

func (d *Decoder) Decode(raw Op) (internal.Op, error)

Decode decodes a single compact operation.

func (*Decoder) DecodeSlice

func (d *Decoder) DecodeSlice(ops []Op) ([]internal.Op, error)

DecodeSlice decodes multiple compact operations.

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

Encoder encodes operations into compact format.

func NewEncoder

func NewEncoder(opts ...Option) *Encoder

NewEncoder creates a new compact encoder with the given options.

func (*Encoder) Encode

func (e *Encoder) Encode(o internal.Op) (Op, error)

Encode encodes a single operation into compact format.

func (*Encoder) EncodeSlice

func (e *Encoder) EncodeSlice(ops []internal.Op) ([]Op, error)

EncodeSlice encodes multiple operations into compact format.

type Op added in v0.4.3

type Op []any

Op represents a compact format operation as an array.

func Encode

func Encode(ops []internal.Op, opts ...Option) ([]Op, error)

Encode encodes operations into compact format.

type Operation

type Operation = internal.CompactOperation

Operation represents a compact format operation.

type Option added in v0.5.15

type Option func(*Options)

Option is a functional option for configuring the encoder.

func WithStringOpcode

func WithStringOpcode(useString bool) Option

WithStringOpcode configures the encoder to use string opcodes.

type Options added in v0.5.15

type Options struct {
	// StringOpcode uses string opcodes instead of numeric ones.
	StringOpcode bool
}

Options configures the compact encoder behavior.

Jump to

Keyboard shortcuts

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