Skip to content

Commit f7f67b9

Browse files
authored
Merge pull request #532 from psteinroe/feat/server-adapter
feat: add server adapter
2 parents 3a1f88d + ec5b1cd commit f7f67b9

33 files changed

+1753
-60
lines changed

.changeset/great-kids-rhyme.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@supabase-cache-helpers/postgrest-react-query": patch
3+
"@supabase-cache-helpers/storage-react-query": patch
4+
"@supabase-cache-helpers/postgrest-swr": patch
5+
"@supabase-cache-helpers/storage-swr": patch
6+
---
7+
8+
update readme to reflect new server-side package

.changeset/soft-trees-crash.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@supabase-cache-helpers/postgrest-server": patch
3+
---
4+
5+
initial release

.github/workflows/ci.yml

+25-12
Original file line numberDiff line numberDiff line change
@@ -51,37 +51,50 @@ jobs:
5151
run: pnpm turbo run test --concurrency=1
5252

5353
- name: Upload postgrest-core coverage
54-
uses: codecov/codecov-action@v4
54+
uses: codecov/codecov-action@v5
5555
with:
56-
files: ./packages/postgrest-core/coverage/coverage-final.json
56+
token: ${{ secrets.CODECOV_TOKEN }}
57+
file: ./packages/postgrest-core/coverage/coverage-final.json
5758
flags: postgrest-core
5859

5960
- name: Upload postgrest-react-query coverage
60-
uses: codecov/codecov-action@v4
61+
uses: codecov/codecov-action@v5
6162
with:
62-
files: ./packages/postgrest-react-query/coverage/coverage-final.json
63+
token: ${{ secrets.CODECOV_TOKEN }}
64+
file: ./packages/postgrest-react-query/coverage/coverage-final.json
6365
flags: postgrest-react-query
6466

6567
- name: Upload postgrest-swr coverage
66-
uses: codecov/codecov-action@v4
68+
uses: codecov/codecov-action@v5
6769
with:
68-
files: ./packages/postgrest-swr/coverage/coverage-final.json
70+
token: ${{ secrets.CODECOV_TOKEN }}
71+
file: ./packages/postgrest-swr/coverage/coverage-final.json
6972
flags: postgrest-swr
7073

7174
- name: Upload storage-core coverage
72-
uses: codecov/codecov-action@v4
75+
uses: codecov/codecov-action@v5
7376
with:
74-
files: ./packages/storage-core/coverage/coverage-final.json
77+
token: ${{ secrets.CODECOV_TOKEN }}
78+
file: ./packages/storage-core/coverage/coverage-final.json
7579
flags: storage-core
7680

7781
- name: Upload storage-swr coverage
78-
uses: codecov/codecov-action@v4
82+
uses: codecov/codecov-action@v5
7983
with:
80-
files: ./packages/storage-swr/coverage/coverage-final.json
84+
token: ${{ secrets.CODECOV_TOKEN }}
85+
file: ./packages/storage-swr/coverage/coverage-final.json
8186
flags: storage-swr
8287

8388
- name: Upload storage-react-query coverage
84-
uses: codecov/codecov-action@v4
89+
uses: codecov/codecov-action@v5
8590
with:
86-
files: ./packages/storage-react-query/coverage/coverage-final.json
91+
token: ${{ secrets.CODECOV_TOKEN }}
92+
file: ./packages/storage-react-query/coverage/coverage-final.json
8793
flags: storage-react-query
94+
95+
- name: Upload postgrest-server coverage
96+
uses: codecov/codecov-action@v5
97+
with:
98+
token: ${{ secrets.CODECOV_TOKEN }}
99+
file: ./packages/postgrest-server/coverage/coverage-final.json
100+
flags: postgrest-server

README.md

+3-21
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010

1111
## Introduction
1212

13-
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.
13+
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.
1414

1515
## Features
1616

1717
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.
1818

