-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
Copy pathindex.ts
128 lines (117 loc) · 3.7 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import type { LiveProvider, CrudFilter, CrudFilters } from "@refinedev/core";
import type {
RealtimeChannel,
RealtimePostgresChangesPayload,
SupabaseClient,
} from "@supabase/supabase-js";
import { liveTypes, supabaseTypes } from "../types";
import { mapOperator } from "../utils";
import warnOnce from "warn-once";
const supportedOperators = [
"eq",
"ne",
"lt",
"lte",
"gt",
"gte",
"in",
];
export const liveProvider = (
supabaseClient: SupabaseClient<any, any, any>,
): LiveProvider => {
return {
subscribe: ({
channel,
types,
params,
callback,
meta,
}): RealtimeChannel => {
const resource = channel.replace("resources/", "");
const listener = (payload: RealtimePostgresChangesPayload<any>) => {
if (
types.includes("*") ||
types.includes(liveTypes[payload.eventType])
) {
if (
liveTypes[payload.eventType] !== "created" &&
params?.ids !== undefined &&
payload.new?.id !== undefined
) {
if (params.ids.map(String).includes(payload.new.id.toString())) {
callback({
channel,
type: liveTypes[payload.eventType],
date: new Date(payload.commit_timestamp),
payload: payload.new,
});
}
} else {
callback({
channel,
type: liveTypes[payload.eventType],
date: new Date(payload.commit_timestamp),
payload: payload.new,
});
}
}
};
const mapFilter = (
filters?: CrudFilters,
meta?: any,
): string | undefined => {
if (!filters || filters?.length === 0) {
return;
}
warnOnce(
filters.length > 1 && !meta?.realtimeFilter,
`Warning: Multiple filters detected for resource "${resource}". Supabase Realtime currently supports only a single filter. The first filter will be applied. To customize this behavior, use the 'meta.realtimeFilter' property.`,
);
const effectiveFilter = meta?.realtimeFilter
? [meta.realtimeFilter]
: [filters[0]];
return effectiveFilter
.map((filter: CrudFilter): string | undefined => {
if ("field" in filter) {
if (supportedOperators.includes(filter.operator)) {
return `${filter.field}=${mapOperator(filter.operator)}.${
filter.value
}`;
}
warnOnce(true, `Unsupported filter operator: ${filter.operator}`);
return undefined;
}
return undefined;
})
.filter(Boolean)
.join(",");
};
const events = types
.map((x) => supabaseTypes[x])
.sort((a, b) => a.localeCompare(b));
const filter = mapFilter(params?.filters, meta);
const ch = `${channel}:${events.join("|")}${filter ? `:${filter}` : ""}`;
let client = supabaseClient.channel(ch);
for (let i = 0; i < events.length; i++) {
client = client.on(
"postgres_changes",
{
event: events[i] as any,
schema:
meta?.schema ||
// @ts-expect-error TS2445 Property rest is protected and only accessible within class SupabaseClient and its subclasses.
supabaseClient?.rest?.schemaName ||
"public",
table: resource,
filter: filter,
},
listener,
);
}
return client.subscribe();
},
unsubscribe: async (channel: RealtimeChannel) => {
supabaseClient.removeChannel(channel);
},
};
};