Skip to content

Commit

Permalink
Merge pull request #532 from psteinroe/feat/server-adapter
Browse files Browse the repository at this point in the history
feat: add server adapter
  • Loading branch information
psteinroe authored Nov 20, 2024
2 parents 3a1f88d + ec5b1cd commit f7f67b9
Show file tree
Hide file tree
Showing 33 changed files with 1,753 additions and 60 deletions.
8 changes: 8 additions & 0 deletions .changeset/great-kids-rhyme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@supabase-cache-helpers/postgrest-react-query": patch
"@supabase-cache-helpers/storage-react-query": patch
"@supabase-cache-helpers/postgrest-swr": patch
"@supabase-cache-helpers/storage-swr": patch
---

update readme to reflect new server-side package
5 changes: 5 additions & 0 deletions .changeset/soft-trees-crash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@supabase-cache-helpers/postgrest-server": patch
---

initial release
37 changes: 25 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,37 +51,50 @@ jobs:
run: pnpm turbo run test --concurrency=1

- name: Upload postgrest-core coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
files: ./packages/postgrest-core/coverage/coverage-final.json
token: ${{ secrets.CODECOV_TOKEN }}
file: ./packages/postgrest-core/coverage/coverage-final.json
flags: postgrest-core

- name: Upload postgrest-react-query coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
files: ./packages/postgrest-react-query/coverage/coverage-final.json
token: ${{ secrets.CODECOV_TOKEN }}
file: ./packages/postgrest-react-query/coverage/coverage-final.json
flags: postgrest-react-query

- name: Upload postgrest-swr coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
files: ./packages/postgrest-swr/coverage/coverage-final.json
token: ${{ secrets.CODECOV_TOKEN }}
file: ./packages/postgrest-swr/coverage/coverage-final.json
flags: postgrest-swr

- name: Upload storage-core coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
files: ./packages/storage-core/coverage/coverage-final.json
token: ${{ secrets.CODECOV_TOKEN }}
file: ./packages/storage-core/coverage/coverage-final.json
flags: storage-core

- name: Upload storage-swr coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
files: ./packages/storage-swr/coverage/coverage-final.json
token: ${{ secrets.CODECOV_TOKEN }}
file: ./packages/storage-swr/coverage/coverage-final.json
flags: storage-swr

- name: Upload storage-react-query coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
files: ./packages/storage-react-query/coverage/coverage-final.json
token: ${{ secrets.CODECOV_TOKEN }}
file: ./packages/storage-react-query/coverage/coverage-final.json
flags: storage-react-query

- name: Upload postgrest-server coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./packages/postgrest-server/coverage/coverage-final.json
flags: postgrest-server
24 changes: 3 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@

## Introduction

