From b394803060ead4d5f6b7a2f21d3e0bcc49a16e66 Mon Sep 17 00:00:00 2001 From: Matus Tomlein Date: Wed, 31 Jan 2024 13:33:40 +0100 Subject: [PATCH] Expose event store from emitter controller to be able to remove all events from database (close #834) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #870 --------- Co-authored-by: Daniel GutieĢrrez Ayuso --- .../Core/Emitter/EmitterControllerImpl.swift | 4 ++ .../EmitterControllerIQWrapper.swift | 4 ++ .../InternalQueue/EventStoreIQWrapper.swift | 52 +++++++++++++++++++ .../Controllers/EmitterController.swift | 3 ++ .../TestEmitterConfiguration.swift | 21 ++++++++ 5 files changed, 84 insertions(+) create mode 100644 Sources/Core/InternalQueue/EventStoreIQWrapper.swift diff --git a/Sources/Core/Emitter/EmitterControllerImpl.swift b/Sources/Core/Emitter/EmitterControllerImpl.swift index be9882485..da9414065 100644 --- a/Sources/Core/Emitter/EmitterControllerImpl.swift +++ b/Sources/Core/Emitter/EmitterControllerImpl.swift @@ -132,6 +132,10 @@ class EmitterControllerImpl: Controller, EmitterController { } } + var eventStore: EventStore { + return emitter.eventStore + } + // MARK: - Methods func flush() { diff --git a/Sources/Core/InternalQueue/EmitterControllerIQWrapper.swift b/Sources/Core/InternalQueue/EmitterControllerIQWrapper.swift index 7dc63d1df..06af6ca03 100644 --- a/Sources/Core/InternalQueue/EmitterControllerIQWrapper.swift +++ b/Sources/Core/InternalQueue/EmitterControllerIQWrapper.swift @@ -85,6 +85,10 @@ class EmitterControllerIQWrapper: EmitterController { get { return InternalQueue.sync { controller.maxEventStoreAge } } set { InternalQueue.sync { controller.maxEventStoreAge = newValue } } } + + var eventStore: EventStore { + get { return InternalQueue.sync { EventStoreIQWrapper(eventStore: controller.eventStore) } } + } // MARK: - Methods diff --git a/Sources/Core/InternalQueue/EventStoreIQWrapper.swift b/Sources/Core/InternalQueue/EventStoreIQWrapper.swift new file mode 100644 index 000000000..5a5204e37 --- /dev/null +++ b/Sources/Core/InternalQueue/EventStoreIQWrapper.swift @@ -0,0 +1,52 @@ +// Copyright (c) 2013-present Snowplow Analytics Ltd. All rights reserved. +// +// This program is licensed to you under the Apache License Version 2.0, +// and you may not use this file except in compliance with the Apache License +// Version 2.0. You may obtain a copy of the Apache License Version 2.0 at +// http://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the Apache License Version 2.0 is distributed on +// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the Apache License Version 2.0 for the specific +// language governing permissions and limitations there under. + +import Foundation + +class EventStoreIQWrapper: NSObject, EventStore { + + private let eventStore: EventStore + + init(eventStore: EventStore) { + self.eventStore = eventStore + } + + func addEvent(_ payload: Payload) { + InternalQueue.sync { eventStore.addEvent(payload) } + } + + func removeEvent(withId storeId: Int64) -> Bool { + return InternalQueue.sync { eventStore.removeEvent(withId: storeId) } + } + + func removeEvents(withIds storeIds: [Int64]) -> Bool { + return InternalQueue.sync { eventStore.removeEvents(withIds: storeIds) } + } + + func removeAllEvents() -> Bool { + return InternalQueue.sync { eventStore.removeAllEvents() } + } + + func count() -> UInt { + return InternalQueue.sync { eventStore.count() } + } + + func emittableEvents(withQueryLimit queryLimit: UInt) -> [EmitterEvent] { + return InternalQueue.sync { eventStore.emittableEvents(withQueryLimit: queryLimit) } + } + + func removeOldEvents(maxSize: Int64, maxAge: TimeInterval) { + return InternalQueue.sync { eventStore.removeOldEvents(maxSize: maxSize, maxAge: maxAge) } + } + +} diff --git a/Sources/Snowplow/Controllers/EmitterController.swift b/Sources/Snowplow/Controllers/EmitterController.swift index 70c1ae7c2..f230bef97 100644 --- a/Sources/Snowplow/Controllers/EmitterController.swift +++ b/Sources/Snowplow/Controllers/EmitterController.swift @@ -21,6 +21,9 @@ public protocol EmitterController: EmitterConfigurationProtocol { /// Whether the emitter is currently sending events. @objc var isSending: Bool { get } + /// The EventStore being used by the emitter. + @objc + var eventStore: EventStore { get } @objc func flush() /// Pause emitting events. diff --git a/Tests/Configurations/TestEmitterConfiguration.swift b/Tests/Configurations/TestEmitterConfiguration.swift index 97d0b9864..9cea943f2 100644 --- a/Tests/Configurations/TestEmitterConfiguration.swift +++ b/Tests/Configurations/TestEmitterConfiguration.swift @@ -80,6 +80,27 @@ class TestEmitterConfiguration: XCTestCase { XCTAssertEqual(0, tracker.emitter?.dbCount) } + func testAllowsAccessToTheEventStore() { + let networkConnection = MockNetworkConnection(requestOption: .post, statusCode: 200) + let networkConfig = NetworkConfiguration(networkConnection: networkConnection) + + let tracker = createTracker(networkConfig: networkConfig, emitterConfig: EmitterConfiguration()) + + tracker.emitter?.pause() + for i in 0..<10 { + _ = tracker.track(Structured(category: "cat", action: "act").value(NSNumber(value: i))) + } + Thread.sleep(forTimeInterval: 0.5) + + XCTAssertEqual(10, tracker.emitter?.dbCount) + XCTAssertEqual(10, tracker.emitter?.eventStore.count()) + + XCTAssertTrue(tracker.emitter?.eventStore.removeAllEvents() ?? false) + + XCTAssertEqual(0, tracker.emitter?.dbCount) + XCTAssertEqual(0, tracker.emitter?.eventStore.count()) + } + private func createTracker(networkConfig: NetworkConfiguration, emitterConfig: EmitterConfiguration) -> TrackerController { let trackerConfig = TrackerConfiguration() trackerConfig.installAutotracking = false