Skip to content

Commit 0c65c0c

Browse files
committed
Enable storing data for multiple sites at once
1 parent c69e785 commit 0c65c0c

13 files changed

+194
-95
lines changed

Modules/Sources/Storage/GRDB/Migrations/V001InitialSchema.swift

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ struct V001InitialSchema {
2929
// not derive them from a Swift class.
3030
// https://swiftpackageindex.com/groue/grdb.swift/v7.6.1/documentation/grdb/migrations#Good-Practices-for-Defining-Migrations
3131
try db.create(table: "product") { productTable in
32-
productTable.primaryKey("id", .integer).notNull()
32+
productTable.column("id", .integer).notNull()
33+
productTable.primaryKey(["siteID", "id"]) // SiteID column created by belongsTo relationship
3334
productTable.belongsTo("site", onDelete: .cascade).notNull()
3435

3536
productTable.column("name", .text).notNull()
@@ -56,7 +57,12 @@ struct V001InitialSchema {
5657
try db.create(table: "productAttribute") { productAttributeTable in
5758
// This table holds local product attributes only. Global attributes belong to a site.
5859
productAttributeTable.autoIncrementedPrimaryKey("id").notNull()
59-
productAttributeTable.belongsTo("product", onDelete: .cascade).notNull()
60+
productAttributeTable.column("siteID", .integer).notNull()
61+
productAttributeTable.column("productID", .integer).notNull()
62+
productAttributeTable.foreignKey(["siteID", "productID"],
63+
references: "product",
64+
columns: ["siteID", "id"],
65+
onDelete: .cascade)
6066

6167
productAttributeTable.column("name", .text).notNull()
6268
productAttributeTable.column("position", .integer).notNull()
@@ -68,8 +74,14 @@ struct V001InitialSchema {
6874

6975
private static func createProductImageTable(_ db: Database) throws {
7076
try db.create(table: "productImage") { productImageTable in
71-
productImageTable.primaryKey("id", .integer).notNull()
72-
productImageTable.belongsTo("product", onDelete: .cascade).notNull()
77+
productImageTable.column("siteID", .integer).notNull()
78+
productImageTable.column("id", .integer).notNull()
79+
productImageTable.primaryKey(["siteID", "id"])
80+
productImageTable.column("productID", .integer).notNull()
81+
productImageTable.foreignKey(["siteID", "productID"],
82+
references: "product",
83+
columns: ["siteID", "id"],
84+
onDelete: .cascade)
7385

7486
productImageTable.column("dateCreated", .datetime).notNull()
7587
productImageTable.column("dateModified", .datetime)
@@ -82,9 +94,14 @@ struct V001InitialSchema {
8294

8395
private static func createProductVariationTable(_ db: Database) throws {
8496
try db.create(table: "productVariation") { productVariationTable in
85-
productVariationTable.primaryKey("id", .integer).notNull()
97+
productVariationTable.column("id", .integer).notNull()
98+
productVariationTable.primaryKey(["siteID", "id"]) // SiteID column created by belongsTo relationship
99+
productVariationTable.column("productID", .integer).notNull()
86100
productVariationTable.belongsTo("site", onDelete: .cascade).notNull()
87-
productVariationTable.belongsTo("product", onDelete: .cascade).notNull()
101+
productVariationTable.foreignKey(["siteID", "productID"],
102+
references: "product",
103+
columns: ["siteID", "id"],
104+
onDelete: .cascade)
88105

89106
productVariationTable.column("sku", .text)
90107
productVariationTable.column("globalUniqueID", .text)
@@ -104,7 +121,12 @@ struct V001InitialSchema {
104121
try db.create(table: "productVariationAttribute") { productVariationAttributeTable in
105122
// This table holds local variation attributes only. Global attributes belong to a site.
106123
productVariationAttributeTable.autoIncrementedPrimaryKey("id").notNull()
107-
productVariationAttributeTable.belongsTo("productVariation", onDelete: .cascade).notNull()
124+
productVariationAttributeTable.column("siteID", .integer).notNull()
125+
productVariationAttributeTable.column("productVariationID", .integer).notNull()
126+
productVariationAttributeTable.foreignKey(["siteID", "productVariationID"],
127+
references: "productVariation",
128+
columns: ["siteID", "id"],
129+
onDelete: .cascade)
108130

109131
productVariationAttributeTable.column("name", .text).notNull()
110132
productVariationAttributeTable.column("option", .text).notNull()
@@ -113,8 +135,14 @@ struct V001InitialSchema {
113135

114136
private static func createProductVariationImageTable(_ db: Database) throws {
115137
try db.create(table: "productVariationImage") { productVariationImageTable in
116-
productVariationImageTable.primaryKey("id", .integer).notNull()
117-
productVariationImageTable.belongsTo("productVariation", onDelete: .cascade).notNull()
138+
productVariationImageTable.column("siteID", .integer).notNull()
139+
productVariationImageTable.column("id", .integer).notNull()
140+
productVariationImageTable.primaryKey(["siteID", "id"])
141+
productVariationImageTable.column("productVariationID", .integer).notNull()
142+
productVariationImageTable.foreignKey(["siteID", "productVariationID"],
143+
references: "productVariation",
144+
columns: ["siteID", "id"],
145+
onDelete: .cascade)
118146

119147
productVariationImageTable.column("dateCreated", .datetime).notNull()
120148
productVariationImageTable.column("dateModified", .datetime)

Modules/Sources/Storage/GRDB/Model/PersistedProduct.swift

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,25 +53,32 @@ public struct PersistedProduct: Codable {
5353
extension PersistedProduct: FetchableRecord, PersistableRecord {
5454
public static var databaseTableName: String { "product" }
5555

56+
public static var primaryKey: [String] { [CodingKeys.siteID.stringValue, CodingKeys.id.stringValue] }
57+
5658
public enum Columns {
57-
static let id = Column(CodingKeys.id)
58-
static let siteID = Column(CodingKeys.siteID)
59-
static let name = Column(CodingKeys.name)
60-
static let productTypeKey = Column(CodingKeys.productTypeKey)
61-
static let fullDescription = Column(CodingKeys.fullDescription)
62-
static let shortDescription = Column(CodingKeys.shortDescription)
63-
static let sku = Column(CodingKeys.sku)
64-
static let globalUniqueID = Column(CodingKeys.globalUniqueID)
65-
static let price = Column(CodingKeys.price)
66-
static let downloadable = Column(CodingKeys.downloadable)
67-
static let parentID = Column(CodingKeys.parentID)
68-
static let manageStock = Column(CodingKeys.manageStock)
69-
static let stockQuantity = Column(CodingKeys.stockQuantity)
70-
static let stockStatusKey = Column(CodingKeys.stockStatusKey)
59+
public static let id = Column(CodingKeys.id)
60+
public static let siteID = Column(CodingKeys.siteID)
61+
public static let name = Column(CodingKeys.name)
62+
public static let productTypeKey = Column(CodingKeys.productTypeKey)
63+
public static let fullDescription = Column(CodingKeys.fullDescription)
64+
public static let shortDescription = Column(CodingKeys.shortDescription)
65+
public static let sku = Column(CodingKeys.sku)
66+
public static let globalUniqueID = Column(CodingKeys.globalUniqueID)
67+
public static let price = Column(CodingKeys.price)
68+
public static let downloadable = Column(CodingKeys.downloadable)
69+
public static let parentID = Column(CodingKeys.parentID)
70+
public static let manageStock = Column(CodingKeys.manageStock)
71+
public static let stockQuantity = Column(CodingKeys.stockQuantity)
72+
public static let stockStatusKey = Column(CodingKeys.stockStatusKey)
7173
}
7274

73-
public static let images = hasMany(PersistedProductImage.self)
74-
public static let attributes = hasMany(PersistedProductAttribute.self)
75+
public static let images = hasMany(PersistedProductImage.self,
76+
using: ForeignKey(PersistedProductImage.primaryKey,
77+
to: primaryKey))
78+
public static let attributes = hasMany(PersistedProductAttribute.self,
79+
using: ForeignKey([PersistedProductAttribute.CodingKeys.siteID.stringValue,
80+
PersistedProductAttribute.CodingKeys.productID.stringValue],
81+
to: primaryKey))
7582
}
7683

7784
// periphery:ignore - TODO: remove ignore when populating database

Modules/Sources/Storage/GRDB/Model/PersistedProductAttribute.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import GRDB
44
// periphery:ignore - TODO: remove ignore when populating database
55
public struct PersistedProductAttribute: Codable {
66
public private(set) var id: Int64?
7+
public let siteID: Int64
78
public let productID: Int64
89
public let name: String
910
public let position: Int64
@@ -12,13 +13,15 @@ public struct PersistedProductAttribute: Codable {
1213
public let options: [String]
1314

1415
public init(id: Int64? = nil,
16+
siteID: Int64,
1517
productID: Int64,
1618
name: String,
1719
position: Int64,
1820
visible: Bool,
1921
variation: Bool,
2022
options: [String]) {
2123
self.id = id
24+
self.siteID = siteID
2225
self.productID = productID
2326
self.name = name
2427
self.position = position
@@ -33,13 +36,14 @@ extension PersistedProductAttribute: FetchableRecord, MutablePersistableRecord {
3336
public static var databaseTableName: String { "productAttribute" }
3437

3538
public enum Columns {
36-
static let id = Column(CodingKeys.id)
39+
public static let id = Column(CodingKeys.id)
40+
public static let siteID = Column(CodingKeys.siteID)
3741
public static let productID = Column(CodingKeys.productID)
38-
static let name = Column(CodingKeys.name)
39-
static let position = Column(CodingKeys.position)
40-
static let visible = Column(CodingKeys.visible)
41-
static let variation = Column(CodingKeys.variation)
42-
static let options = Column(CodingKeys.options)
42+
public static let name = Column(CodingKeys.name)
43+
public static let position = Column(CodingKeys.position)
44+
public static let visible = Column(CodingKeys.visible)
45+
public static let variation = Column(CodingKeys.variation)
46+
public static let options = Column(CodingKeys.options)
4347
}
4448

4549
public mutating func didInsert(_ inserted: InsertionSuccess) {
@@ -49,9 +53,10 @@ extension PersistedProductAttribute: FetchableRecord, MutablePersistableRecord {
4953

5054

5155
// periphery:ignore - TODO: remove ignore when populating database
52-
private extension PersistedProductAttribute {
56+
extension PersistedProductAttribute {
5357
enum CodingKeys: String, CodingKey {
5458
case id
59+
case siteID
5560
case productID
5661
case name
5762
case position

Modules/Sources/Storage/GRDB/Model/PersistedProductImage.swift

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import GRDB
33

44
// periphery:ignore - TODO: remove ignore when populating database
55
public struct PersistedProductImage: Codable {
6+
public let siteID: Int64
67
public let id: Int64
78
public let productID: Int64
89
public let dateCreated: Date
@@ -11,13 +12,15 @@ public struct PersistedProductImage: Codable {
1112
public let name: String?
1213
public let alt: String?
1314

14-
public init(id: Int64,
15+
public init(siteID: Int64,
16+
id: Int64,
1517
productID: Int64,
1618
dateCreated: Date,
1719
dateModified: Date?,
1820
src: String,
1921
name: String?,
2022
alt: String?) {
23+
self.siteID = siteID
2124
self.id = id
2225
self.productID = productID
2326
self.dateCreated = dateCreated
@@ -32,21 +35,25 @@ public struct PersistedProductImage: Codable {
3235
extension PersistedProductImage: FetchableRecord, PersistableRecord {
3336
public static var databaseTableName: String { "productImage" }
3437

38+
public static var primaryKey: [String] { [CodingKeys.siteID.stringValue, CodingKeys.id.stringValue] }
39+
3540
public enum Columns {
36-
static let id = Column(CodingKeys.id)
41+
public static let siteID = Column(CodingKeys.siteID)
42+
public static let id = Column(CodingKeys.id)
3743
public static let productID = Column(CodingKeys.productID)
38-
static let dateCreated = Column(CodingKeys.dateCreated)
39-
static let dateModified = Column(CodingKeys.dateModified)
40-
static let src = Column(CodingKeys.src)
41-
static let name = Column(CodingKeys.name)
42-
static let alt = Column(CodingKeys.alt)
44+
public static let dateCreated = Column(CodingKeys.dateCreated)
45+
public static let dateModified = Column(CodingKeys.dateModified)
46+
public static let src = Column(CodingKeys.src)
47+
public static let name = Column(CodingKeys.name)
48+
public static let alt = Column(CodingKeys.alt)
4349
}
4450
}
4551

4652

4753
// periphery:ignore - TODO: remove ignore when populating database
4854
private extension PersistedProductImage {
4955
enum CodingKeys: String, CodingKey {
56+
case siteID
5057
case id
5158
case productID
5259
case dateCreated

Modules/Sources/Storage/GRDB/Model/PersistedProductVariation.swift

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,29 @@ public struct PersistedProductVariation: Codable {
4444
extension PersistedProductVariation: FetchableRecord, PersistableRecord {
4545
public static var databaseTableName: String { "productVariation" }
4646

47+
public static var primaryKey: [String] { [CodingKeys.siteID.stringValue, CodingKeys.id.stringValue] }
48+
4749
public enum Columns {
48-
static let id = Column(CodingKeys.id)
49-
static let siteID = Column(CodingKeys.siteID)
50-
static let productID = Column(CodingKeys.productID)
51-
static let sku = Column(CodingKeys.sku)
52-
static let globalUniqueID = Column(CodingKeys.globalUniqueID)
53-
static let price = Column(CodingKeys.price)
54-
static let downloadable = Column(CodingKeys.downloadable)
55-
static let fullDescription = Column(CodingKeys.fullDescription)
56-
static let manageStock = Column(CodingKeys.manageStock)
57-
static let stockQuantity = Column(CodingKeys.stockQuantity)
58-
static let stockStatusKey = Column(CodingKeys.stockStatusKey)
50+
public static let id = Column(CodingKeys.id)
51+
public static let siteID = Column(CodingKeys.siteID)
52+
public static let productID = Column(CodingKeys.productID)
53+
public static let sku = Column(CodingKeys.sku)
54+
public static let globalUniqueID = Column(CodingKeys.globalUniqueID)
55+
public static let price = Column(CodingKeys.price)
56+
public static let downloadable = Column(CodingKeys.downloadable)
57+
public static let fullDescription = Column(CodingKeys.fullDescription)
58+
public static let manageStock = Column(CodingKeys.manageStock)
59+
public static let stockQuantity = Column(CodingKeys.stockQuantity)
60+
public static let stockStatusKey = Column(CodingKeys.stockStatusKey)
5961
}
6062

61-
public static let attributes = hasMany(PersistedProductVariationAttribute.self).forKey("attributes")
62-
public static let image = hasOne(PersistedProductVariationImage.self).forKey("image")
63+
public static let attributes = hasMany(PersistedProductVariationAttribute.self,
64+
using: ForeignKey([PersistedProductVariationAttribute.CodingKeys.siteID.stringValue,
65+
PersistedProductVariationAttribute.CodingKeys.productVariationID.stringValue],
66+
to: primaryKey))
67+
public static let image = hasOne(PersistedProductVariationImage.self,
68+
using: ForeignKey(PersistedProductVariationImage.primaryKey,
69+
to: primaryKey))
6370
}
6471

6572

Modules/Sources/Storage/GRDB/Model/PersistedProductVariationAttribute.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@ import GRDB
44
// periphery:ignore - TODO: remove ignore when populating database
55
public struct PersistedProductVariationAttribute: Codable {
66
public private(set) var id: Int64?
7+
public let siteID: Int64
78
public let productVariationID: Int64
89
public let name: String
910
public let option: String
1011

1112
public init(id: Int64? = nil,
13+
siteID: Int64,
1214
productVariationID: Int64,
1315
name: String,
1416
option: String) {
1517
self.id = id
18+
self.siteID = siteID
1619
self.productVariationID = productVariationID
1720
self.name = name
1821
self.option = option
@@ -25,10 +28,11 @@ extension PersistedProductVariationAttribute: FetchableRecord, MutablePersistabl
2528
public static var databaseTableName: String { "productVariationAttribute" }
2629

2730
public enum Columns {
28-
static let id = Column(CodingKeys.id)
31+
public static let id = Column(CodingKeys.id)
32+
public static let siteID = Column(CodingKeys.siteID)
2933
public static let productVariationID = Column(CodingKeys.productVariationID)
30-
static let name = Column(CodingKeys.name)
31-
static let option = Column(CodingKeys.option)
34+
public static let name = Column(CodingKeys.name)
35+
public static let option = Column(CodingKeys.option)
3236
}
3337

3438
public mutating func didInsert(_ inserted: InsertionSuccess) {
@@ -38,9 +42,10 @@ extension PersistedProductVariationAttribute: FetchableRecord, MutablePersistabl
3842

3943

4044
// periphery:ignore - TODO: remove ignore when populating database
41-
private extension PersistedProductVariationAttribute {
45+
extension PersistedProductVariationAttribute {
4246
enum CodingKeys: String, CodingKey {
4347
case id
48+
case siteID
4449
case productVariationID
4550
case name
4651
case option

0 commit comments

Comments
 (0)