The cache helpers bridge the gap between popular frontend cache management solutions such as [SWR](https://swr.vercel.app) or [React Query](https://tanstack.com/query/latest), and the Supabase client libraries. All features of [`postgrest-js`](https://github.com/supabase/postgrest-js), [`storage-js`](https://github.com/supabase/storage-js) and [`realtime-js`](https://github.com/supabase/realtime-js) are supported. The cache helpers parse any query into a unique and definite query key, and automatically populates your query cache with every mutation using implicit knowledge of the schema. Check out the [demo](https://supabase-cache-helpers-swr.vercel.app) and find out how it feels like for your users.
The cache helpers bridge the gap between popular frontend cache management solutions such as [SWR](https://swr.vercel.app) or [React Query](https://tanstack.com/query/latest), and the Supabase client libraries. All features of [`postgrest-js`](https://github.com/supabase/postgrest-js), [`storage-js`](https://github.com/supabase/storage-js) and [`realtime-js`](https://github.com/supabase/realtime-js) are supported. It also provides a simple server-side abstraction to cache queries to the `PostgREST` API. The cache helpers parse any query into a unique and definite query key, and automatically populates your query cache with every mutation using implicit knowledge of the schema. Check out the [demo](https://supabase-cache-helpers-swr.vercel.app) and find out how it feels like for your users.

## Features

With just one single line of code, you can simplify the logic of **fetching, subscribing to updates, and mutating data as well as storage objects** in your project, and have all the amazing features of [SWR](https://swr.vercel.app) or [React Query](https://tanstack.com/query/latest) out-of-the-box.

- **Seamless** integration with [SWR](https://swr.vercel.app) and [React Query](https://tanstack.com/query/latest)
- Support for **Server-Side** queries
- **Automatic** cache key generation
- Easy **Pagination** and **Infinite Scroll** queries
- **Insert**, **update**, **upsert** and **delete** mutations
Expand All @@ -42,6 +43,7 @@ The cache helpers are split up into reusable libraries.
- [`storage-swr`](./packages/storage-swr/README.md): [SWR](https://swr.vercel.app) wrapper for storage [storage-js](https://github.com/supabase/storage-js)
- [`postgrest-react-query`](./packages/postgrest-react-query/README.md): [React Query](https://tanstack.com/query/latest) wrapper for [postgrest-js](https://github.com/supabase/postgrest-js)
- [`storage-react-query`](./packages/storage-react-query/README.md): [React Query](https://tanstack.com/query/latest) wrapper for storage [storage-js](https://github.com/supabase/storage-js)
- [`postgrest-server`](./packages/postgrest-server/README.md): Server-side caching wrapper for [postgrest-js](https://github.com/supabase/postgrest-js).

### Shared Packages

Expand All @@ -67,25 +69,5 @@ Each package/app is 100% [TypeScript](https://www.typescriptlang.org/).
<br />
(we are <a href="https://twitter.com/psteinroe">hiring</a>!)
</td>
<td align="center">
<a href="https://supabase.com/">
<img src="https://avatars.githubusercontent.com/u/54469796?s=200&v=4" style="width:100px;border-radius:50%" " alt="Supabase" />
</a>
<br />
<b>Supabase</b>
<br />
<a href="https://supabase.com">https://supabase.com</a>
<br />
</td>
<td align="center">
<a href="https://github.com/Marviel">
<img src="https://avatars.githubusercontent.com/u/2037165?v=4" style="width:100px;border-radius:50%" " alt="Marviel" />
</a>
<br />
<b>Luke Bechtel</b>
<br />
<a href="https://github.com/Marviel">@Marviel</a>
<br />
</td>
</tr>
</table>
1 change: 1 addition & 0 deletions docs/pages/postgrest/_meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export default {
subscriptions: 'Subscriptions',
'custom-cache-updates': 'Custom Cache Updates',
ssr: 'Server Side Rendering',
server: 'Server Side Caching',
};
157 changes: 157 additions & 0 deletions docs/pages/postgrest/server.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { Tabs } from 'nextra/components';

# Server-Side Caching

Cache helpers also provides a simple caching abstraction to be used server-side via `@supabase-cache-helpers/postgrest-server`.

## Motivation

At some point, you might want to cache your PostgREST requests on the server-side too. Most users either do not cache at all, or caching might look like this:


```ts
const cache = new Some3rdPartyCache(...)

let contact = await cache.get(contactId) as Tables<"contact"> | undefined | null;
if (!contact){
const { data } = await supabase.from("contact").select("*").eq("id", contactId).throwOnError()
contact = data
await cache.set(contactId, contact, Date.now() + 60_000)
}

// use contact
```

There are a few annoying things about this code:

- Manual type casting
- No support for stale-while-revalidate

Most people would build a small wrapper around this to make it easier to use and so did we: This library is the result of a rewrite of our own caching layer after some developers were starting to replicate it. It’s used in production by Hellomateo any others.

## Features

- **Typescript**: Fully typesafe
- **Tiered Cache**: Multiple caches in series to fall back on
- **Stale-While-Revalidate**: Async loading of data from your origin
- **Deduping**: Prevents multiple requests for the same data from being made at the same time

## Getting Started

Fist, install the dependency:

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
<Tabs.Tab>`npm install @supabase-cache-helpers/postgrest-server`</Tabs.Tab>
<Tabs.Tab>`pnpm add @supabase-cache-helpers/postgrest-server`</Tabs.Tab>
<Tabs.Tab>`yarn add @supabase-cache-helpers/postgrest-server`</Tabs.Tab>
<Tabs.Tab>`bun install @supabase-cache-helpers/postgrest-server`</Tabs.Tab>
</Tabs>

This is how you can make your first cached query:

```ts
import { QueryCache } from '@supabase-cache-helpers/postgrest-server';
import { MemoryStore } from '@supabase-cache-helpers/postgrest-server/stores';
import { createClient } from '@supabase/supabase-js';
import { Database } from './types';

const client = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
);

const map = new Map();

const cache = new QueryCache(ctx, {
stores: [new MemoryStore({ persistentMap: map })],
// Configure the defaults
fresh: 1000,
stale: 2000,
});

const res = await cache.query(
client
.from('contact')
.select('id,username')
.eq('username', contacts[0].username!)
.single(),
// overwrite the default per query
{ fresh: 100, stale : 200 }
);

```

### Context

You may wonder what `ctx` is passed above. In serverless functions it’s not always trivial to run some code after you have returned a response. This is where the context comes in. It allows you to register promises that should be awaited before the function is considered done. Fortunately many providers offer a way to do this.

In order to be used in this cache library, the context must implement the following interface:

```ts
export interface Context {
waitUntil: (p: Promise<unknown>) => void;
}
```

For stateful applications, you can use the `DefaultStatefulContext`:

```ts
import { DefaultStatefulContext } from "@unkey/cache";
const ctx = new DefaultStatefulContext()
```

## Tiered Cache

Different caches have different characteristics, some may be fast but volatile, others may be slow but persistent. By using a tiered cache, you can combine the best of both worlds. In almost every case, you want to use a fast in-memory cache as the first tier. There is no reason not to use it, as it doesn’t add any latency to your application.

The goal of this implementation is that it’s invisible to the user. Everything behaves like a single cache. You can add as many tiers as you want.

### Example

```ts
import { QueryCache } from '@supabase-cache-helpers/postgrest-server';
import { MemoryStore, RedisStore } from '@supabase-cache-helpers/postgrest-server/stores';
import { Redis } from 'ioredis';
import { createClient } from '@supabase/supabase-js';
import { Database } from './types';

const client = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
);

const map = new Map();

const redis = new Redis({...});

const cache = new QueryCache(ctx, {
stores: [new MemoryStore({ persistentMap: map }), new RedisStore({ redis })],
fresh: 1000,
stale: 2000
});

const res = await cache.query(
client
.from('contact')
.select('id,username')
.eq('username', contacts[0].username!)
.single()
);

```


## Stale-While-Revalidate

To make data fetching as easy as possible, the cache offers a swr method, that acts as a pull through cache. If the data is fresh, it will be returned from the cache, if it’s stale it will be returned from the cache and a background refresh will be triggered and if it’s not in the cache, the data will be synchronously fetched from the origin.

```ts
const res = await cache.swr(
client
.from('contact')
.select('id,username')
.eq('username', contacts[0].username!)
.single()
);
```

5 changes: 3 additions & 2 deletions packages/postgrest-react-query/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ A collection of React Query utilities for working with Supabase.
<a href="https://github.com/psteinroe/supabase-cache-helpers/actions/workflows/ci.yml"><img src="https://github.com/psteinroe/supabase-cache-helpers/actions/workflows/ci.yml/badge.svg?branch=main" alt="Latest build" target="\_parent"></a>
<a href="https://github.com/psteinroe/supabase-cache-helpers"><img src="https://img.shields.io/github/stars/psteinroe/supabase-cache-helpers.svg?style=social&amp;label=Star" alt="GitHub Stars" target="\_parent"></a>
[![codecov](https://codecov.io/gh/psteinroe/supabase-cache-helpers/branch/main/graph/badge.svg?token=SPMWSVBRGX)](https://codecov.io/gh/psteinroe/supabase-cache-helpers)

## Introduction

The cache helpers bridge the gap between popular frontend cache management solutions such as [SWR](https://swr.vercel.app) or [React Query](https://tanstack.com/query/latest), and the Supabase client libraries. All features of [`postgrest-js`](https://github.com/supabase/postgrest-js), [`storage-js`](https://github.com/supabase/storage-js) and [`realtime-js`](https://github.com/supabase/realtime-js) are supported. The cache helpers parse any query into a unique and definite query key, and automatically populates your query cache with every mutation using implicit knowledge of the schema. Check out the [demo](https://supabase-cache-helpers-react-query.vercel.app/) and find out how it feels like for your users.
The cache helpers bridge the gap between popular frontend cache management solutions such as [SWR](https://swr.vercel.app) or [React Query](https://tanstack.com/query/latest), and the Supabase client libraries. All features of [`postgrest-js`](https://github.com/supabase/postgrest-js), [`storage-js`](https://github.com/supabase/storage-js) and [`realtime-js`](https://github.com/supabase/realtime-js) are supported. It also provides a simple server-side abstraction to cache queries to the `PostgREST` API. The cache helpers parse any query into a unique and definite query key, and automatically populates your query cache with every mutation using implicit knowledge of the schema. Check out the [demo](https://supabase-cache-helpers-swr.vercel.app) and find out how it feels like for your users.

## Features

With just one single line of code, you can simplify the logic of **fetching, subscribing to updates, and mutating data as well as storage objects** in your project, and have all the amazing features of [SWR](https://swr.vercel.app) or [React Query](https://tanstack.com/query/latest) out-of-the-box.

- **Seamless** integration with [SWR](https://swr.vercel.app) and [React Query](https://tanstack.com/query/latest)
- Support for **Server-Side** queries
- **Automatic** cache key generation
- Easy **Pagination** and **Infinite Scroll** queries
- **Insert**, **update**, **upsert** and **delete** mutations
Expand All @@ -27,3 +27,4 @@ And a lot [more](https://supabase-cache-helpers.vercel.app).
---

**View full documentation and examples on [supabase-cache-helpers.vercel.app](https://supabase-cache-helpers.vercel.app).**

34 changes: 34 additions & 0 deletions packages/postgrest-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# PostgREST Server Cache

A collection of server-side caching utilities for working with Supabase.

<a href="https://github.com/psteinroe/supabase-cache-helpers/actions/workflows/ci.yml"><img src="https://github.com/psteinroe/supabase-cache-helpers/actions/workflows/ci.yml/badge.svg?branch=main" alt="Latest build" target="\_parent"></a>
<a href="https://github.com/psteinroe/supabase-cache-helpers"><img src="https://img.shields.io/github/stars/psteinroe/supabase-cache-helpers.svg?style=social&amp;label=Star" alt="GitHub Stars" target="\_parent"></a>
[![codecov](https://codecov.io/gh/psteinroe/supabase-cache-helpers/branch/main/graph/badge.svg?token=SPMWSVBRGX)](https://codecov.io/gh/psteinroe/supabase-cache-helpers)

## Introduction

The cache helpers bridge the gap between popular frontend cache management solutions such as [SWR](https://swr.vercel.app) or [React Query](https://tanstack.com/query/latest), and the Supabase client libraries. All features of [`postgrest-js`](https://github.com/supabase/postgrest-js), [`storage-js`](https://github.com/supabase/storage-js) and [`realtime-js`](https://github.com/supabase/realtime-js) are supported. It also provides a simple server-side abstraction to cache queries to the `PostgREST` API. The cache helpers parse any query into a unique and definite query key, and automatically populates your query cache with every mutation using implicit knowledge of the schema. Check out the [demo](https://supabase-cache-helpers-swr.vercel.app) and find out how it feels like for your users.

## Features

With just one single line of code, you can simplify the logic of **fetching, subscribing to updates, and mutating data as well as storage objects** in your project, and have all the amazing features of [SWR](https://swr.vercel.app) or [React Query](https://tanstack.com/query/latest) out-of-the-box.

- **Seamless** integration with [SWR](https://swr.vercel.app) and [React Query](https://tanstack.com/query/latest)
- Support for **Server-Side** queries
- **Automatic** cache key generation
- Easy **Pagination** and **Infinite Scroll** queries
- **Insert**, **update**, **upsert** and **delete** mutations
- **Auto-populate** cache after mutations and subscriptions
- **Auto-expand** mutation queries based on existing cache data to keep app up-to-date
- One-liner to upload, download and remove **Supabase Storage** objects

And a lot [more](https://supabase-cache-helpers.vercel.app).

---

**View full documentation and examples on [supabase-cache-helpers.vercel.app](https://supabase-cache-helpers.vercel.app).**

## Acknowledgement

The hard part of this package has been extracted from `@unkey/cache`. If you are on the lookout for a generic typesafe caching solution be sure to check it out.
Loading

0 comments on commit f7f67b9

Please sign in to comment.