Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/silver-age-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@electric-sql/pglite": patch
---

Add Apache AGE graph database extension support
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "postgres-pglite"]
path = postgres-pglite
url = ../postgres-pglite.git
url = https://github.com/jpabbuehl/postgres-pglite.git
59 changes: 59 additions & 0 deletions docs/extensions/age.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Apache AGE Extension

[Apache AGE](https://age.apache.org/) (A Graph Extension) brings graph database capabilities to PostgreSQL, allowing you to use the Cypher query language alongside standard SQL.

## Installation

The AGE extension is included with PGlite. To use it:

```typescript
import { PGlite } from '@electric-sql/pglite'
import { age } from '@electric-sql/pglite/age'

const pg = new PGlite({
extensions: {
age,
},
})
```

## Important Notes

### Schema Qualification

All AGE functions are in the `ag_catalog` schema. The extension does not implicitly update the search path for safety. You must either manually set the `search_path` to include `ag_catalog` for your connection, or use fully-qualified names:

```typescript
// Explicit qualification:
await pg.exec("SELECT ag_catalog.create_graph('g');")

// Setting the search path for the session:
await pg.exec('SET search_path = ag_catalog, "$user", public;')
await pg.exec("SELECT create_graph('g');")
```

### Column Definitions

Cypher queries require column definitions in the `as` clause to map the dynamic graph types back to standard PostgreSQL relations:

```typescript
// Single column
SELECT * FROM ag_catalog.cypher('g', $$ RETURN 1 $$) as (v ag_catalog.agtype);

// Multiple columns
SELECT * FROM ag_catalog.cypher('g', $$
MATCH (n) RETURN n.name, n.age
$$) as (name ag_catalog.agtype, age ag_catalog.agtype);
```

## Limitations

- **File operations**: `load_labels_from_file()` is not available (no filesystem access in WASM)
- **Memory**: Large graphs may hit WebAssembly memory limits
- **Performance**: Graph operations are CPU-intensive; consider pagination for large result sets

## Resources

- [Apache AGE Documentation](https://age.apache.org/age-manual/master/index.html)
- [Cypher Query Language](https://neo4j.com/docs/cypher-manual/current/)
- [AGE GitHub Repository](https://github.com/apache/age)
10 changes: 10 additions & 0 deletions packages/pglite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@
"default": "./dist/pg_uuidv7/index.cjs"
}
},
"./age": {
"import": {
"types": "./dist/age/index.d.ts",
"default": "./dist/age/index.js"
},
"require": {
"types": "./dist/age/index.d.cts",
"default": "./dist/age/index.cjs"
}
},
"./nodefs": {
"import": {
"types": "./dist/fs/nodefs.d.ts",
Expand Down
4 changes: 4 additions & 0 deletions packages/pglite/scripts/bundle-wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ async function main() {
'.js',
'.cjs',
])
await findAndReplaceInDir('./dist/age', /\.\.\/release\//g, '', [
'.js',
'.cjs',
])
await findAndReplaceInDir(
'./dist',
`require("./postgres.js")`,
Expand Down
17 changes: 17 additions & 0 deletions packages/pglite/src/age/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type {
Extension,
ExtensionSetupResult,
PGliteInterface,
} from '../interface'

const setup = async (_pg: PGliteInterface, emscriptenOpts: any) => {
return {
emscriptenOpts,
bundlePath: new URL('../../release/age.tar.gz', import.meta.url),
} satisfies ExtensionSetupResult
}

export const age = {
name: 'age',
setup,
} satisfies Extension
Loading