mstgnz / godyno

SQL to Struct Conversion

Repository from Github https://github.commstgnz/godynoRepository from Github https://github.commstgnz/godyno

godyno

GoDyno is a lightweight library that automatically converts Go database query results into dynamic structs with matching real types. It provides an experience similar to Laravel's stdClass in Go, without compromising Go's static type safety.

🌟 Key Features

  • Automatic Type Detection: Creates structs with correct data types based on database query results
  • Nested Field Support: Access nested fields with dot notation like address.city
  • Direct Usage: Use values directly in conditional expressions and operations
  • Type-Safe Getters: Type-safe getters like GetBool(), GetInt(), GetFloat(), GetString()
  • Pure Go Implementation: Requires no external dependencies, uses only standard library

πŸ€” Why GoDyno?

Problem

When running database queries in Go, there are typically two ways to get results:

  1. Predefined structs: Not flexible, requires different struct structures for each query
  2. map[string]any: Very flexible, but creates type conversion difficulties
// Challenge with map[string]any:
data := map[string]any{"active": true}

// This doesn't work directly - requires type conversion
if data["active"] {  // Compilation error!
    // ...
}

// Instead, you always need to perform type conversion
if active, ok := data["active"].(bool); ok && active {
    // ...
}

Solution

GoDyno automatically converts database queries to Go values and provides a type-safe API:

// With GoDyno:
results, _ := GoDyno.QueryToStruct(db, "SELECT id, active, count FROM products")

// Direct usage in if conditions:
if results[0].GetBool("active") {
    fmt.Println("Product is active!")
}

// Numeric operations:
if results[0].GetInt("count") > 10 {
    fmt.Println("High stock!")
}

πŸ“¦ Installation

go get github.com/mstgnz/godyno

πŸš€ Usage

Basic Query

package main

import (
    "database/sql"
    "fmt"
    "log"

    "github.com/mstgnz/godyno"
    _ "github.com/lib/pq"
)

func main() {
    db, err := sql.Open("postgres", "connection-string")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    query := "SELECT id, title, active, price FROM products WHERE category_id = $1"

    results, err := godyno.QueryToStruct(db, query, 5)
    if err != nil {
        log.Fatal(err)
    }

    for _, product := range results {
        // Boolean values
        if product.GetBool("active") {
            // Numeric values
            id := product.GetInt("id")
            price := product.GetFloat("price")

            // String values
            title := product.GetString("title")

            fmt.Printf("Product #%d: %s - %.2f USD\n", id, title, price)
        }
    }
}

Using Nested Fields

query := `SELECT
    p.id,
    p.title,
    p.price,
    c.name AS category.name,
    s.stock AS stock.quantity,
    s.status AS stock.status
FROM products p
JOIN categories c ON c.id = p.category_id
JOIN stock s ON s.product_id = p.id
WHERE p.id = $1`

result, err := godyno.QueryToStruct(db, query, 42)
if err != nil {
    log.Fatal(err)
}

if len(result) > 0 {
    product := result[0]

    fmt.Println("Product:", product.GetString("title"))
    fmt.Println("Category:", product.GetString("category.name"))

    // Access to nested fields
    if product.GetInt("stock.quantity") > 0 && product.GetString("stock.status") == "available" {
        fmt.Println("In stock!")
    }
}

πŸ’‘ For Those Transitioning from Laravel to Go

If you're using the following structure in Laravel:

$products = DB::select('select * from products');
foreach ($products as $product) {
    if ($product->active) {
        echo $product->title;
    }
}

With GoDyno, you can write similarly in Go:

products, _ := godyno.QueryToStruct(db, "SELECT * FROM products")
for _, product := range products {
    if product.GetBool("active") {
        fmt.Println(product.GetString("title"))
    }
}

πŸ§ͺ Unit Tests

To run all tests:

go test -v ./...

πŸ“„ License

Distributed under the MIT License. See the LICENSE file for more information.

🀝 Contributing

Your contributions are welcome! Please add your tests before submitting a pull request and ensure the code complies with Go standards.

πŸ“Š Performance

Since GoDyno works with dynamic types and uses reflection, it may show a slight performance difference compared to predefined structs. However, for many applications, this difference is negligible, and the flexibility provided by GoDyno more than compensates for this small performance cost.

πŸ™ Inspiration

This library was developed to safely use features like Laravel's stdClass object and PHP's dynamic typing in Go. It aims to preserve the advantages of Go's static type system while offering the flexibility found in dynamic languages.

About

SQL to Struct Conversion

License:MIT License


Languages

Language:Go 100.0%