@electric-sql/pglite
Advanced tools
Comparing version 0.2.0-alpha.0 to 0.2.0-alpha.1
@@ -1,2 +0,2 @@ | ||
import{a,b,c,d,e,f}from"./chunk-VGIHPWIO.js";import"./chunk-MAGDP6ZW.js";import"./chunk-TYZHXJCT.js";export{a as Mutex,d as PGlite,e as messages,c as parse,f as protocol,b as types}; | ||
import{a,b,c,d,e,f}from"./chunk-IUK5QO5B.js";import"./chunk-HQE2QCTQ.js";import"./chunk-RZJOGGMK.js";export{a as Mutex,d as PGlite,e as messages,c as parse,f as protocol,b as types}; | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
import{i as e,k as t}from"../chunk-TYZHXJCT.js";t();e();var s=async(r,n)=>({emscriptenOpts:n,bundlePath:new URL("../vector.tar.gz",import.meta.url)}),a={name:"pgvector",setup:s};export{a as vector}; | ||
import{h as e,j as t}from"../chunk-RZJOGGMK.js";t();e();var s=async(r,n)=>({emscriptenOpts:n,bundlePath:new URL("../vector.tar.gz",import.meta.url)}),a={name:"pgvector",setup:s};export{a as vector}; | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
import{b as w,d as g}from"../chunk-UNO2UYXI.js";import{g as P}from"../chunk-MAGDP6ZW.js";import{d as e,e as o,f as d,g as m,i as f,k as h}from"../chunk-TYZHXJCT.js";h();f();var l,c,s,p,r,n,u,T,v=class{constructor(t,i){o(this,u);this.debug=0;o(this,l,!1);o(this,c,!1);o(this,s,void 0);o(this,p,void 0);o(this,r,new Map);o(this,n,new Set);let{dataDir:a,fsType:y}=P(t);this.dataDir=a,this.fsType=y,d(this,p,i??{}),this.debug=i?.debug??0,d(this,s,w(new Worker(new URL("./process.js",import.meta.url),{type:"module"}))),this.waitReady=m(this,u,T).call(this,t)}get ready(){return e(this,l)}get closed(){return e(this,c)}async close(){await e(this,s).close(),d(this,c,!0)}async query(t,i,a){return e(this,s).query(t,i,a)}async exec(t,i){return e(this,s).exec(t,i)}async transaction(t){let i=g(t);return e(this,s).transaction(i)}async execProtocol(t){return e(this,s).execProtocol(t)}async listen(t,i){return e(this,r).has(t)||e(this,r).set(t,new Set),e(this,r).get(t)?.add(i),await this.exec(`LISTEN ${t}`),async()=>{await this.unlisten(t,i)}}async unlisten(t,i){i?e(this,r).get(t)?.delete(i):e(this,r).delete(t),e(this,r).get(t)?.size===0&&await this.exec(`UNLISTEN ${t}`)}onNotification(t){return e(this,n).add(t),()=>{e(this,n).delete(t)}}offNotification(t){e(this,n).delete(t)}receiveNotification(t,i){let a=e(this,r).get(t);if(a)for(let y of a)queueMicrotask(()=>y(i));for(let y of e(this,n))queueMicrotask(()=>y(t,i))}async dumpDataDir(){return e(this,s).dumpDataDir()}};l=new WeakMap,c=new WeakMap,s=new WeakMap,p=new WeakMap,r=new WeakMap,n=new WeakMap,u=new WeakSet,T=async function(t){await e(this,s).init(t,e(this,p),g(this.receiveNotification.bind(this))),d(this,l,!0)};export{v as PGliteWorker}; | ||
import{b as w,d as g}from"../chunk-7ZUVL47R.js";import{g as P}from"../chunk-HQE2QCTQ.js";import{d as e,e as o,f as d,g as m,h as f,j as h}from"../chunk-RZJOGGMK.js";h();f();var l,c,s,p,r,n,u,T,v=class{constructor(t,i){o(this,u);this.debug=0;o(this,l,!1);o(this,c,!1);o(this,s,void 0);o(this,p,void 0);o(this,r,new Map);o(this,n,new Set);let{dataDir:a,fsType:y}=P(t);this.dataDir=a,this.fsType=y,d(this,p,i??{}),this.debug=i?.debug??0,d(this,s,w(new Worker(new URL("./process.js",import.meta.url),{type:"module"}))),this.waitReady=m(this,u,T).call(this,t)}get ready(){return e(this,l)}get closed(){return e(this,c)}async close(){await e(this,s).close(),d(this,c,!0)}async query(t,i,a){return e(this,s).query(t,i,a)}async exec(t,i){return e(this,s).exec(t,i)}async transaction(t){let i=g(t);return e(this,s).transaction(i)}async execProtocol(t){return e(this,s).execProtocol(t)}async listen(t,i){return e(this,r).has(t)||e(this,r).set(t,new Set),e(this,r).get(t)?.add(i),await this.exec(`LISTEN ${t}`),async()=>{await this.unlisten(t,i)}}async unlisten(t,i){i?e(this,r).get(t)?.delete(i):e(this,r).delete(t),e(this,r).get(t)?.size===0&&await this.exec(`UNLISTEN ${t}`)}onNotification(t){return e(this,n).add(t),()=>{e(this,n).delete(t)}}offNotification(t){e(this,n).delete(t)}receiveNotification(t,i){let a=e(this,r).get(t);if(a)for(let y of a)queueMicrotask(()=>y(i));for(let y of e(this,n))queueMicrotask(()=>y(t,i))}async dumpDataDir(){return e(this,s).dumpDataDir()}};l=new WeakMap,c=new WeakMap,s=new WeakMap,p=new WeakMap,r=new WeakMap,n=new WeakMap,u=new WeakSet,T=async function(t){await e(this,s).init(t,e(this,p),g(this.receiveNotification.bind(this))),d(this,l,!0)};export{v as PGliteWorker}; | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
import{d as o}from"../chunk-VGIHPWIO.js";import{a as s,c as y,d as c}from"../chunk-UNO2UYXI.js";import"../chunk-MAGDP6ZW.js";import{i as n,k as i}from"../chunk-TYZHXJCT.js";i();n();var t,p={async init(r,e,a){return t=new o(r,e),await t.waitReady,a&&t.onNotification(a),!0},async close(){await t.close()},async query(r,e,a){return await t.query(r,e,a)},async exec(r,e){return await t.exec(r,e)},async transaction(r){return await t.transaction(e=>r(c(e)))},async execProtocol(r){return await t.execProtocol(r)},async dumpDataDir(){let r=await t.dumpDataDir();return y(r,[await r.arrayBuffer()])}};s(p); | ||
import{d as o}from"../chunk-IUK5QO5B.js";import{a as s,c as y,d as c}from"../chunk-7ZUVL47R.js";import"../chunk-HQE2QCTQ.js";import{h as n,j as i}from"../chunk-RZJOGGMK.js";i();n();var t,p={async init(r,e,a){return t=new o(r,e),await t.waitReady,a&&t.onNotification(a),!0},async close(){await t.close()},async query(r,e,a){return await t.query(r,e,a)},async exec(r,e){return await t.exec(r,e)},async transaction(r){return await t.transaction(e=>r(c(e)))},async execProtocol(r){return await t.execProtocol(r)},async dumpDataDir(){let r=await t.dumpDataDir();return y(r,[await r.arrayBuffer()])}};s(p); | ||
//# sourceMappingURL=process.js.map |
{ | ||
"name": "@electric-sql/pglite", | ||
"version": "0.2.0-alpha.0", | ||
"version": "0.2.0-alpha.1", | ||
"private": false, | ||
@@ -22,2 +22,3 @@ "publishConfig": { | ||
".": "./dist/index.js", | ||
"./live": "./dist/live/index.js", | ||
"./worker": "./dist/worker/index.js", | ||
@@ -54,6 +55,5 @@ "./vector": "./dist/vector/index.js" | ||
"bun": "^1.1.18", | ||
"comlink": "^4.4.1", | ||
"concurrently": "^8.2.2", | ||
"http-server": "^14.1.1", | ||
"pg-protocol": "^1.6.0", | ||
"pg-protocol": "^1.6.1", | ||
"playwright": "^1.42.1", | ||
@@ -60,0 +60,0 @@ "prettier": "3.2.5", |
121
README.md
@@ -362,2 +362,123 @@ <p align="center"> | ||
## Live Queries | ||
The "live" extension enables you to subscribe to a query and receve updated results when the underlying tables change. | ||
To use the extension it needs adding to the PGlite instance when creating it: | ||
```ts | ||
import { PGlite } from "@electric-sql/pglite"; | ||
import { live } from "@electric-sql/pglite/live"; | ||
const pg = new PGlite({ | ||
extensions: { | ||
live, | ||
}, | ||
}); | ||
``` | ||
There are three methods on the `live` namespace: | ||
- `live.query()` for basic live queries. With less machinery in PG it's quicker for small results sets and narrow rows. | ||
- `live.incrementalQuery()` for incremental queries. It materialises the full result set on each update from only the changes emitted by the `live.changes` api. Perfect for feeding into React and good performance for large result sets and wide rows. | ||
- `live.changes()` a lower level API that emits the changes (insert/update/delete) that can then be mapped to mutations in a UI or other datastore. | ||
### live.query<T>() | ||
This is very similar to a standard query, but takes an additional callback that receives the results whenever they change: | ||
```js | ||
const ret = pg.live.query("SELECT * FROM test ORDER BY rand;", [], (res) => { | ||
// res is the same as a standard query result object | ||
}); | ||
``` | ||
The returned value from the call is an object with this interface: | ||
```ts | ||
interface LiveQueryReturn<T> { | ||
initialResults: Results<T>; | ||
unsubscribe: () => Promise<void>; | ||
refresh: () => Promise<void>; | ||
} | ||
``` | ||
- `initialResults` is the initial results set (also sent to the callback | ||
- `unsubscribe` allow you to unsubscribe from the live query | ||
- `refresh` allows you to force a refresh of the query | ||
Internally it watches for the tables that the query depends on, and reruns the query whenever they are changed. | ||
### live.incrementalQuery<T>() | ||
Similar to above, but maintains a temporary table inside of Postgres of the previous state. When the tables it depends on change the query is re-run and diffed with the last state. Only the changes from the last version of the query are copied from WASM into JS. | ||
It requires an additional `key` argument, the name of a column (often a PK) to key the diff on. | ||
```ts | ||
const ret = pg.live.incrementalQuery( | ||
"SELECT * FROM test ORDER BY rand;", [], "id", | ||
(res) => { | ||
// res is the same as a standard query result object | ||
} | ||
); | ||
``` | ||
The returned value is of the same type as the `query` method above. | ||
### live.changes() | ||
A lower level API which is the backend for the `incrementalQuery`, it emits the change that have happened. It requires a `key` to key the diff on: | ||
```ts | ||
const ret = pg.live.changes( | ||
"SELECT * FROM test ORDER BY rand;", [], "id", | ||
(res) => { | ||
// res is a change result object | ||
} | ||
); | ||
``` | ||
the returned value from the call is defined by this interface: | ||
```ts | ||
interface LiveChangesReturn<T = { [key: string]: any }> { | ||
fields: { name: string; dataTypeID: number }[]; | ||
initialChanges: Array<Change<T>>; | ||
unsubscribe: () => Promise<void>; | ||
refresh: () => Promise<void>; | ||
} | ||
``` | ||
The results passed to the callback are array of `Change` objects: | ||
```ts | ||
type ChangeInsert<T> = { | ||
__changed_columns__: string[]; | ||
__op__: "INSERT"; | ||
__after__: number; | ||
} & T; | ||
type ChangeDelete<T> = { | ||
__changed_columns__: string[]; | ||
__op__: "DELETE"; | ||
__after__: undefined; | ||
} & T; | ||
type ChangeUpdate<T> = { | ||
__changed_columns__: string[]; | ||
__op__: "UPDATE"; | ||
__after__: number; | ||
} & T; | ||
type Change<T> = ChangeInsert<T> | ChangeDelete<T> | ChangeUpdate<T>; | ||
``` | ||
Each `Change` includes the new values along with: | ||
- `__changed_columns__` the columns names that were changes | ||
- `__op__` the operation that is required to update the state (`INSERT`, `UPDATE`, `DELETE`) | ||
- `__after__` the `key` of the row that this row should be after, it will be included in `__changed_columns__` if it has been changed. | ||
This API can be used to implement very efficient in-place DOM updates. | ||
## ORM support. | ||
@@ -364,0 +485,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
11690524
16
33
3078
548
3
11