Skip to content

Commit 94c3625

Browse files
committed
Add database to ServiceLocator
1 parent 9f9b8cc commit 94c3625

File tree

4 files changed

+82
-37
lines changed

4 files changed

+82
-37
lines changed
Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import Foundation
22
import GRDB
33

4-
// TODO: remove ignore when we start using this
5-
// periphery: ignore
6-
public final class GRDBManager {
4+
public protocol GRDBManagerProtocol {
5+
init(databasePath: String) throws
6+
var databaseConnection: GRDBDatabaseConnection { get }
7+
}
8+
9+
public protocol GRDBDatabaseConnection: DatabaseReader & DatabaseWriter {}
710

8-
let databaseQueue: DatabaseQueue
11+
public final class GRDBManager: GRDBManagerProtocol {
12+
13+
public var databaseConnection: GRDBDatabaseConnection
914
private let databasePath: String
1015

1116
public init(databasePath: String) throws {
@@ -16,20 +21,18 @@ public final class GRDBManager {
1621

1722
try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
1823

19-
self.databaseQueue = try DatabaseQueue(path: databasePath)
24+
self.databaseConnection = try DatabaseQueue(path: databasePath)
2025

2126
try migrateIfNeeded()
2227
}
2328

2429
init() throws {
2530
self.databasePath = "in-memory"
26-
self.databaseQueue = try DatabaseQueue()
31+
self.databaseConnection = try DatabaseQueue()
2732
try migrateIfNeeded()
2833
}
2934
}
3035

31-
// TODO: remove ignore when we start using this
32-
// periphery: ignore
3336
private extension GRDBManager {
3437
func migrateIfNeeded() throws {
3538
var migrator = DatabaseMigrator()
@@ -43,6 +46,8 @@ private extension GRDBManager {
4346
try V001InitialSchema.migrate(db)
4447
}
4548

46-
try migrator.migrate(databaseQueue)
49+
try migrator.migrate(databaseConnection)
4750
}
4851
}
52+
53+
extension DatabaseQueue: GRDBDatabaseConnection {}

Modules/Tests/StorageTests/GRDB/GRDBManagerTests.swift

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ struct GRDBManagerTests {
1818
let manager = try GRDBManager()
1919

2020
// When
21-
let tableExists = try manager.databaseQueue.read { db in
21+
let tableExists = try manager.databaseConnection.read { db in
2222
return (
2323
try db.tableExists("site"),
2424
try db.tableExists("product"),
@@ -49,7 +49,7 @@ struct GRDBManagerTests {
4949

5050
init() throws {
5151
self.manager = try GRDBManager()
52-
try manager.databaseQueue.write { db in
52+
try manager.databaseConnection.write { db in
5353
let record = TestSite(id: sampleSiteID)
5454
try record.insert(db)
5555
}
@@ -60,7 +60,7 @@ struct GRDBManagerTests {
6060
// Given
6161

6262
// When
63-
try manager.databaseQueue.write { db in
63+
try manager.databaseConnection.write { db in
6464
let record = TestProduct(
6565
siteID: 1,
6666
id: 100,
@@ -74,7 +74,7 @@ struct GRDBManagerTests {
7474
}
7575

7676
// Then
77-
let productCount = try manager.databaseQueue.read { db in
77+
let productCount = try manager.databaseConnection.read { db in
7878
try TestProduct.fetchCount(db)
7979
}
8080

@@ -84,7 +84,7 @@ struct GRDBManagerTests {
8484
@Test("Insert product variation with a relationship to a product")
8585
func test_after_init_can_insert_productVariation_with_foreign_key() throws {
8686
// Given – parent product
87-
try manager.databaseQueue.write { db in
87+
try manager.databaseConnection.write { db in
8888
let product = TestProduct(
8989
siteID: 1,
9090
id: 100,
@@ -98,7 +98,7 @@ struct GRDBManagerTests {
9898
}
9999

100100
// When - Insert variation
101-
try manager.databaseQueue.write { db in
101+
try manager.databaseConnection.write { db in
102102
let variation = TestProductVariation(
103103
siteID: 1,
104104
id: 200,
@@ -110,7 +110,7 @@ struct GRDBManagerTests {
110110
}
111111

112112
// Then
113-
let variations = try manager.databaseQueue.read { db in
113+
let variations = try manager.databaseConnection.read { db in
114114
try TestProductVariation.fetchAll(db)
115115
}
116116

@@ -121,7 +121,7 @@ struct GRDBManagerTests {
121121
@Test("Fetch variations by product ID")
122122
func test_after_init_and_insert_can_query_productVariation_using_foreign_key() throws {
123123
// Given parent product and some variations
124-
try manager.databaseQueue.write { db in
124+
try manager.databaseConnection.write { db in
125125
// Insert product
126126
let product = TestProduct(
127127
siteID: 1,
@@ -148,7 +148,7 @@ struct GRDBManagerTests {
148148
}
149149

150150
// When
151-
let variations = try manager.databaseQueue.read { db in
151+
let variations = try manager.databaseConnection.read { db in
152152
try TestProductVariation
153153
.filter(Column("productID") == 100)
154154
.fetchAll(db)
@@ -162,7 +162,7 @@ struct GRDBManagerTests {
162162
@Test("Insert product attribute with options array (JSON)")
163163
func test_after_init_can_insert_productAttribute_with_options_as_JSON_array() throws {
164164
// Given parent product
165-
try manager.databaseQueue.write { db in
165+
try manager.databaseConnection.write { db in
166166
// Insert product first
167167
let product = TestProduct(
168168
siteID: 1,
@@ -177,7 +177,7 @@ struct GRDBManagerTests {
177177
}
178178

179179
// When
180-
try manager.databaseQueue.write { db in
180+
try manager.databaseConnection.write { db in
181181
let attribute = TestProductAttribute(
182182
productID: 100,
183183
name: "Color",
@@ -190,7 +190,7 @@ struct GRDBManagerTests {
190190
}
191191

192192
// Then
193-
let attribute = try manager.databaseQueue.read { db in
193+
let attribute = try manager.databaseConnection.read { db in
194194
try TestProductAttribute.fetchOne(db)
195195
}
196196

@@ -201,7 +201,7 @@ struct GRDBManagerTests {
201201
@Test("Insert variation attributes")
202202
func test_after_init_can_insert_variation_attributes() throws {
203203
// Given parent product and variation
204-
try manager.databaseQueue.write { db in
204+
try manager.databaseConnection.write { db in
205205
// Insert product
206206
let product = TestProduct(
207207
siteID: 1,
@@ -226,7 +226,7 @@ struct GRDBManagerTests {
226226
}
227227

228228
// When
229-
try manager.databaseQueue.write { db in
229+
try manager.databaseConnection.write { db in
230230
let variationAttribute = TestProductVariationAttribute(
231231
productVariationID: 200,
232232
name: "Color",
@@ -236,7 +236,7 @@ struct GRDBManagerTests {
236236
}
237237

238238
// Then
239-
let attributes = try manager.databaseQueue.read { db in
239+
let attributes = try manager.databaseConnection.read { db in
240240
try TestProductVariationAttribute.fetchAll(db)
241241
}
242242

@@ -247,14 +247,14 @@ struct GRDBManagerTests {
247247
@Test("Deleting site cascades to all related entities")
248248
func test_deleting_site_cascades_to_all_related_entities() throws {
249249
// Given - Create a separate site for this test to avoid interfering with other tests
250-
let testSiteId = try manager.databaseQueue.write { db -> Int64 in
250+
let testSiteId = try manager.databaseConnection.write { db -> Int64 in
251251
let site = TestSite(id: 999)
252252
try site.insert(db)
253253
return 999
254254
}
255255

256256
// Insert full entity hierarchy
257-
try manager.databaseQueue.write { db in
257+
try manager.databaseConnection.write { db in
258258
let product = TestProduct(
259259
siteID: testSiteId,
260260
id: 100,
@@ -294,7 +294,7 @@ struct GRDBManagerTests {
294294
}
295295

296296
// Verify entities exist for test site
297-
let countsBefore = try manager.databaseQueue.read { db in
297+
let countsBefore = try manager.databaseConnection.read { db in
298298
return (
299299
products: try TestProduct.filter(Column("siteID") == testSiteId).fetchCount(db),
300300
variations: try TestProductVariation.filter(Column("siteID") == testSiteId).fetchCount(db),
@@ -309,12 +309,12 @@ struct GRDBManagerTests {
309309
#expect(countsBefore.variationAttributes == 1)
310310

311311
// When - Delete the site
312-
_ = try manager.databaseQueue.write { db in
312+
_ = try manager.databaseConnection.write { db in
313313
try TestSite.filter(Column("id") == testSiteId).deleteAll(db)
314314
}
315315

316316
// Then - All related entities should be deleted
317-
let countsAfter = try manager.databaseQueue.read { db in
317+
let countsAfter = try manager.databaseConnection.read { db in
318318
return (
319319
sites: try TestSite.filter(Column("id") == testSiteId).fetchCount(db),
320320
products: try TestProduct.filter(Column("siteID") == testSiteId).fetchCount(db),
@@ -334,13 +334,13 @@ struct GRDBManagerTests {
334334
@Test("Fetch products by site")
335335
func test_can_fetch_products_by_site() throws {
336336
// Given - Create second site and products for both sites
337-
let site2Id = try manager.databaseQueue.write { db -> Int64 in
337+
let site2Id = try manager.databaseConnection.write { db -> Int64 in
338338
let site = TestSite(id: 2)
339339
try site.insert(db)
340340
return 2
341341
}
342342

343-
try manager.databaseQueue.write { db in
343+
try manager.databaseConnection.write { db in
344344
// Site 1 products
345345
for i in 1...3 {
346346
let product = TestProduct(
@@ -371,13 +371,13 @@ struct GRDBManagerTests {
371371
}
372372

373373
// When
374-
let site1Products = try manager.databaseQueue.read { db in
374+
let site1Products = try manager.databaseConnection.read { db in
375375
try TestProduct
376376
.filter(Column("siteID") == sampleSiteID)
377377
.fetchAll(db)
378378
}
379379

380-
let site2Products = try manager.databaseQueue.read { db in
380+
let site2Products = try manager.databaseConnection.read { db in
381381
try TestProduct
382382
.filter(Column("siteID") == site2Id)
383383
.fetchAll(db)
@@ -397,7 +397,7 @@ struct GRDBManagerTests {
397397
@Test("Fetch variations by site")
398398
func test_can_fetch_variations_by_site() throws {
399399
// Given - Product and variations
400-
try manager.databaseQueue.write { db in
400+
try manager.databaseConnection.write { db in
401401
let product = TestProduct(
402402
siteID: sampleSiteID,
403403
id: 100,
@@ -422,7 +422,7 @@ struct GRDBManagerTests {
422422
}
423423

424424
// When
425-
let variations = try manager.databaseQueue.read { db in
425+
let variations = try manager.databaseConnection.read { db in
426426
try TestProductVariation
427427
.filter(Column("siteID") == sampleSiteID)
428428
.fetchAll(db)
@@ -438,7 +438,7 @@ struct GRDBManagerTests {
438438
func test_cannot_insert_product_without_valid_site() throws {
439439
// When/Then
440440
#expect(throws: DatabaseError.self) {
441-
try manager.databaseQueue.write { db in
441+
try manager.databaseConnection.write { db in
442442
let product = TestProduct(
443443
siteID: 999, // Non-existent site
444444
id: 100,
@@ -457,7 +457,7 @@ struct GRDBManagerTests {
457457
func test_cannot_insert_variation_without_valid_product() throws {
458458
// When/Then
459459
#expect(throws: DatabaseError.self) {
460-
try manager.databaseQueue.write { db in
460+
try manager.databaseConnection.write { db in
461461
let variation = TestProductVariation(
462462
siteID: sampleSiteID,
463463
id: 200,

WooCommerce/Classes/ServiceLocator/ServiceLocator.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ final class ServiceLocator {
6161
///
6262
private static var _storageManager = CoreDataManager(name: WooConstants.databaseStackName, crashLogger: crashLogging)
6363

64+
/// GRDB Manager for local catalog persistence
65+
///
66+
private static var _grdbManager: GRDBManagerProtocol?
67+
6468
/// Cocoalumberjack DDLog
6569
///
6670
private static var _fileLogger: Logs = DDFileLogger()
@@ -191,6 +195,30 @@ final class ServiceLocator {
191195
return _storageManager
192196
}
193197

198+
/// Provides the access point to the GRDBManager for local catalog persistence.
199+
/// - Returns: An instance of GRDBManagerProtocol when the pointOfSaleLocalCatalogi1 feature flag is enabled
200+
/// - Throws: Fatal error if GRDBManager initialization fails
201+
static var grdbManager: GRDBManagerProtocol {
202+
guard featureFlagService.isFeatureFlagEnabled(.pointOfSaleLocalCatalogi1) else {
203+
fatalError("GRDBManager accessed when pointOfSaleLocalCatalogi1 feature flag is disabled")
204+
}
205+
206+
guard let grdbManager = _grdbManager else {
207+
do {
208+
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
209+
let databasePath = documentsPath.appendingPathComponent(WooConstants.localSQLiteDatabaseName).path
210+
let manager = try GRDBManager(databasePath: databasePath)
211+
DDLogInfo("Started GRDBManager with database path: \(databasePath)")
212+
_grdbManager = manager
213+
return manager
214+
} catch {
215+
fatalError("Failed to initialize GRDBManager: \(error)")
216+
}
217+
}
218+
219+
return grdbManager
220+
}
221+
194222
/// Provides the access point to the FileLogger.
195223
/// - Returns: An implementation of the Logs protocol. It defaults to DDFileLogger
196224
static var fileLogger: Logs {
@@ -417,6 +445,14 @@ extension ServiceLocator {
417445

418446
_productImageUploader = mock
419447
}
448+
449+
static func setGRDBManager(_ testInstance: GRDBManagerProtocol) {
450+
guard isRunningTests() else {
451+
return
452+
}
453+
454+
_grdbManager = testInstance
455+
}
420456
}
421457

422458

WooCommerce/Classes/System/WooConstants.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public enum WooConstants {
1313
///
1414
static let databaseStackName = "WooCommerce"
1515

16+
/// Local SQLite Database Name
17+
///
18+
static let localSQLiteDatabaseName = "woo-local.db"
19+
1620
/// Keychain Access's Service Name
1721
///
1822
public static let keychainServiceName = "com.automattic.woocommerce"

0 commit comments

Comments
 (0)