Pglite live extension

In a previous lesson we created the Pglite service that calls Pglite.create from @electric-sql/pglite:

export class Pglite extends Effect.Service<Pglite>()("Pglite", {
  effect: Effect.gen(function* () {
    const indexDb = yield* Config.string("INDEX_DB");

    const client = yield* Effect.tryPromise({
      try: () => _PGlite.PGlite.create(`idb://${indexDb}`),
      catch: (error) => new PgliteError({ cause: error }),
    });

    const orm = drizzle({ client });

    const query = <R>(execute: (_: typeof orm) => Promise<R>) =>
      Effect.tryPromise({
        try: () => execute(orm),
        catch: (error) => new PgliteError({ cause: error }),
      });

    return { client, orm, query };
  }),
}) {}

Pglite supports providing extension to add new features to postgres. One of these is the live extension (from @electric-sql/pglite/live).

Adding an extension only requires providing it inside PGlite.create:

import { live } from "@electric-sql/pglite/live";
// ...

export class Pglite extends Effect.Service<Pglite>()("Pglite", {
  effect: Effect.gen(function* () {
    const indexDb = yield* Config.string("INDEX_DB");

    const client = yield* Effect.tryPromise({
      try: () =>
        _PGlite.PGlite.create(`idb://${indexDb}`, {
          extensions: { live },
        }),
      catch: (error) => new PgliteError({ cause: error }),
    });

    const orm = drizzle({ client });

    const query = <R>(execute: (_: typeof orm) => Promise<R>) =>
      Effect.tryPromise({
        try: () => execute(orm),
        catch: (error) => new PgliteError({ cause: error }),
      });

    return { client, orm, query };
  }),
}) {}

With this the return type of client contains a live: LiveNamespace property. This will be used by pglite to listen for changes and re-execute reactive queries.