-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathchannel.ts
More file actions
158 lines (126 loc) · 3.91 KB
/
channel.ts
File metadata and controls
158 lines (126 loc) · 3.91 KB
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
interface Root {}
interface Database { _db: any }
interface Collection { _coll: any }
interface Document { _doc: any }
interface TablesDB { _tdb: any }
interface Table { _tbl: any }
interface Row { _row: any }
interface Bucket { _bkt: any }
interface File { _file: any }
interface Func { _fn: any }
interface Execution { _exec: any }
interface Team { _team: any }
interface Membership { _mem: any }
interface Resolved { _res: any }
type Actionable = Document | Row | File | Team | Membership;
function normalize(id: string): string {
if (id === undefined || id === null) {
throw new Error("Channel ID is required");
}
const trimmed = String(id).trim();
if (trimmed === "") {
throw new Error("Channel ID is required");
}
return trimmed;
}
export class Channel<T> {
declare _type: T;
private constructor(private readonly segments: string[]) {}
private next<N>(segment: string, id?: string): Channel<N> {
const segments =
id === undefined
? [...this.segments, segment]
: [...this.segments, segment, normalize(id)];
return new Channel<N>(segments) as any;
}
private resolve(action: string): Channel<Resolved> {
return new Channel<Resolved>([...this.segments, action]) as any;
}
toString(): string {
return this.segments.join(".");
}
// --- DATABASE ROUTE ---
// Only available on Channel<Database>
collection(this: Channel<Database>, id: string): Channel<Collection> {
return this.next<Collection>("collections", id);
}
// Only available on Channel<Collection>
document(this: Channel<Collection>, id?: string): Channel<Document> {
// Default: no document ID segment
return this.next<Document>("documents", id);
}
// --- TABLESDB ROUTE ---
table(this: Channel<TablesDB>, id: string): Channel<Table> {
return this.next<Table>("tables", id);
}
row(this: Channel<Table>, id?: string): Channel<Row> {
// Default: no row ID segment
return this.next<Row>("rows", id);
}
// --- BUCKET ROUTE ---
file(this: Channel<Bucket>, id?: string): Channel<File> {
// Default: no file ID segment
return this.next<File>("files", id);
}
// --- TERMINAL ACTIONS ---
// Restricted to the Actionable union
create(this: Channel<Actionable>): Channel<Resolved> {
return this.resolve("create");
}
upsert(this: Channel<Document | Row>): Channel<Resolved> {
return this.resolve("upsert");
}
update(this: Channel<Actionable>): Channel<Resolved> {
return this.resolve("update");
}
delete(this: Channel<Actionable>): Channel<Resolved> {
return this.resolve("delete");
}
// --- ROOT FACTORIES ---
static database(id: string) {
return new Channel<Database>(["databases", normalize(id)]);
}
static execution(id: string) {
return new Channel<Execution>(["executions", normalize(id)]);
}
static tablesdb(id: string) {
return new Channel<TablesDB>(["tablesdb", normalize(id)]);
}
static bucket(id: string) {
return new Channel<Bucket>(["buckets", normalize(id)]);
}
static function(id: string) {
return new Channel<Func>(["functions", normalize(id)]);
}
static team(id: string) {
return new Channel<Team>(["teams", normalize(id)]);
}
static membership(id: string) {
return new Channel<Membership>(["memberships", normalize(id)]);
}
static account(): string {
return "account";
}
// Global events
static documents(): string {
return "documents";
}
static rows(): string {
return "rows";
}
static files(): string {
return "files";
}
static executions(): string {
return "executions";
}
static teams(): string {
return "teams";
}
static memberships(): string {
return "memberships";
}
}
// Export types for backward compatibility with realtime
export type ActionableChannel = Channel<Document> | Channel<Row> | Channel<File> | Channel<Execution> | Channel<Team> | Channel<Membership>;
export type ResolvedChannel = Channel<Resolved>;