Skip to content

Latest commit

 

History

History
159 lines (122 loc) · 4.41 KB

File metadata and controls

159 lines (122 loc) · 4.41 KB

Dot Library

The Dot library provides a powerful utility for accessing and modifying nested properties in objects using dot notation. It simplifies working with complex nested structures in Go by allowing you to use string paths to navigate through maps, structs, and arrays.

Installation

import "github.com/getevo/evo/v2/lib/dot"

Features

  • Dot Notation Access: Access nested properties using simple string paths (e.g., "user.address.city")
  • Type Support: Works with maps, structs, arrays, and slices
  • Get & Set Operations: Both retrieve and modify values in complex objects
  • Array Indexing: Support for array/slice access using index notation (e.g., "users[0].name")
  • Error Handling: Proper error reporting for invalid paths or operations
  • Reflection-Based: Uses Go's reflection capabilities for dynamic property access

API Reference

Get

func Get(obj any, prop string) (any, error)

Retrieves a value from an object using dot notation.

Parameters:

  • obj: The object to retrieve the value from (can be a map, struct, array, or slice)
  • prop: The property path using dot notation (e.g., "user.address.city" or "users[0].name")

Returns:

  • The value at the specified path
  • An error if the path is invalid or the property doesn't exist

Set

func Set(input any, prop string, value any) error

Sets a value in an object using dot notation.

Parameters:

  • input: The object to modify (must be a pointer for structs)
  • prop: The property path using dot notation (e.g., "user.address.city" or "users[0].name")
  • value: The new value to set

Returns:

  • An error if the path is invalid, the property doesn't exist, or the object is not modifiable

Usage Examples

Basic Usage with Maps

package main

import (
    "fmt"
    "github.com/getevo/evo/v2/lib/dot"
)

func main() {
    // Create a map with nested properties
    data := map[string]any{
        "user": map[string]any{
            "name": "John Doe",
            "address": map[string]any{
                "city": "New York",
                "zip": "10001",
            },
        },
    }
    
    // Get a nested property
    city, err := dot.Get(data, "user.address.city")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("City:", city) // Output: City: New York
    
    // Set a nested property
    err = dot.Set(&data, "user.address.city", "San Francisco")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    // Verify the change
    city, _ = dot.Get(data, "user.address.city")
    fmt.Println("New City:", city) // Output: New City: San Francisco
}

Working with Arrays and Slices

package main

import (
    "fmt"
    "github.com/getevo/evo/v2/lib/dot"
)

func main() {
    // Create a map with an array
    data := map[string]any{
        "users": []map[string]any{
            {
                "name": "Alice",
                "age":  30,
            },
            {
                "name": "Bob",
                "age":  25,
            },
        },
    }
    
    // Get a value from an array using index
    name, err := dot.Get(data, "users[0].name")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("First user:", name) // Output: First user: Alice
    
    // Set a value in an array
    err = dot.Set(&data, "users[1].age", 26)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    // Verify the change
    age, _ := dot.Get(data, "users[1].age")
    fmt.Println("Bob's new age:", age) // Output: Bob's new age: 26
}

How It Works

The Dot library uses Go's reflection capabilities to dynamically access and modify properties in objects. It works by:

  1. Parsing the dot notation path into individual segments
  2. Traversing the object structure one segment at a time
  3. Using reflection to access properties in maps, structs, arrays, and slices
  4. Handling special cases like array indexing with a regular expression

For maps, it directly accesses the map keys. For structs, it uses reflection to access the fields. For arrays and slices, it uses indexing to access elements.

When setting values, it ensures that the object is properly modifiable (e.g., structs must be passed as pointers) and creates intermediate objects as needed (e.g., creating nested maps if they don't exist).