powder

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 10 Imported by: 0

README

powder-go — Go 바인딩

Powder 엔진의 Go 클라이언트. powder-ffi 크레이트가 내보내는 안정 C ABI를 통해 Rust 코어를 호출하고, zero-copy PCB 컬럼 버퍼를 순수 Go로 디코드한다.

  • Windows: C 툴체인 불필요 — 라이브러리를 syscall로 바인딩하므로 CGO_ENABLED=0으로 빌드된다.
  • Linux / macOS: cgo를 통해 공유 라이브러리를 dlopen한다.

빌드 & 테스트

# 1. 네이티브 C-ABI 라이브러리
cargo build -p powder-ffi --release
#    -> <target>/release/powder_ffi.dll | libpowder_ffi.so | libpowder_ffi.dylib

# 2. 이를 대상으로 Go 테스트 실행
cd bindings/go
POWDER_LIB=<target>/release/powder_ffi.dll go test ./...

POWDER_LIB가 테스트에 네이티브 라이브러리 위치를 알려준다; 없으면 테스트는 스킵된다.

사용법

import powder "github.com/OSS-Ncode/powderORM/bindings/go"

if err := powder.Load("/path/to/powder_ffi.dll"); err != nil { panic(err) }

db, err := powder.Connect("sqlite::memory:")
if err != nil { panic(err) }
defer db.Close()

db.Exec("CREATE TABLE users (id INTEGER, name TEXT, score REAL)")
db.Exec("INSERT INTO users VALUES (?,?,?)", 1, "alice", 9.5)

// 플루언트 빌더, 또는 바인딩 파라미터가 있는 raw SQL.
batch, err := db.Run(powder.Table("users").Select("id", "name").OrderBy("id", "ASC"))
name := batch.Column("name")
for r := 0; r < batch.NumRows(); r++ {
    fmt.Println(name.String(r))
}

// 트랜잭션; 중첩 호출은 savepoint 사용.
err = db.Transaction(func(tx *powder.Client) error {
    _, err := tx.Exec("INSERT INTO users VALUES (2, 'bob', 7.0)")
    return err
})

참고

  • 바인딩 파라미터는 Go 정수, 부동소수점, string, bool, nil을 받는다. ABI를 JSON 배열 문자열로 넘어가므로 C 표면이 단순 포인터와 정수로 유지된다.
  • Column은 리틀 엔디언 PCB 페이로드에서 값을 바로 읽는다; 요청하기 전까지 아무것도 구체화되지 않는다. Batch.Rows()는 편의용(복사) 뷰다.
  • PCB 페이로드는 네이티브 메모리에서 Go 슬라이스로 한 번 복사되고 이후 GC가 소유한다 — Go는 외부 할당에 대한 포인터를 안전하게 들고 있을 수 없다.
  • Client는 자신의 호출을 직렬화한다; Rust 코어가 단일 연결을 소유한다.

ORM

powder.schema.json 텍스트로 스키마 인식 모델 레이어를 얻는다 — 다른 모든 Powder ORM과 동일한 연산·문법(공유 Rust 엔진):

orm, err := db.Orm(schemaJSON)
defer orm.Close()
users := orm.Table("users")

users.Create(powder.M{"id": 1, "name": "alice", "score": 9.5, "active": true})
rows, err := users.FindMany(powder.M{
    "where":   powder.M{"active": true, "score": powder.M{"gte": 5}},
    "orderBy": powder.M{"score": "desc"},
    "limit":   10,
})
posts, _ := orm.Table("posts").FindMany(powder.M{"include": powder.M{"user": true}})
users.Update(powder.M{"id": 1}, powder.M{"score": 10})
users.Count(powder.M{"active": true})
users.GroupBy(powder.M{"by": []string{"active"}, "count": true,
    "having": powder.M{"_count": powder.M{"gte": 2}}})

whereeq ne gt gte lt lte like in 연산자와 AND/OR/NOT 중첩, include(배치 관계 로드)와 join(belongsTo LEFT JOIN)을 지원한다.

Documentation

Overview

