From 820736c910475289d07590f6f4c53080e6e6da93 Mon Sep 17 00:00:00 2001 From: Marina Chemezova Date: Wed, 14 Jan 2026 16:29:26 +0500 Subject: [PATCH 1/3] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=B8=D0=BB=D1=8F=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bricks/source/AnyFailableQuery.swift | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/bricks/source/AnyFailableQuery.swift b/bricks/source/AnyFailableQuery.swift index 8370c05..37dd6c8 100644 --- a/bricks/source/AnyFailableQuery.swift +++ b/bricks/source/AnyFailableQuery.swift @@ -7,25 +7,25 @@ import Foundation -// Type erasing wrapper for FailableQuery -public struct AnyFailableQuery: FailableQuery { - private class _AnyFailableQueryBox: FailableQuery { - func load(completion: @escaping (Swift.Result) -> Void) { - fatalError("This method is abstract") - } - } - - private class _FailableQueryBox: _AnyFailableQueryBox { - private let _base: Base - init(_ base: Base) { - _base = base - } - - override func load(completion: @escaping (Swift.Result) -> Void) { - return _base.load(completion: completion) - } +private class _AnyFailableQueryBox: FailableQuery { + func load(completion: @escaping (Swift.Result) -> Void) { + fatalError("This method is abstract") } +} + +private class _FailableQueryBox: _AnyFailableQueryBox { + private let _base: Base + init(_ base: Base) { + _base = base + } + override func load(completion: @escaping (Swift.Result) -> Void) { + return _base.load(completion: completion) + } +} + +// Type erasing wrapper for FailableQuery +public struct AnyFailableQuery: FailableQuery { private let _box: _AnyFailableQueryBox public init(_ wrappee: Q) where Q: FailableQuery, Q.Success == Success, Q.Failure == Failure { From 049c29e4072f962a79792855fec6a9247a5aa672 Mon Sep 17 00:00:00 2001 From: Marina Chemezova Date: Wed, 14 Jan 2026 16:40:34 +0500 Subject: [PATCH 2/3] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BE=D0=BF=D0=B5=D1=87=D0=B0=D1=82=D0=BA?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bricks/source/InMemoryStorage.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bricks/source/InMemoryStorage.swift b/bricks/source/InMemoryStorage.swift index b7eb5e1..377879c 100644 --- a/bricks/source/InMemoryStorage.swift +++ b/bricks/source/InMemoryStorage.swift @@ -7,7 +7,7 @@ import Foundation -/// In-memory storage simply holds the data passed into `load` method +/// In-memory storage simply holds the data passed into `save` method public final class InMemoryStorage: SynchronousStorage { private var stored: Stored? public private(set) var timestamp: Date? From 515eb1032b41029f4fdc5df005a97374909b173e Mon Sep 17 00:00:00 2001 From: Marina Chemezova Date: Wed, 14 Jan 2026 16:40:52 +0500 Subject: [PATCH 3/3] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=BC=D0=B8=D0=BD=D0=B8=D0=BC=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D0=BE=D0=B5=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 32 ++++++++++++++++++++++++++++++++ bricks.xcodeproj/project.pbxproj | 2 ++ 2 files changed, 34 insertions(+) diff --git a/README.md b/README.md index 9696404..27c143d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,37 @@ # Bricks ![237940157-f9e1d753-fed9-47c8-90b2-abc127e5c7d4](https://github.com/aniramskaya/bricks/assets/108326429/6688c16f-d99a-4f43-9c14-5f0fc5a13e78) +Эта библиотечка состоит из набора сущностей и декораторов (кирпичиков), с помощью которых можно строить различную логику загркзыи и кэширования данных. +В ее основе лежат два протокола: Query и FailableQuery. Остальные компоненты библиотеки реализуют один из них и предоставляют расширения этих протоколов для того чтобы можно было выстраивать сложные сервисы используя непрерывную dot-нотацию +Простой пример: +```swift + static func simpleModelLoader() -> any FailableQuery { + let dto = DTO(value: UUID()) + // Загрузить DTO используя DTOLoader и выполнить маппинг DTO на модель + return DTOLoader(dto: dto).map(with: DTO.toModel) + } +``` +Чуть сложнее: +```swift + static func modelLoaderWithInMemoryCache() -> any FailableQuery { + let dto = DTO(value: UUID()) + + let storage = InMemoryStorage().asQuery() + + // Начинаем с получения данных из кэша в памяти (storage) + return storage + // Применяем к нему политику валидации TimeIntervalValidationPolicy + .expiring(validationPolicy: TimeIntervalValidationPolicy()) + // Если кэш невалиден, запускается вторая ветка + .fallback( + // Загружается DTO + DTOLoader(dto: dto) + // DTO маппится в модель + .map(with: DTO.toModel) + // модель сохраняется в InMemoryStorage + .store(into: storage) + ) + } +``` diff --git a/bricks.xcodeproj/project.pbxproj b/bricks.xcodeproj/project.pbxproj index 4f27846..29ba124 100644 --- a/bricks.xcodeproj/project.pbxproj +++ b/bricks.xcodeproj/project.pbxproj @@ -67,6 +67,7 @@ CC27C14F2A3887E600AF020E /* ParallelPriority.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParallelPriority.swift; sourceTree = ""; }; CC27C1532A38880A00AF020E /* ParallelPriorityLoaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParallelPriorityLoaderTests.swift; sourceTree = ""; }; CC4771462A28BAA2005AAE39 /* PaginatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginatorTests.swift; sourceTree = ""; }; + CC56EACF2F17B3730044956B /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; CC5CB3C82A2E0C4B00DCE080 /* Paginator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Paginator.swift; sourceTree = ""; }; CC5CB3CA2A2E108700DCE080 /* Paginator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Paginator.swift; sourceTree = ""; }; CC7141782A2721A3005DBA5F /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; @@ -140,6 +141,7 @@ CC86FB112A07A40300416227 = { isa = PBXGroup; children = ( + CC56EACF2F17B3730044956B /* README.md */, CC97021B2A417BA000918FC0 /* Bricks.podspec */, CC7431D92A07B568004E0175 /* bricks.xctestplan */, CC86FB1D2A07A40300416227 /* bricks */,