1919
- **Seamless** integration with [SWR](https://swr.vercel.app) and [React Query](https://tanstack.com/query/latest)
20+
- Support for **Server-Side** queries
2021
- **Automatic** cache key generation
2122
- Easy **Pagination** and **Infinite Scroll** queries
2223
- **Insert**, **update**, **upsert** and **delete** mutations
@@ -42,6 +43,7 @@ The cache helpers are split up into reusable libraries.
4243
- [`storage-swr`](./packages/storage-swr/README.md): [SWR](https://swr.vercel.app) wrapper for storage [storage-js](https://github.com/supabase/storage-js)
4344
- [`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)
4445
- [`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)
46+
- [`postgrest-server`](./packages/postgrest-server/README.md): Server-side caching wrapper for [postgrest-js](https://github.com/supabase/postgrest-js).
4547

4648
### Shared Packages
4749

@@ -67,25 +69,5 @@ Each package/app is 100% [TypeScript](https://www.typescriptlang.org/).
6769
<br />
6870
(we are <a href="https://twitter.com/psteinroe">hiring</a>!)
6971
</td>
70-
<td align="center">
71-
<a href="https://supabase.com/">
72-
<img src="https://avatars.githubusercontent.com/u/54469796?s=200&v=4" style="width:100px;border-radius:50%" " alt="Supabase" />
73-
</a>
74-
<br />
75-
<b>Supabase</b>
76-
<br />
77-
<a href="https://supabase.com">https://supabase.com</a>
78-
<br />
79-
</td>
80-
<td align="center">
81-
<a href="https://github.com/Marviel">
82-
<img src="https://avatars.githubusercontent.com/u/2037165?v=4" style="width:100px;border-radius:50%" " alt="Marviel" />
83-
</a>
84-
<br />
85-
<b>Luke Bechtel</b>
86-
<br />
87-
<a href="https://github.com/Marviel">@Marviel</a>
88-
<br />
89-
</td>
9072
</tr>
9173
</table>

docs/pages/postgrest/_meta.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ export default {
55
subscriptions: 'Subscriptions',
66
'custom-cache-updates': 'Custom Cache Updates',
77
ssr: 'Server Side Rendering',
8+
server: 'Server Side Caching',
89
};

docs/pages/postgrest/server.mdx

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import { Tabs } from 'nextra/components';
2+
3+
# Server-Side Caching
4+
5+
Cache helpers also provides a simple caching abstraction to be used server-side via `@supabase-cache-helpers/postgrest-server`.
6+
7+
## Motivation
8+
9+
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:
10+
11+
12+
```ts
13+
const cache = new Some3rdPartyCache(...)
14+
15+
let contact = await cache.get(contactId) as Tables<"contact"> | undefined | null;
16+
if (!contact){
17+
const { data } = await supabase.from("contact").select("*").eq("id", contactId).throwOnError()
18+
contact = data
19+
await cache.set(contactId, contact, Date.now() + 60_000)
20+
}
21+
22+
// use contact
23+
```
24+
25+
There are a few annoying things about this code:
26+
27+
- Manual type casting
28+
- No support for stale-while-revalidate
29+
30+
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.
31+
32+
## Features
33+
34+
- **Typescript**: Fully typesafe
35+
- **Tiered Cache**: Multiple caches in series to fall back on
36+
- **Stale-While-Revalidate**: Async loading of data from your origin
37+
- **Deduping**: Prevents multiple requests for the same data from being made at the same time
38+
39+
## Getting Started
40+
41+
Fist, install the dependency:
42+
43+
<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
44+
<Tabs.Tab>`npm install @supabase-cache-helpers/postgrest-server`</Tabs.Tab>
45+
<Tabs.Tab>`pnpm add @supabase-cache-helpers/postgrest-server`</Tabs.Tab>
46+
<Tabs.Tab>`yarn add @supabase-cache-helpers/postgrest-server`</Tabs.Tab>
47+
<Tabs.Tab>`bun install @supabase-cache-helpers/postgrest-server`</Tabs.Tab>
48+
</Tabs>
49+
50+
This is how you can make your first cached query:
51+
52+
```ts
53+
import { QueryCache } from '@supabase-cache-helpers/postgrest-server';
54+
import { MemoryStore } from '@supabase-cache-helpers/postgrest-server/stores';
55+
import { createClient } from '@supabase/supabase-js';
56+
import { Database } from './types';
57+
58+
const client = createClient<Database>(
59+
process.env.SUPABASE_URL,
60+
process.env.SUPABASE_ANON_KEY
61+
);
62+
63+
const map = new Map();
64+
65+
const cache = new QueryCache(ctx, {
66+
stores: [new MemoryStore({ persistentMap: map })],
67+
// Configure the defaults
68+
fresh: 1000,
69+
stale: 2000,
70+
});
71+
72+
const res = await cache.query(
73+
client
74+
.from('contact')
75+
.select('id,username')
76+
.eq('username', contacts[0].username!)
77+
.single(),
78+
// overwrite the default per query
79+
{ fresh: 100, stale : 200 }
80+
);
81+
82+
```
83+
84+
### Context
85+
86+
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.
87+
88+
In order to be used in this cache library, the context must implement the following interface:
89+
90+
```ts
91+
export interface Context {
92+
waitUntil: (p: Promise<unknown>) => void;
93+
}
94+
```
95+
96+
For stateful applications, you can use the `DefaultStatefulContext`:
97+
98+
```ts
99+
import { DefaultStatefulContext } from "@unkey/cache";
100+
const ctx = new DefaultStatefulContext()
101+
```
102+
103+
## Tiered Cache
104+
105+
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.
106+
107+
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.
108+
109+
### Example
110+
111+
```ts
112+
import { QueryCache } from '@supabase-cache-helpers/postgrest-server';
113+
import { MemoryStore, RedisStore } from '@supabase-cache-helpers/postgrest-server/stores';
114+
import { Redis } from 'ioredis';
115+
import { createClient } from '@supabase/supabase-js';
116+
import { Database } from './types';
117+
118+
const client = createClient<Database>(
119+
process.env.SUPABASE_URL,
120+
process.env.SUPABASE_ANON_KEY
121+
);
122+
123+
const map = new Map();
124+
125+
const redis = new Redis({...});
126+
127+
const cache = new QueryCache(ctx, {
128+
stores: [new MemoryStore({ persistentMap: map }), new RedisStore({ redis })],
129+
fresh: 1000,
130+
stale: 2000
131+
});
132+
133+
const res = await cache.query(
134+
client
135+
.from('contact')
136+
.select('id,username')
137+
.eq('username', contacts[0].username!)
138+
.single()
139+
);
140+
141+
```
142+
143+
144+
## Stale-While-Revalidate
145+
146+
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.
147+
148+
```ts
149+
const res = await cache.swr(
150+
client
151+
.from('contact')
152+
.select('id,username')
153+
.eq('username', contacts[0].username!)
154+
.single()
155+
);
156+
```
157+

packages/postgrest-react-query/README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ A collection of React Query utilities for working with Supabase.
55
<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>
66
<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>
77
[![codecov](https://codecov.io/gh/psteinroe/supabase-cache-helpers/branch/main/graph/badge.svg?token=SPMWSVBRGX)](https://codecov.io/gh/psteinroe/supabase-cache-helpers)
8-
98
## Introduction
109

11-
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.
10+
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.
1211

1312
## Features
1413

1514
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.
1615

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

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

packages/postgrest-server/README.md

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# PostgREST Server Cache
2+
3+
A collection of server-side caching utilities for working with Supabase.
4+
5+
<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>
6+
<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>
7+
[![codecov](https://codecov.io/gh/psteinroe/supabase-cache-helpers/branch/main/graph/badge.svg?token=SPMWSVBRGX)](https://codecov.io/gh/psteinroe/supabase-cache-helpers)
8+
9+
## Introduction
10+
11+
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.
12+
13+
## Features
14+
15+
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.
16+
17+
- **Seamless** integration with [SWR](https://swr.vercel.app) and [React Query](https://tanstack.com/query/latest)
18+
- Support for **Server-Side** queries
19+
- **Automatic** cache key generation
20+
- Easy **Pagination** and **Infinite Scroll** queries
21+
- **Insert**, **update**, **upsert** and **delete** mutations
22+
- **Auto-populate** cache after mutations and subscriptions
23+
- **Auto-expand** mutation queries based on existing cache data to keep app up-to-date
24+
- One-liner to upload, download and remove **Supabase Storage** objects
25+
26+
And a lot [more](https://supabase-cache-helpers.vercel.app).
27+
28+
---
29+
30+
**View full documentation and examples on [supabase-cache-helpers.vercel.app](https://supabase-cache-helpers.vercel.app).**
31+
32+
## Acknowledgement
33+
34+
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.

0 commit comments

Comments
 (0)