Package powder is the Go client for the Powder engine.

It talks to the Rust core through the stable C ABI exported by the powder-ffi crate (powder_ffi.dll / libpowder_ffi.so / .dylib). Query results arrive as the zero-copy PCB columnar buffer and are decoded in pure Go.

Load the native library once, then connect:

if err := powder.Load("/path/to/powder_ffi.dll"); err != nil { ... }
db, err := powder.Connect("sqlite::memory:")
defer db.Close()

batch, err := db.Query("SELECT id, name FROM users WHERE id >= ?", 2)
name := batch.Column("name")
for r := 0; r < batch.NumRows(); r++ { fmt.Println(name.String(r)) }

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Load

func Load(path string) error

Load binds the native Powder library from an absolute path. Call once before Connect; subsequent calls are no-ops.

Types

type Batch

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

Batch is a decoded columnar result set.

func DecodePCB

func DecodePCB(data []byte) (*Batch, error)

DecodePCB parses a PCB payload. The batch borrows data; do not mutate it.

func (*Batch) Column

func (b *Batch) Column(name string) *Column

Column returns the named column, or nil.

func (*Batch) Columns

func (b *Batch) Columns() []*Column

func (*Batch) NumRows

func (b *Batch) NumRows() int

func (*Batch) Rows

func (b *Batch) Rows() []map[string]any

Rows returns a row-oriented view (copies) — handy for small result sets.

type Client

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

Client is a database connection. It is safe for use from one goroutine at a time; the Rust core serializes access to its single connection.

func Connect

func Connect(url string) (*Client, error)

Connect opens a connection (e.g. "sqlite::memory:" or a file path). Call Load first.

func (*Client) Close

func (c *Client) Close() error

Close releases the connection. Safe to call more than once.

func (*Client) Exec

func (c *Client) Exec(sql string, params ...any) (int64, error)

Exec runs a non-row statement (INSERT/UPDATE/DDL) and returns rows affected.

func (*Client) Orm

func (c *Client) Orm(schemaJSON string) (*Orm, error)

Orm parses a `powder.schema.json` document and returns the model layer.

func (*Client) Query

func (c *Client) Query(sql string, params ...any) (*Batch, error)

Query runs a query and decodes the PCB result into a Batch.

func (*Client) Run

func (c *Client) Run(q *Query) (*Batch, error)

Run executes a built Query.

func (*Client) Transaction

func (c *Client) Transaction(fn func(tx *Client) error) (err error)

Transaction runs fn in a transaction. The outermost call issues BEGIN IMMEDIATE + COMMIT/ROLLBACK; nested calls use SAVEPOINT / RELEASE / ROLLBACK TO, so an inner transaction that fails rolls back only its own work while an outer one can still commit.

type Column

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

Column is a single decoded PCB column. Values are read straight out of the little-endian payload; nothing is materialized until you ask for it.

func (*Column) Bool

func (c *Column) Bool(row int) bool

func (*Column) Float64

func (c *Column) Float64(row int) float64

func (*Column) Get

func (c *Column) Get(row int) any

Get returns the boxed value at row, or nil for NULL / out of range.

func (*Column) Int64

func (c *Column) Int64(row int) int64

func (*Column) IsValid

func (c *Column) IsValid(row int) bool

IsValid reports whether the slot at row holds a value (vs. SQL NULL).

func (*Column) Len

func (c *Column) Len() int

func (*Column) Name

func (c *Column) Name() string

func (*Column) String

func (c *Column) String(row int) string

func (*Column) Type

func (c *Column) Type() DataType

type DataType

type DataType uint8

DataType is one of the four physical column types carried by PCB.

const (
	Int64 DataType = iota
	Float64
	Bool
	Utf8
)

func (DataType) String

func (d DataType) String() string

type M

type M = map[string]any

M is shorthand for the JSON-shaped maps the ORM takes and returns.

type Orm

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

Orm is the model layer over a Client: the same operation semantics as the TS/Python ORMs, executed by the shared Rust engine. Build one from the `powder.schema.json` text; then address tables by name.

