Skip to content

feat(realtime): add convenience types for handling broadcast changes #723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Examples/Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
7956406A2955AFBD0088A06F /* ErrorText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 795640692955AFBD0088A06F /* ErrorText.swift */; };
7956406D2955B3500088A06F /* SwiftUINavigation in Frameworks */ = {isa = PBXBuildFile; productRef = 7956406C2955B3500088A06F /* SwiftUINavigation */; };
795640702955B5190088A06F /* IdentifiedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = 7956406F2955B5190088A06F /* IdentifiedCollections */; };
795E90A12DE87AA3009F8C11 /* AsyncAlgorithms in Frameworks */ = {isa = PBXBuildFile; productRef = 795E90A02DE87AA3009F8C11 /* AsyncAlgorithms */; };
796298992AEBBA77000AA957 /* MFAFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796298982AEBBA77000AA957 /* MFAFlow.swift */; };
7962989D2AEBC6F9000AA957 /* SVGView in Frameworks */ = {isa = PBXBuildFile; productRef = 7962989C2AEBC6F9000AA957 /* SVGView */; };
79719ECE2ADF26C400737804 /* Supabase in Frameworks */ = {isa = PBXBuildFile; productRef = 79719ECD2ADF26C400737804 /* Supabase */; };
Expand Down Expand Up @@ -174,6 +175,7 @@
files = (
79D884D92B3C18E90009EA4A /* Supabase in Frameworks */,
79B8F4242B5FED7C0000E839 /* IdentifiedCollections in Frameworks */,
795E90A12DE87AA3009F8C11 /* AsyncAlgorithms in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -397,6 +399,7 @@
packageProductDependencies = (
79D884D82B3C18E90009EA4A /* Supabase */,
79B8F4232B5FED7C0000E839 /* IdentifiedCollections */,
795E90A02DE87AA3009F8C11 /* AsyncAlgorithms */,
);
productName = SlackClone;
productReference = 79D884C72B3C18830009EA4A /* SlackClone.app */;
Expand Down Expand Up @@ -458,6 +461,7 @@
7962989B2AEBC6F9000AA957 /* XCRemoteSwiftPackageReference "SVGView" */,
79E2B5562B97890F0042CD21 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */,
79BE429F2D942EFD00B9DDF4 /* XCRemoteSwiftPackageReference "clerk-ios" */,
795E909F2DE87AA3009F8C11 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */,
);
productRefGroup = 793895C72954ABFF0044F2B8 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -991,6 +995,14 @@
minimumVersion = 1.0.0;
};
};
795E909F2DE87AA3009F8C11 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/apple/swift-async-algorithms.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.0.4;
};
};
7962989B2AEBC6F9000AA957 /* XCRemoteSwiftPackageReference "SVGView" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/exyte/SVGView";
Expand Down Expand Up @@ -1028,6 +1040,11 @@
package = 7956406E2955B5190088A06F /* XCRemoteSwiftPackageReference "swift-identified-collections" */;
productName = IdentifiedCollections;
};
795E90A02DE87AA3009F8C11 /* AsyncAlgorithms */ = {
isa = XCSwiftPackageProductDependency;
package = 795E909F2DE87AA3009F8C11 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */;
productName = AsyncAlgorithms;
};
7962989C2AEBC6F9000AA957 /* SVGView */ = {
isa = XCSwiftPackageProductDependency;
package = 7962989B2AEBC6F9000AA957 /* XCRemoteSwiftPackageReference "SVGView" */;
Expand Down
3 changes: 3 additions & 0 deletions Examples/SlackClone/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["denoland.vscode-deno"]
}
24 changes: 24 additions & 0 deletions Examples/SlackClone/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"deno.enablePaths": [
"supabase/functions"
],
"deno.lint": true,
"deno.unstable": [
"bare-node-builtins",
"byonm",
"sloppy-imports",
"unsafe-proto",
"webgpu",
"broadcast-channel",
"worker-options",
"cron",
"kv",
"ffi",
"fs",
"http",
"net"
],
"[typescript]": {
"editor.defaultFormatter": "denoland.vscode-deno"
}
}
63 changes: 39 additions & 24 deletions Examples/SlackClone/ChannelStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
// Created by Guilherme Souza on 18/01/24.
//

import AsyncAlgorithms
import Foundation
import OSLog
import Supabase

@MainActor
Expand All @@ -22,22 +24,21 @@ final class ChannelStore {
Task {
channels = await fetchChannels()

let channel = supabase.channel("public:channels")
await supabase.realtimeV2.setAuth()

let insertions = channel.postgresChange(InsertAction.self, table: "channels")
let deletions = channel.postgresChange(DeleteAction.self, table: "channels")
let realtimeChannel = supabase.channel("channel:*") {
$0.isPrivate = true
}

await channel.subscribe()
let insertions = realtimeChannel.broadcastStream(event: "INSERT")
let updates = realtimeChannel.broadcastStream(event: "UPDATE")
let deletions = realtimeChannel.broadcastStream(event: "DELETE")

Task {
for await insertion in insertions {
handleInsertedChannel(insertion)
}
}
await realtimeChannel.subscribe()

Task {
for await delete in deletions {
handleDeletedChannel(delete)
for await event in merge(insertions, updates, deletions) {
handleBroadcastEvent(event)
}
}
}
Expand All @@ -52,7 +53,7 @@ final class ChannelStore {
.insert(channel)
.execute()
} catch {
dump(error)
Logger.main.error("Failed to add channel: \(error.localizedDescription)")
toast = .init(status: .error, title: "Error", description: error.localizedDescription)
}
}
Expand All @@ -62,7 +63,8 @@ final class ChannelStore {
return channel
}

let channel: Channel = try await supabase
let channel: Channel =
try await supabase
.from("channels")
.select()
.eq("id", value: id)
Expand All @@ -72,27 +74,40 @@ final class ChannelStore {
return channel
}

private func handleInsertedChannel(_ action: InsertAction) {
private func handleBroadcastEvent(_ event: BroadcastEvent) {
do {
let channel = try action.decodeRecord(decoder: decoder) as Channel
channels.append(channel)
let change = try event.broadcastChange()
switch change.operation {
case .insert(let channel):
channels.append(try channel.decode(decoder: decoder))

case .update(let new, _):
let channel = try new.decode(decoder: decoder) as Channel
if let index = channels.firstIndex(where: { $0.id == channel.id }) {
channels[index] = channel
} else {
Logger.main.warning("Channel with ID \(channel.id) not found for update")
}

case .delete(let old):
guard let id = old["id"]?.intValue else {
Logger.main.error("Missing channel ID in delete operation")
return
}
channels.removeAll { $0.id == id }
messages.removeMessages(for: id)
}
} catch {
dump(error)
Logger.main.error("Failed to handle broadcast event: \(error.localizedDescription)")
toast = .init(status: .error, title: "Error", description: error.localizedDescription)
}
}

private func handleDeletedChannel(_ action: DeleteAction) {
guard let id = action.oldRecord["id"]?.intValue else { return }
channels.removeAll { $0.id == id }
messages.removeMessages(for: id)
}

private func fetchChannels() async -> [Channel] {
do {
return try await supabase.from("channels").select().execute().value
} catch {
dump(error)
Logger.main.error("Failed to fetch channels: \(error.localizedDescription)")
toast = .init(status: .error, title: "Error", description: error.localizedDescription)
return []
}
Expand Down
9 changes: 9 additions & 0 deletions Examples/SlackClone/supabase/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,12 @@
.branches
.temp
.env

# Supabase
.branches
.temp

# dotenvx
.env.keys
.env.local
.env.*.local
Loading
Loading