Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Modules/Sources/Storage/GRDB/Model/PersistedProduct.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ extension PersistedProduct: FetchableRecord, PersistableRecord {
static let stockQuantity = Column(CodingKeys.stockQuantity)
static let stockStatusKey = Column(CodingKeys.stockStatusKey)
}

public static let images = hasMany(PersistedProductImage.self)
public static let attributes = hasMany(PersistedProductAttribute.self)
}

private extension PersistedProduct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ extension PersistedProductVariation: FetchableRecord, PersistableRecord {
static let stockQuantity = Column(CodingKeys.stockQuantity)
static let stockStatusKey = Column(CodingKeys.stockStatusKey)
}

public static let attributes = hasMany(PersistedProductVariationAttribute.self)
public static let image = hasOne(PersistedProductVariationImage.self)
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Storage

// MARK: - PersistedProduct Conversions
extension PersistedProduct {
public init(from posProduct: POSProduct) {
init(from posProduct: POSProduct) {
self.init(
id: posProduct.productID,
siteID: posProduct.siteID,
Expand All @@ -22,7 +22,7 @@ extension PersistedProduct {
)
}

public func toPOSProduct(images: [ProductImage] = [], attributes: [ProductAttribute] = []) -> POSProduct {
func toPOSProduct(images: [ProductImage] = [], attributes: [ProductAttribute] = []) -> POSProduct {
return POSProduct(
siteID: siteID,
productID: id,
Expand All @@ -42,11 +42,47 @@ extension PersistedProduct {
stockStatusKey: stockStatusKey
)
}

func toPOSProduct(db: GRDBDatabaseConnection) throws -> POSProduct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ what are the use cases for fetching products, then their relationships separately, as this method seems to do? I'd think the products (with some filter) are fetched including the relationships?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think they are – relationships are just foreign keys. If you fetch a record from SQLite, you'll get the id for looking up the relationship, but it won't walk the graph for you. I'll double check that GRDB doesn't do it for us, but I don't think it does.

let images = try db.read { db in
return try request(for: PersistedProduct.images).fetchAll(db)
}
let attributes = try db.read { db in
return try request(for: PersistedProduct.attributes).fetchAll(db)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could these be combined into one database transaction, potentially saving some overhead from each db.read:

Suggested change
let images = try db.read { db in
return try request(for: PersistedProduct.images).fetchAll(db)
}
let attributes = try db.read { db in
return try request(for: PersistedProduct.attributes).fetchAll(db)
}
let (images, attributes) = try db.read { db in
let images = try request(for: PersistedProduct.images).fetchAll(db)
let attributes = try request(for: PersistedProduct.attributes).fetchAll(db)
return (images, attributes)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both done in e3d7b85

return toPOSProduct(
images: images.map { $0.toProductImage() },
attributes: attributes.map { $0.toProductAttribute(siteID: siteID) }
)
}

}

// MARK: - POSProduct Storage Extensions
extension POSProduct {
public func save(to db: GRDBDatabaseConnection) throws {
try db.write { db in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you know if it's recommended to weak self in the db.write closure?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know of a recommendation.

The updates closure that we pass to write is non-escaping, so it can't be stored by GRDB, and we don't hold it beyond our function scope either.

I don't see any reason to make self weak here, at least not to avoid retain cycles.

let product = PersistedProduct(from: self)
try product.insert(db)

// Save related images
for image in self.images {
let persistedImage = PersistedProductImage(from: image, productID: self.productID)
try persistedImage.insert(db)
}

// Save related attributes
for attribute in self.attributes {
var persistedAttribute = PersistedProductAttribute(from: attribute, productID: self.productID)
try persistedAttribute.insert(db)
}
}
}
}

// MARK: - PersistedProductAttribute Conversions
extension PersistedProductAttribute {
public init(from productAttribute: ProductAttribute, productID: Int64) {
init(from productAttribute: ProductAttribute, productID: Int64) {
self.init(
productID: productID,
name: productAttribute.name,
Expand All @@ -57,7 +93,7 @@ extension PersistedProductAttribute {
)
}

public func toProductAttribute(siteID: Int64) -> ProductAttribute {
func toProductAttribute(siteID: Int64) -> ProductAttribute {
return ProductAttribute(
siteID: siteID,
attributeID: 0,
Expand All @@ -72,7 +108,7 @@ extension PersistedProductAttribute {

// MARK: - PersistedProductImage Conversions
extension PersistedProductImage {
public init(from productImage: ProductImage, productID: Int64) {
init(from productImage: ProductImage, productID: Int64) {
self.init(
id: productImage.imageID,
productID: productID,
Expand All @@ -84,7 +120,7 @@ extension PersistedProductImage {
)
}

public func toProductImage() -> ProductImage {
func toProductImage() -> ProductImage {
return ProductImage(
imageID: id,
dateCreated: dateCreated,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Storage

// MARK: - PersistedProductVariation Conversions
extension PersistedProductVariation {
public init(from posProductVariation: POSProductVariation) {
init(from posProductVariation: POSProductVariation) {
self.init(
id: posProductVariation.productVariationID,
siteID: posProductVariation.siteID,
Expand All @@ -19,7 +19,7 @@ extension PersistedProductVariation {
)
}

public func toPOSProductVariation(attributes: [ProductVariationAttribute] = [], image: ProductImage? = nil) -> POSProductVariation {
func toPOSProductVariation(attributes: [ProductVariationAttribute] = [], image: ProductImage? = nil) -> POSProductVariation {
return POSProductVariation(
siteID: siteID,
productID: productID,
Expand All @@ -36,19 +36,55 @@ extension PersistedProductVariation {
stockStatusKey: stockStatusKey
)
}

func toPOSProductVariation(db: GRDBDatabaseConnection) throws -> POSProductVariation {
let image = try db.read { db in
return try request(for: PersistedProductVariation.image).fetchOne(db)
}
let attributes = try db.read { db in
return try request(for: PersistedProductVariation.attributes).fetchAll(db)
}
return toPOSProductVariation(
attributes: attributes.map { $0.toProductVariationAttribute() },
image: image?.toProductImage()
)
}

}

// MARK: - POSProductVariation Storage Extensions
extension POSProductVariation {
public func save(to db: GRDBDatabaseConnection) throws {
try db.write { db in
let variation = PersistedProductVariation(from: self)
try variation.insert(db)

// Save related image if present
if let image = self.image {
let persistedImage = PersistedProductVariationImage(from: image, productVariationID: self.productVariationID)
try persistedImage.insert(db)
}

// Save related attributes
for attribute in self.attributes {
var persistedAttribute = PersistedProductVariationAttribute(from: attribute, productVariationID: self.productVariationID)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could be let?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No – insert is mutating for attributes, because of the autoincremented ID.

try persistedAttribute.insert(db)
}
}
}
}

// MARK: - PersistedProductVariationAttribute Conversions
extension PersistedProductVariationAttribute {
public init(from productVariationAttribute: ProductVariationAttribute, productVariationID: Int64) {
init(from productVariationAttribute: ProductVariationAttribute, productVariationID: Int64) {
self.init(
productVariationID: productVariationID,
name: productVariationAttribute.name,
option: productVariationAttribute.option
)
}

public func toProductVariationAttribute() -> ProductVariationAttribute {
func toProductVariationAttribute() -> ProductVariationAttribute {
return ProductVariationAttribute(
id: id ?? 0,
name: name,
Expand Down