Skip to content

Commit

Permalink
Change the value of XXXChange to Change in Document.subscribe (#84)
Browse files Browse the repository at this point in the history
* Allow specifying a topic when subscribing to a document

* Replace Text.onChanges with Document.subscribe

* Change the value of XXXChange to Change in Document.subscribe

* hide TextChange class

* Update TextViewModel.swift

* Update TextViewModel.swift

* Update swift-integration.yml

* add custom docker setup script
  • Loading branch information
humdrum authored Jul 11, 2023
1 parent b6424dc commit 663f0fd
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 60 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/swift-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ jobs:
runs-on: macos-13
steps:
- uses: actions/checkout@v3
- name: Setup Docker on macOS
uses: douglascamata/setup-docker-macos-action@v1-alpha
- name: Setup Docker on macOS using Colima, Lima-VM, and Homebrew.
uses: ./ # Uses an action in the root directory
id: docker
- run: docker-compose -f docker/docker-compose-ci.yml up --build -d
- name: Run tests
run: swift test --enable-code-coverage -v --filter YorkieIntegrationTests
Expand Down
22 changes: 10 additions & 12 deletions Examples/TextEditorApp/TextEditorApp/TextEditor/TextViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,17 @@ class TextViewModel {

var textChanges = [TextOperation]()

event.value.forEach { changeInfo in
changeInfo.operations.forEach {
if let op = $0 as? SelectOpInfo {
let range: NSRange

if op.from <= op.to {
range = NSRange(location: op.from, length: op.to - op.from)
} else {
range = NSRange(location: op.to, length: op.from - op.to)
}

textChanges.append(.select(range: range, actorID: changeInfo.actorID ?? ""))
event.value.operations.forEach {
if let op = $0 as? SelectOpInfo {
let range: NSRange

if op.from <= op.to {
range = NSRange(location: op.from, length: op.to - op.from)
} else {
range = NSRange(location: op.to, length: op.from - op.to)
}

textChanges.append(.select(range: range, actorID: event.value.actorID ?? ""))
}
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/Document/DocEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public struct SnapshotEvent: DocEvent {

protocol ChangeEvent: DocEvent {
var type: DocEventType { get }
var value: [ChangeInfo] { get }
var value: ChangeInfo { get }
}

/**
Expand All @@ -86,7 +86,7 @@ public struct LocalChangeEvent: ChangeEvent {
/**
* LocalChangeEvent type
*/
public var value: [ChangeInfo]
public var value: ChangeInfo
}

/**
Expand All @@ -102,5 +102,5 @@ public struct RemoteChangeEvent: ChangeEvent {
/**
* RemoteChangeEvent type
*/
public var value: [ChangeInfo]
public var value: ChangeInfo
}
40 changes: 16 additions & 24 deletions Sources/Document/Document.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public actor Document {
let changeInfo = ChangeInfo(message: change.message ?? "",
operations: opInfos,
actorID: change.id.getActorID())
let changeEvent = LocalChangeEvent(value: [changeInfo])
let changeEvent = LocalChangeEvent(value: changeInfo)
self.processDocEvent(changeEvent)

Logger.trace("after update a local change: \(self.toJSON())")
Expand Down Expand Up @@ -331,8 +331,9 @@ public actor Document {
self.changeID.syncLamport(with: $0.id.getLamport())
}

let changeEvent = RemoteChangeEvent(value: changeInfos)
self.processDocEvent(changeEvent)
changeInfos.forEach {
self.processDocEvent(RemoteChangeEvent(value: $0))
}

Logger.debug(
"""
Expand Down Expand Up @@ -383,32 +384,23 @@ public actor Document {
private func processDocEvent(_ event: DocEvent) {
if event.type != .snapshot {
if let event = event as? ChangeEvent {
var changeInfos = [String: [ChangeInfo]]()

event.value.forEach { changeInfo in
var operations = [String: [any OperationInfo]]()

changeInfo.operations.forEach { operationInfo in
self.subscribeCallbacks.keys.forEach { targetPath in
if self.isSameElementOrChildOf(operationInfo.path, targetPath) {
if operations[targetPath] == nil {
operations[targetPath] = [any OperationInfo]()
}
operations[targetPath]?.append(operationInfo)
}
}
}
var operations = [String: [any OperationInfo]]()

operations.forEach { key, value in
if changeInfos[key] == nil {
changeInfos[key] = [ChangeInfo]()
event.value.operations.forEach { operationInfo in
self.subscribeCallbacks.keys.forEach { targetPath in
if self.isSameElementOrChildOf(operationInfo.path, targetPath) {
if operations[targetPath] == nil {
operations[targetPath] = [any OperationInfo]()
}
operations[targetPath]?.append(operationInfo)
}
changeInfos[key]?.append(ChangeInfo(message: changeInfo.message, operations: value, actorID: changeInfo.actorID))
}
}

changeInfos.forEach { key, value in
self.subscribeCallbacks[key]?(event.type == .localChange ? LocalChangeEvent(value: value) : RemoteChangeEvent(value: value))
operations.forEach { key, value in
let info = ChangeInfo(message: event.value.message, operations: value, actorID: event.value.actorID)

self.subscribeCallbacks[key]?(event.type == .localChange ? LocalChangeEvent(value: info) : RemoteChangeEvent(value: info))
}
}
} else {
Expand Down
6 changes: 3 additions & 3 deletions Tests/Integration/DocumentIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -387,15 +387,15 @@ final class DocumentIntegrationTests: XCTestCase {
var d3Events = [any OperationInfo]()

await self.d1.subscribe { event in
d1Events.append(contentsOf: (event as? ChangeEvent)?.value[0].operations ?? [])
d1Events.append(contentsOf: (event as? ChangeEvent)?.value.operations ?? [])
}

await self.d1.subscribe(targetPath: "$.todos") { event in
d2Events.append(contentsOf: (event as? ChangeEvent)?.value[0].operations ?? [])
d2Events.append(contentsOf: (event as? ChangeEvent)?.value.operations ?? [])
}

await self.d1.subscribe(targetPath: "$.counter") { event in
d3Events.append(contentsOf: (event as? ChangeEvent)?.value[0].operations ?? [])
d3Events.append(contentsOf: (event as? ChangeEvent)?.value.operations ?? [])
}

try await self.d2.update { root in
Expand Down
12 changes: 6 additions & 6 deletions Tests/Unit/Document/DocumentTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ class DocumentTests: XCTestCase {

await target.subscribe { event in
XCTAssertEqual(event.type, .localChange)
XCTAssertEqual((event as? LocalChangeEvent)?.value[0].operations.compactMap { $0.path }, ["$", "$.", "$..obj", "$..obj", "$..obj", "$..obj", "$."])
XCTAssertEqual((event as? LocalChangeEvent)?.value.operations.compactMap { $0.path }, ["$", "$.", "$..obj", "$..obj", "$..obj", "$..obj", "$."])
}

try await target.update { root in
Expand Down Expand Up @@ -794,7 +794,7 @@ class DocumentTests: XCTestCase {
await target.subscribe { event in
XCTAssertEqual(event.type, .localChange)

if let ops = (event as? LocalChangeEvent)?.value[0].operations {
if let ops = (event as? LocalChangeEvent)?.value.operations {
XCTAssertEqual(ops[0] as! SetOpInfo, SetOpInfo(path: "$", key: "arr"))
XCTAssertEqual(ops[1] as! AddOpInfo, AddOpInfo(path: "$.arr", index: 0))
XCTAssertEqual(ops[2] as! AddOpInfo, AddOpInfo(path: "$.arr", index: 1))
Expand All @@ -809,7 +809,7 @@ class DocumentTests: XCTestCase {
await target.subscribe(targetPath: "$.arr") { event in
XCTAssertEqual(event.type, .localChange)

if let ops = (event as? LocalChangeEvent)?.value[0].operations {
if let ops = (event as? LocalChangeEvent)?.value.operations {
XCTAssertEqual(ops[0] as! AddOpInfo, AddOpInfo(path: "$.arr", index: 0))
XCTAssertEqual(ops[1] as! AddOpInfo, AddOpInfo(path: "$.arr", index: 1))
XCTAssertEqual(ops[2] as! RemoveOpInfo, RemoveOpInfo(path: "$.arr", key: nil, index: 1))
Expand Down Expand Up @@ -841,7 +841,7 @@ class DocumentTests: XCTestCase {
await target.subscribe { event in
XCTAssertEqual(event.type, .localChange)

if let ops = (event as? LocalChangeEvent)?.value[0].operations {
if let ops = (event as? LocalChangeEvent)?.value.operations {
XCTAssertEqual(ops[0] as! SetOpInfo, SetOpInfo(path: "$", key: "cnt"))
XCTAssertEqual(ops[1] as! IncreaseOpInfo, IncreaseOpInfo(path: "$.cnt", value: 1))
XCTAssertEqual(ops[2] as! IncreaseOpInfo, IncreaseOpInfo(path: "$.cnt", value: 10))
Expand All @@ -865,7 +865,7 @@ class DocumentTests: XCTestCase {
await target.subscribe { event in
XCTAssertEqual(event.type, .localChange)

if let ops = (event as? LocalChangeEvent)?.value[0].operations {
if let ops = (event as? LocalChangeEvent)?.value.operations {
XCTAssertEqual(ops[0] as! SetOpInfo, SetOpInfo(path: "$", key: "text"))
XCTAssertEqual(ops[1] as! EditOpInfo, EditOpInfo(path: "$.text", from: 0, to: 0, attributes: nil, content: "hello world"))
XCTAssertEqual(ops[2] as! SelectOpInfo, SelectOpInfo(path: "$.text", from: 11, to: 11))
Expand All @@ -888,7 +888,7 @@ class DocumentTests: XCTestCase {
await target.subscribe { event in
XCTAssertEqual(event.type, .localChange)

if let ops = (event as? LocalChangeEvent)?.value[0].operations {
if let ops = (event as? LocalChangeEvent)?.value.operations {
XCTAssertEqual(ops[0] as! SetOpInfo, SetOpInfo(path: "$", key: "textWithAttr"))
XCTAssertEqual(ops[1] as! EditOpInfo, EditOpInfo(path: "$.textWithAttr", from: 0, to: 0, attributes: nil, content: "hello world"))
XCTAssertEqual(ops[2] as! SelectOpInfo, SelectOpInfo(path: "$.textWithAttr", from: 11, to: 11))
Expand Down
14 changes: 4 additions & 10 deletions Tests/Unit/Document/JSONTextTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,7 @@ final class JSONTextTest: XCTestCase {
try await doc.update { root in root.text = JSONText() }

await doc.subscribe(targetPath: "$.text") {
($0 as! ChangeEvent).value.forEach { changeInfo in
view.applyChanges(operations: changeInfo.operations)
}
view.applyChanges(operations: ($0 as! ChangeEvent).value.operations)
}

let commands: [(from: Int, to: Int, content: String)] = [
Expand All @@ -143,9 +141,7 @@ final class JSONTextTest: XCTestCase {
try await doc.update { root in root.text = JSONText() }

await doc.subscribe(targetPath: "$.text") {
($0 as! ChangeEvent).value.forEach { changeInfo in
view.applyChanges(operations: changeInfo.operations)
}
view.applyChanges(operations: ($0 as! ChangeEvent).value.operations)
}

let commands: [(from: Int, to: Int, content: String)] = [
Expand Down Expand Up @@ -180,9 +176,7 @@ final class JSONTextTest: XCTestCase {
try await doc.update { root in root.text = JSONText() }

await doc.subscribe(targetPath: "$.text") {
($0 as! ChangeEvent).value.forEach { changeInfo in
view.applyChanges(operations: changeInfo.operations)
}
view.applyChanges(operations: ($0 as! ChangeEvent).value.operations)
}

let commands: [(from: Int, to: Int, content: String)] = [
Expand Down Expand Up @@ -216,7 +210,7 @@ final class JSONTextTest: XCTestCase {
}

await doc.subscribe(targetPath: "$.text") { event in
XCTAssertEqual((event as! ChangeEvent).value[0].operations[0] as! SelectOpInfo, SelectOpInfo(path: "$.text", from: 2, to: 4))
XCTAssertEqual((event as! ChangeEvent).value.operations[0] as! SelectOpInfo, SelectOpInfo(path: "$.text", from: 2, to: 4))
}

try await doc.update { root in (root.text as? JSONText)?.select(2, 4) }
Expand Down
68 changes: 68 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: "Setup Docker on macOS"
description: "Setup Docker on macOS using Colima, Lima-VM, and Homebrew."
outputs:
colima-version:
value: ${{ steps.colima-version.outputs.version }}
description: Version of Colima
docker-client-version:
value: ${{ steps.docker-client-version.outputs.version }}
description: Version of the Docker client
docker-compose-version:
value: ${{ steps.docker-compose-version.outputs.version }}
description: Version of Docker Compose
runs:
using: "composite"
steps:
- name: Safety check
if: runner.os != 'macOS'
run: |
echo "Not a macOS runner, exiting."
exit 1
shell: bash
- name: Update Homebrew
run: |
brew update --preinstall
brew_repository="$(brew --repository)"
mkdir -p .github
cat "$brew_repository/Library/Taps/homebrew/homebrew-core/Formula/colima.rb" > .github/brew-colima
cat "$brew_repository/Library/Taps/homebrew/homebrew-core/Formula/docker.rb" > .github/brew-docker
cat "$brew_repository/Library/Taps/homebrew/homebrew-core/Formula/docker-compose.rb" > .github/brew-docker-compose
shell: bash
- name: Install Docker client, Docker Compose, and Colima
env:
HOMEBREW_NO_AUTO_UPDATE: "1"
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: "1"
run: brew install -f docker docker-compose colima
shell: bash
- name: Configure Docker Compose plugin
run: |
mkdir -p ~/.docker/cli-plugins
ln -sfn "$(brew --prefix)/opt/docker-compose/bin/docker-compose" ~/.docker/cli-plugins/docker-compose
shell: bash
- name: Start Colima
run: colima start
shell: bash
- id: docker-client-version
run: |
content="$(docker version)"
content="${content//'%'/'%25'}"
content="${content//$'\n'/'%0A'}"
content="${content//$'\r'/'%0D'}"
echo "::set-output name=version::$content"
shell: bash
- id: docker-compose-version
run: |
content="$(docker compose version)"
content="${content//'%'/'%25'}"
content="${content//$'\n'/'%0A'}"
content="${content//$'\r'/'%0D'}"
echo "::set-output name=version::$content"
shell: bash
- id: colima-version
run: |
content="$(colima version)"
content="${content//'%'/'%25'}"
content="${content//$'\n'/'%0A'}"
content="${content//$'\r'/'%0D'}"
echo "::set-output name=version::$content"
shell: bash

0 comments on commit 663f0fd

Please sign in to comment.