Skip to content

Commit 99df559

Browse files
authored
Merge pull request #16 from psteinroe/feat/mutation-improvements
feat: insert many, select on mutations and more
2 parents 7c01fad + a2323de commit 99df559

24 files changed

+563
-273
lines changed

.changeset/sixty-pumpkins-add.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@supabase-cache-helpers/postgrest-fetcher": minor
3+
"@supabase-cache-helpers/postgrest-mutate": minor
4+
"@supabase-cache-helpers/postgrest-swr": minor
5+
"@supabase-cache-helpers/postgrest-shared": patch
6+
---
7+
8+
- [BREAKING] Add support for insert many
9+
- Allow defining the select query on mutations
10+
- refactor internal swr mutation functions to prepare for subscriptions
11+
- move mutation fetchers into common postgrest-fetcher lib
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { PostgrestQueryBuilder } from "@supabase/postgrest-js";
2+
import { GetResult } from "@supabase/postgrest-js/dist/module/select-query-parser";
3+
import { GenericTable } from "@supabase/postgrest-js/dist/module/types";
4+
5+
export const buildDeleteFetcher =
6+
<
7+
T extends GenericTable,
8+
Q extends string = "*",
9+
R = GetResult<T["Row"], Q extends "*" ? "*" : Q>
10+
>(
11+
qb: PostgrestQueryBuilder<T>,
12+
primaryKeys: (keyof T["Row"])[],
13+
query?: Q
14+
) =>
15+
async (input: Partial<T["Row"]>) => {
16+
let filterBuilder = qb.delete();
17+
for (const key of primaryKeys) {
18+
const value = input[key];
19+
if (!value)
20+
throw new Error(`Missing value for primary key ${String(key)}`);
21+
filterBuilder = filterBuilder.eq(key as string, value);
22+
}
23+
const { data } = await filterBuilder
24+
.select(query ?? "*")
25+
.throwOnError()
26+
.single();
27+
return data as R;
28+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1+
export * from "./delete";
12
export * from "./fetcher";
3+
export * from "./insert";
24
export * from "./pagination-fetcher";
5+
export * from "./update";
6+
export * from "./upsert";
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { PostgrestQueryBuilder } from "@supabase/postgrest-js";
2+
import { GetResult } from "@supabase/postgrest-js/dist/module/select-query-parser";
3+
import { GenericTable } from "@supabase/postgrest-js/dist/module/types";
4+
5+
export const buildInsertFetcher =
6+
<
7+
T extends GenericTable,
8+
Q extends string = "*",
9+
R = GetResult<T["Row"], Q extends "*" ? "*" : Q>
10+
>(
11+
qb: PostgrestQueryBuilder<T>,
12+
mode: "single" | "multiple",
13+
query?: Q
14+
) =>
15+
async (input: T["Insert"] | T["Insert"][]) => {
16+
if (!Array.isArray(input)) input = [input];
17+
const filterBuilder = qb
18+
.insert(input)
19+
.throwOnError()
20+
.select(query ?? "*");
21+
22+
if (mode === "single") {
23+
const { data } = await filterBuilder.single();
24+
return data as R;
25+
} else {
26+
const { data } = await filterBuilder;
27+
return data as R[];
28+
}
29+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { PostgrestQueryBuilder } from "@supabase/postgrest-js";
2+
import { GetResult } from "@supabase/postgrest-js/dist/module/select-query-parser";
3+
import { GenericTable } from "@supabase/postgrest-js/dist/module/types";
4+
5+
export const buildUpdateFetcher =
6+
<
7+
T extends GenericTable,
8+
Q extends string = "*",
9+
R = GetResult<T["Row"], Q extends "*" ? "*" : Q>
10+
>(
11+
qb: PostgrestQueryBuilder<T>,
12+
primaryKeys: (keyof T["Row"])[],
13+
query?: Q
14+
) =>
15+
async (input: Partial<T["Row"]>) => {
16+
let filterBuilder = qb.update(input);
17+
for (const key of primaryKeys) {
18+
const value = input[key];
19+
if (!value)
20+
throw new Error(`Missing value for primary key ${String(key)}`);
21+
filterBuilder = filterBuilder.eq(key as string, value);
22+
}
23+
const { data } = await filterBuilder
24+
.select(query ?? "*")
25+
.throwOnError()
26+
.single();
27+
28+
return data as R;
29+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { PostgrestQueryBuilder } from "@supabase/postgrest-js";
2+
import { GetResult } from "@supabase/postgrest-js/dist/module/select-query-parser";
3+
import { GenericTable } from "@supabase/postgrest-js/dist/module/types";
4+
5+
export const buildUpsertFetcher =
6+
<
7+
T extends GenericTable,
8+
Q extends string = "*",
9+
R = GetResult<T["Row"], Q extends "*" ? "*" : Q>
10+
>(
11+
qb: PostgrestQueryBuilder<T>,
12+
mode: "single" | "multiple",
13+
query?: Q
14+
) =>
15+
async (input: T["Insert"] | T["Insert"][]) => {
16+
if (!Array.isArray(input)) input = [input];
17+
const filterBuilder = qb
18+
.upsert(input)
19+
.throwOnError()
20+
.select(query ?? "*");
21+
22+
if (mode === "single") {
23+
const { data } = await filterBuilder.single();
24+
return data as R;
25+
} else {
26+
const { data } = await filterBuilder;
27+
return data as R[];
28+
}
29+
};

packages/postgrest-filter/__tests__/postgrest-filter-fn.integration.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@ describe("postgrest-filter-fn", () => {
222222
])("%s", async (name, applyFilterQuery) => {
223223
const q = applyFilterQuery(query);
224224
const { data, error } = await q.single();
225-
console.log(data);
226225
expect(error).toEqual(undefined);
227226
expect(data).toBeTruthy();
228227
expect(

packages/postgrest-mutate/src/upsert.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { isPaginationCacheData } from "@supabase-cache-helpers/postgrest-shared"
55
import { calculateNewCount } from "./lib";
66
import { MutatorFn } from "./types";
77

8-
export const buildUpsertMutator = <Type extends object>(
8+
export const buildUpsertMutator = <Type>(
99
input: Type,
1010
primaryKeys: (keyof Type)[],
1111
hasPathsFilterFn: (input: Type) => boolean

packages/postgrest-shared/src/types.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,22 @@ export const isPaginationCacheData = <Type>(
1616
data: PostgrestCacheData<Type>
1717
): data is PostgrestPaginationCacheData<Type> => Array.isArray(data);
1818

19+
export type RevalidateTableOpt = { schema?: string; table: string };
20+
21+
export type RevalidateRelationOpt<Type> = {
22+
schema?: string;
23+
relation: string;
24+
relationIdColumn: string;
25+
fKeyColumn: keyof Type;
26+
};
1927
export type PostgrestMutatorOpts<Type> = {
2028
/**
2129
* Will set all keys of the tables to stale
2230
*/
23-
revalidateTables?: { schema?: string; table: string }[];
31+
revalidateTables?: RevalidateTableOpt[];
2432
/**
2533
* Will set all keys of the tables where relation.primaryKey === myObj.fKey
2634
*/
27-
revalidateRelations?: {
28-
schema?: string;
29-
relation: string;
30-
relationIdColumn: string;
31-
fKeyColumn: keyof Type;
32-
}[];
35+
revalidateRelations?: RevalidateRelationOpt<Type>[];
3336
schema?: string;
3437
};

packages/postgrest-swr/__tests__/mutate/use-delete-mutation.integration.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe("useDeleteMutation", () => {
3636
revalidateOnReconnect: false,
3737
}
3838
);
39-
const [insert] = useInsertMutation(client.from("contact"));
39+
const [insert] = useInsertMutation(client.from("contact"), "single");
4040
const [deleteContact] = useDeleteMutation(client.from("contact"), ["id"]);
4141
return (
4242
<div>

0 commit comments

Comments
 (0)