pg_liquid 0.2.0

A PostgreSQL extension for Liquid template processing.
# pg_liquid

A high-performance PostgreSQL extension for Liquid template processing, built with Rust and pgrx.

![License](https://img.shields.io/badge/license-MIT-blue.svg)
![PostgreSQL](https://img.shields.io/badge/PostgreSQL-13%2B-blue.svg)
![Rust](https://img.shields.io/badge/Rust-1.70%2B-orange.svg)

## Overview

`pg_liquid` brings the power of [Liquid templating](https://shopify.github.io/liquid/) directly into PostgreSQL. This extension provides two main functions for validating and rendering Liquid templates with JSON data, enabling dynamic content generation within your database.

Liquid is a safe, template language originally created by Shopify and used by Jekyll, GitHub Pages, and many other platforms. With `pg_liquid`, you can leverage this powerful templating system directly in your PostgreSQL queries and stored procedures.

## Features

- **๐Ÿ” Syntax Validation**: Check if Liquid template code has valid syntax
- **๐ŸŽจ Template Rendering**: Process Liquid templates with JSON data to generate final output
- **โšก High Performance**: Built in Rust for optimal performance and memory safety
- **๐Ÿ”— PostgreSQL Native**: Seamless integration with PostgreSQL's JSONB type
- **๐Ÿ“š Full Liquid Support**: Complete support for Liquid syntax including filters, conditionals, loops, and more
- **๐Ÿ›ก๏ธ Memory Safe**: Rust implementation prevents memory leaks and crashes
- **๐Ÿงช Well Tested**: Comprehensive test suite ensuring reliability

## Installation

### Prerequisites

- PostgreSQL 13+ with development headers
- Rust 1.70+
- pgrx framework

### Quick Start

#### 1. Install pgrx

```bash
cargo install --locked cargo-pgrx
```

#### 2. Initialize pgrx

Replace `pg17` with your PostgreSQL version (pg13, pg14, pg15, pg16, or pg17):

```bash
cargo pgrx init --pg17 $(which pg_config)
```

#### 3. Build and Install the Extension

```bash
# Clone just the pg_liquid directory or download the standalone package
git clone https://github.com/pitorg/pg_liquid
cd pg_liquid

cargo pgrx install --release
```

#### 4. Enable the Extension

Connect to your PostgreSQL database and run:

```sql
CREATE EXTENSION liquid;
```

### Development Installation

For development and testing:

```bash
cd pg_liquid
cargo pgrx run --release
```

**Note**: This extension is completely standalone and does not require any other components from the liquid-rust repository. It uses the published `liquid` crate from crates.io.

**Architecture**: The extension follows the pgrx pattern where the crate is named `pg_liquid` but creates an extension called `liquid` with functions in the `liquid` schema.

This will start a PostgreSQL instance with the extension already loaded.

### Verify Installation

Once installed, verify the extension works:

```sql
-- Connect to your PostgreSQL database
CREATE EXTENSION liquid;

-- Test basic functionality
SELECT liquid.check_valid_syntax('Hello {{ name }}!');
-- Should return: true

SELECT liquid.render('Hello {{ name }}!', '{"name": "World"}'::jsonb);
-- Should return: "Hello World!"
```

## Functions

The extension provides two main functions in the `liquid` schema:

### `liquid.check_valid_syntax(liquid_code TEXT) โ†’ BOOLEAN`

Validates whether the provided Liquid template code has valid syntax.

**Parameters:**
- `liquid_code` (TEXT): The Liquid template code to validate

**Returns:**
- `BOOLEAN`: `true` if the syntax is valid, `false` otherwise

**Examples:**

```sql
-- Valid syntax examples
SELECT liquid.check_valid_syntax('Hello {{ name }}!');
-- Returns: true
```

### `liquid.render(liquid_code TEXT, data JSONB) โ†’ TEXT`

Renders a Liquid template with the provided JSON data.

**Parameters:**
- `liquid_code` (TEXT): The Liquid template code to render
- `data` (JSONB): JSON object containing the data to use in template rendering

**Returns:**
- `TEXT`: The rendered template output

**Examples:**

```sql
-- Basic variable substitution
SELECT liquid.render(
  'Hello {{ user.name }}! You have {{ user.credits }} credits.',
  '{
    "user": {
      "name": "Alice",
      "credits": 100
    }
  }'::jsonb
);
-- Returns: "Hello Alice! You have 100 credits."

-- Conditional rendering
SELECT liquid.render(
  '{% if user.is_premium %}Premium user{% else %}Regular user{% endif %}',
  '{"user": {"is_premium": true}}'::jsonb
);
-- Returns: "Premium user"
```

## Liquid Syntax Support

`pg_liquid` supports the complete Liquid syntax.

## Performance

`pg_liquid` is built with performance in mind:

- **Rust Implementation**: Leverages Rust's zero-cost abstractions and memory safety
- **Compiled Templates**: Templates are parsed once and can be cached for repeated use
- **Efficient JSON Handling**: Direct integration with PostgreSQL's JSONB type
- **Memory Safe**: No memory leaks or buffer overflows

### Benchmarks

Real-world performance testing shows excellent throughput for template rendering:

```sql
-- Test: 1 million simple liquid template renders
SELECT count(*) FROM (
    SELECT liquid.render(
        'Hej {{ user.name }}'::text, 
        format('{"user":{"name":"%s"}}', generate_series)::jsonb
    )
    FROM generate_series(1,1000000)
) AS x;

-- Result: 1,000,000 renders in 13.716 seconds
-- Performance: ~73,000 renders per second
-- Per-operation: ~13.7 microseconds per render
```

**Performance Summary:**
- **Throughput**: ~73,000 template renders per second
- **Latency**: ~13.7 microseconds per render operation  
- **Comparison**: ~96x slower than simple `replace()` (expected for full template engine)
- **Use Case**: Excellent for high-throughput applications requiring dynamic content

## Error Handling

The extension handles errors gracefully:

- **Syntax Validation**: Use `check_valid_syntax()` to check templates before rendering
- **Detailed Error Messages**: Clear error messages for debugging template issues
- **Safe Failures**: Invalid templates return errors rather than crashing the database

```sql
-- Validate before rendering
SELECT CASE 
  WHEN liquid.check_valid_syntax('{{ user.name }') THEN
    liquid.render('{{ user.name }', '{"user": {"name": "Alice"}}'::jsonb)
  ELSE
    'Invalid template syntax'
END;
```

## Testing

Run the test suite:

```bash
cargo pgrx test
```

This will run both Rust unit tests and PostgreSQL integration tests.

### Development Setup

1. Get the pg_liquid directory (standalone)
2. Install dependencies: `cargo install cargo-pgrx`
3. Initialize pgrx: `cargo pgrx init`
4. Run tests: `cargo pgrx test`
5. Start development server: `cargo pgrx run`

**Dependencies**: This extension only depends on the published `liquid` crate from crates.io and does not require any local dependencies.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Related Projects

- [liquid-rust]https://github.com/cobalt-org/liquid-rust - The underlying Liquid implementation
- [pgrx]https://github.com/pgcentralfoundation/pgrx - PostgreSQL extension framework
- [Liquid]https://shopify.github.io/liquid/ - The original Liquid template language