An open API service indexing awesome lists of open source software.

https://github.com/pardnchiu/go-pg

(Go Package) PostgreSQL client with chained method calls
https://github.com/pardnchiu/go-pg

backend chain-syntax go golang pardnchiu postgresql

Last synced: 24 days ago
JSON representation

(Go Package) PostgreSQL client with chained method calls

Awesome Lists containing this project

README

          

# PostgreSQL Pool

> Golang PostgreSQL wrapper supporting chain calls, read-write separation, query builder, and complete connection management.
>
> MySQL version [here](https://github.com/pardnchiu/go-mysql)

[![pkg](https://pkg.go.dev/badge/github.com/pardnchiu/go-pg.svg)](https://pkg.go.dev/github.com/pardnchiu/go-pg)
[![license](https://img.shields.io/github/license/pardnchiu/go-pg)](LICENSE)
[![version](https://img.shields.io/github/v/tag/pardnchiu/go-pg)](https://github.com/pardnchiu/go-pg/releases)
![card](https://goreportcard.com/badge/github.com/pardnchiu/go-pg)

## Key Features

### Read-Write Separation
Support read-write connection pool configuration, enabling pre-connections to improve efficiency.

### Query Builder
Provide a chainable SQL query builder interface to prevent SQL injection attacks.

### CRUD Operations
Complete support for create, read, update, and delete operations.

### PostgreSQL-Specific Features
- Support for schemas
- ILIKE operator for case-insensitive pattern matching
- ON CONFLICT for upsert operations
- RETURNING clause for insert/update operations

## Dependencies

- [`github.com/lib/pq`](https://github.com/lib/pq)
- [`github.com/joho/godotenv`](https://github.com/joho/godotenv)

## Installation

```bash
go get github.com/pardnchiu/go-pg
```

## Environment Variables

```env
# default 127.0.0.1
PG_READ_HOST=
# default 5432
PG_READ_PORT=
# default postgres
PG_READ_USER=
# default empty
PG_READ_PASSWORD=
# default postgres
PG_READ_DATABASE=
# default disable
PG_READ_SSLMODE=
# default 4
PG_READ_CONNECTION=

# * default is read
PG_WRITE_HOST=
PG_WRITE_PORT=
PG_WRITE_USER=
PG_WRITE_PASSWORD=
PG_WRITE_DATABASE=
PG_WRITE_SSLMODE=
PG_WRITE_CONNECTION=
```

## Configuration

### Method 1: Using Config Struct

```go
config := goPg.Config{
Read: &goPg.DBConfig{
Host: "localhost",
Port: 5432,
User: "postgres",
Password: "password",
Database: "myapp",
SSLMode: "disable",
Connection: 10,
},
Write: &goPg.DBConfig{
Host: "localhost",
Port: 5432,
User: "postgres",
Password: "password",
Database: "myapp",
SSLMode: "disable",
Connection: 5,
},
}

pool, err := goPg.New(config)
```

### Method 2: Using Environment Variables

```go
pool, err := goPg.New()
```

## Query Operations

### Basic Query

```go
rows, err := pool.Read.
Schema("public").
Table("users").
Select("id", "name", "email").
Where("status", "active").
Get()

defer rows.Close()
for rows.Next() {
var id int
var name, email string
rows.Scan(&id, &name, &email)
}
```

### Complex Conditions

```go
rows, err := pool.Read.
Schema("public").
Table("users").
Select("*").
Where("age", ">", 18).
Where("status", "active").
Where("name", "ILIKE", "john"). // Case-insensitive
OrderBy("created_at", "DESC").
Limit(10).
Offset(20).
Get()
```

### JOIN Query

```go
rows, err := pool.Read.
Schema("public").
Table("users").
Select("users.name", "profiles.bio").
LeftJoin("profiles", "users.id", "profiles.user_id").
Where("users.status", "active").
Get()
```

### Query with Total Count

```go
rows, err := pool.Read.
Schema("public").
Table("users").
Select("id", "name").
Where("status", "active").
Total().
Limit(10).
Get()

for rows.Next() {
var total, id int
var name string
rows.Scan(&total, &id, &name)
}
```

## Insert Operations

### Basic Insert

```go
data := map[string]interface{}{
"name": "Jane Doe",
"email": "jane@example.com",
"age": 25,
}

lastID, err := pool.Write.
Schema("public").
Table("users").
Insert(data)
```

## Update Operations

### Basic Update

```go
updateData := map[string]interface{}{
"age": 26,
"status": "updated",
}

result, err := pool.Write.
Schema("public").
Table("users").
Where("id", 1).
Update(updateData)

rowsAffected, _ := result.RowsAffected()
```

### Using PostgreSQL Functions

```go
updateData := map[string]interface{}{
"updated_at": "NOW()",
"last_login": "CURRENT_TIMESTAMP",
}

result, err := pool.Write.
Schema("public").
Table("users").
Where("id", 1).
Update(updateData)
```

### Increase Values

```go
result, err := pool.Write.
Schema("public").
Table("users").
Where("id", 1).
Increase("view_count", 1).
Update()
```

## Upsert Operations

### Basic Upsert

```go
data := map[string]interface{}{
"email": "unique@example.com",
"name": "New User",
"age": 30,
}

// Update all fields on conflict
lastID, err := pool.Write.
Schema("public").
Table("users").
Upsert(data, []string{"email"})
```

### Upsert with Specific Update Fields

```go
data := map[string]interface{}{
"email": "unique@example.com",
"name": "New User",
}

updateData := map[string]interface{}{
"name": "Updated User",
"last_login": "NOW()",
}

lastID, err := pool.Write.
Schema("public").
Table("users").
Upsert(data, []string{"email"}, updateData)
```

## Direct SQL Execution

### Query

```go
rows, err := pool.Read.Query(
"SELECT * FROM users WHERE age > $1 AND status = $2",
18,
"active",
)
```

### Execute

```go
result, err := pool.Write.Exec(
"UPDATE users SET status = $1 WHERE age > $2",
"senior",
35,
)
```

## Supported PostgreSQL Functions

- `NOW()`
- `CURRENT_TIMESTAMP`
- `CURRENT_DATE`
- `CURRENT_TIME`
- `LOCALTIMESTAMP`
- `LOCALTIME`
- `TRANSACTION_TIMESTAMP()`
- `STATEMENT_TIMESTAMP()`
- `CLOCK_TIMESTAMP()`
- `GEN_RANDOM_UUID()`
- `RANDOM()`
- And more...

## Connection Pool Management

```go
defer pool.Close()
```

The package automatically listens for `SIGINT` and `SIGTERM` signals for graceful shutdown.

## Slow Query Logging

Queries taking longer than 20ms are automatically logged.

## Complete Example

```go
package main

import (
"log"
goPg "github.com/pardnchiu/go-pg"
)

func main() {
pool, err := goPg.New()
if err != nil {
log.Fatal(err)
}
defer pool.Close()

// Insert
data := map[string]interface{}{
"name": "John Doe",
"email": "john@example.com",
"age": 30,
}
lastID, _ := pool.Write.Schema("public").Table("users").Insert(data)

// Query
rows, _ := pool.Read.
Schema("public").
Table("users").
Select("id", "name", "email").
Where("age", ">", 18).
OrderBy("created_at", "DESC").
Limit(10).
Get()
defer rows.Close()

for rows.Next() {
var id int
var name, email string
rows.Scan(&id, &name, &email)
log.Printf("User: %s (%s)\n", name, email)
}

// Update
updateData := map[string]interface{}{
"age": 31,
}
pool.Write.Schema("public").Table("users").Where("id", lastID).Update(updateData)
}
```

## License

This project is licensed under the [MIT](LICENSE) license.

## Author

邱敬幃 Pardn Chiu





***

©️ 2025 [邱敬幃 Pardn Chiu](https://pardn.io)