orm, err := db.Orm(schemaJSON)
users := orm.Table("users")
rows, err := users.FindMany(powder.M{
    "where":   powder.M{"active": true, "score": powder.M{"gte": 5}},
    "orderBy": powder.M{"score": "desc"},
    "limit":   10,
})

func (*Orm) Close

func (o *Orm) Close()

Close frees the parsed schema. Safe to call more than once.

func (*Orm) Table

func (o *Orm) Table(name string) *OrmTable

Table returns a handle for one table's CRUD surface.

type OrmTable

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

OrmTable is the unified CRUD surface of Powder ORM for one table.

func (*OrmTable) Aggregate

func (t *OrmTable) Aggregate(fn, column string, where M) (*float64, error)

Aggregate runs SUM/AVG/MIN/MAX over one column; nil when no rows match.

func (*OrmTable) All

func (t *OrmTable) All() ([]M, error)

All returns every row.

func (*OrmTable) Count

func (t *OrmTable) Count(where M) (int64, error)

Count counts rows matching where (nil counts everything).

func (*OrmTable) Create

func (t *OrmTable) Create(data M) (int64, error)

Create INSERTs one row; missing (nullable) columns are omitted.

func (*OrmTable) CreateMany

func (t *OrmTable) CreateMany(rows []M) (int64, error)

CreateMany bulk-INSERTs with multi-row VALUES, chunked; every row must carry the same columns as the first.

func (*OrmTable) Delete

func (t *OrmTable) Delete(where M) (int64, error)

Delete DELETEs matching rows. An empty where is rejected — use DeleteAll.

func (*OrmTable) DeleteAll

func (t *OrmTable) DeleteAll() (int64, error)

DeleteAll deletes every row (explicit opt-in).

func (*OrmTable) Exists

func (t *OrmTable) Exists(where M) (bool, error)

Exists reports whether at least one row matches.

func (*OrmTable) FindFirst

func (t *OrmTable) FindFirst(opts M) (M, error)

FindFirst returns the first matching row, or nil.

func (*OrmTable) FindMany

func (t *OrmTable) FindMany(opts M) ([]M, error)

FindMany returns rows matching opts (`where`, `orderBy`, `limit`, `offset`, `include`, `join` — same keys as the TS/Python ORMs). Pass nil for all rows.

func (*OrmTable) GroupBy

func (t *OrmTable) GroupBy(opts M) ([]M, error)

GroupBy groups with aggregates (`by`, `count`, `sum`, `avg`, `min`, `max`, `having`, `orderBy`, `limit`, `offset`). Aggregates come back aliased `_count`, `_sum_<col>`, ....

func (*OrmTable) Update

func (t *OrmTable) Update(where M, data M) (int64, error)

Update UPDATEs matching rows; returns the affected count.

type Query

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

Query is a fluent, injection-safe SELECT builder — the Go mirror of the Rust/TypeScript/Java builders. Values go through bound parameters; only identifiers you supply are interpolated.

q := powder.Table("users").Select("id", "name").
	Filter("score >= ?", 5.0).OrderBy("score", "DESC").Limit(10)
batch, err := db.Run(q)

func Table

func Table(name string) *Query

Table starts a query against the named table.

func (*Query) Filter

func (q *Query) Filter(predicate string, params ...any) *Query

Filter adds a WHERE predicate; supply one "?" per parameter. Repeated calls are ANDed together.

func (*Query) Limit

func (q *Query) Limit(n int64) *Query

func (*Query) Offset

func (q *Query) Offset(n int64) *Query

func (*Query) OrderBy

func (q *Query) OrderBy(column, direction string) *Query

OrderBy sets the sort column and direction ("ASC" or "DESC").

func (*Query) Params

func (q *Query) Params() []any

Params returns the bound parameters, in placeholder order.

func (*Query) SQL

func (q *Query) SQL() string

SQL renders the statement.

func (*Query) Select

func (q *Query) Select(columns ...string) *Query

Select sets the projected columns (defaults to "*").

Jump to

Keyboard shortcuts

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