Skip to content

Commit

Permalink
Fully key MHolding (like MTransaction) to better ensure unique ids #6
Browse files Browse the repository at this point in the history
  • Loading branch information
Reed Es committed Mar 9, 2022
1 parent 3404873 commit 8b9cdaa
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 15 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ ticker, share count, share basis, etc.
| holdingAccountID | string | true | true | The account hosting the position. |
| holdingSecurityID | string | true | true | The security of the position. |
| holdingLotID | string | true | true | The lot of the position, if any. |
| shareCount | double | false | false | The number of shares held in the position. |
| shareBasis | double | false | false | The price paid per share of the security. |
| acquiredAt | date | false | false | The date of the acquisition. |
| shareCount | double | false | true | The number of shares held in the position. |
| shareBasis | double | false | true | The price paid per share of the security. |
| acquiredAt | date | false | true | The date of the acquisition. |

### MSecurity

Expand Down Expand Up @@ -319,6 +319,8 @@ public protocol AllocAttributable {
Swift open-source libraries (by the same author):

* [FINporter](https://github.com/openalloc/FINporter) - library and command-line tool to transform various specialized finance-related formats to the standardized schema of AllocData
* [SwiftTabler](https://github.com/openalloc/SwiftTabler) - multi-platform SwiftUI component for displaying (and interacting with) tabular data
* [SwiftDetailer](https://github.com/openalloc/SwiftDetailer) - multi-platform SwiftUI component for editing fielded data
* [SwiftCompactor](https://github.com/openalloc/SwiftCompactor) - formatters for the concise display of Numbers, Currency, and Time Intervals
* [SwiftModifiedDietz](https://github.com/openalloc/SwiftModifiedDietz) - A tool for calculating portfolio performance using the Modified Dietz method
* [SwiftNiceScale](https://github.com/openalloc/SwiftNiceScale) - generate 'nice' numbers for label ticks over a range, such as for y-axis on a chart
Expand Down
6 changes: 3 additions & 3 deletions Sources/Model/Holding/MHolding+Attributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ extension MHolding: AllocAttributable {
AllocAttribute(CodingKeys.accountID, .string, isRequired: true, isKey: true, "The account hosting the position."),
AllocAttribute(CodingKeys.securityID, .string, isRequired: true, isKey: true, "The security of the position."),
AllocAttribute(CodingKeys.lotID, .string, isRequired: true, isKey: true, "The lot of the position, if any."),
AllocAttribute(CodingKeys.shareCount, .double, isRequired: false, isKey: false, "The number of shares held in the position."),
AllocAttribute(CodingKeys.shareBasis, .double, isRequired: false, isKey: false, "The price paid per share of the security."),
AllocAttribute(CodingKeys.acquiredAt, .date, isRequired: false, isKey: false, "The date of the acquisition."),
AllocAttribute(CodingKeys.shareCount, .double, isRequired: false, isKey: true, "The number of shares held in the position."),
AllocAttribute(CodingKeys.shareBasis, .double, isRequired: false, isKey: true, "The price paid per share of the security."),
AllocAttribute(CodingKeys.acquiredAt, .date, isRequired: false, isKey: true, "The date of the acquisition."),
]
}
20 changes: 17 additions & 3 deletions Sources/Model/Holding/MHolding+Key.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,31 @@ extension MHolding: AllocKeyed {
public let accountNormID: NormalizedID
public let securityNormID: NormalizedID
public let lotNormID: NormalizedID
public var shareCount: Double?
public var shareBasis: Double?
public var acquiredAt: Date?

public init(accountID: String, securityID: String, lotID: String) {
public init(accountID: String,
securityID: String,
lotID: String,
shareCount: Double? = nil,
shareBasis: Double? = nil,
acquiredAt: Date? = nil) {
self.accountNormID = MHolding.normalizeID(accountID)
self.securityNormID = MHolding.normalizeID(securityID)
self.lotNormID = MHolding.normalizeID(lotID)
self.shareCount = shareCount
self.shareBasis = shareBasis
self.acquiredAt = acquiredAt
}

public init(_ element: MHolding) {
self.init(accountID: element.accountID,
securityID: element.securityID,
lotID: element.lotID)
lotID: element.lotID,
shareCount: element.shareCount,
shareBasis: element.shareBasis,
acquiredAt: element.acquiredAt)
}
}

Expand All @@ -45,6 +59,6 @@ extension MHolding: AllocKeyed {
}

public static var emptyKey: Key {
Key(accountID: "", securityID: "", lotID: "")
Key(accountID: "", securityID: "", lotID: "", shareCount: nil, shareBasis: nil, acquiredAt: Date.init(timeIntervalSinceReferenceDate: 0))
}
}
10 changes: 9 additions & 1 deletion Sources/Model/Holding/MHolding+Row.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ extension MHolding: AllocRowed {
let _securityID = getStr(row, CodingKeys.securityID.rawValue)
else { throw AllocDataError.invalidPrimaryKey("Holding") }
let _lotID = getStr(row, CodingKeys.lotID.rawValue) ?? ""
return Key(accountID: _accountID, securityID: _securityID, lotID: _lotID)
let _shareCount = getDouble(row, CodingKeys.shareCount.rawValue)
let _shareBasis = getDouble(row, CodingKeys.shareBasis.rawValue)
let _acquiredAt = getDate(row, CodingKeys.acquiredAt.rawValue)
return Key(accountID: _accountID,
securityID: _securityID,
lotID: _lotID,
shareCount: _shareCount,
shareBasis: _shareBasis,
acquiredAt: _acquiredAt)
}

public static func decode(_ rawRows: [RawRow], rejectedRows: inout [RawRow]) throws -> [DecodedRow] {
Expand Down
24 changes: 19 additions & 5 deletions Tests/Model/MHoldingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,30 @@ class MHoldingTests: XCTestCase {
}

func testPrimaryKey() throws {
let element = MHolding(accountID: " A-x?3 ", securityID: " -3B ! ", lotID: " ")
let element = MHolding(accountID: " A-x?3 ", securityID: " -3B ! ", lotID: " ", shareCount: 5, shareBasis: 6, acquiredAt: timestamp)
let actual = element.primaryKey
let expected = MHolding.Key(accountID: " A-x?3 ", securityID: " -3B ! ", lotID: " ")
let expected = MHolding.Key(accountID: " A-x?3 ", securityID: " -3B ! ", lotID: " ", shareCount: 5, shareBasis: 6, acquiredAt: timestamp)
XCTAssertEqual(expected, actual)
}

func testGetPrimaryKey() throws {
let finRow: MHolding.DecodedRow = ["holdingAccountID": " A-x?3 ", "holdingSecurityID": " -3B ! ", "holdingLotID": " "]
func testGetPrimaryKeyWithOptionals() throws {
let finRow: MHolding.DecodedRow = ["holdingAccountID": " A-x?3 ",
"holdingSecurityID": " -3B ! ",
"holdingLotID": " ",
"shareCount": 5,
"shareBasis": 6,
"acquiredAt": timestamp]
let actual = try MHolding.getPrimaryKey(finRow)
let expected = MHolding.Key(accountID: " A-x?3 ", securityID: " -3B ! ", lotID: " ")
let expected = MHolding.Key(accountID: " A-x?3 ", securityID: " -3B ! ", lotID: " ", shareCount: 5, shareBasis: 6, acquiredAt: timestamp)
XCTAssertEqual(expected, actual)
}

func testGetPrimaryKeyWithoutOptionals() throws {
let finRow: MHolding.DecodedRow = ["holdingAccountID": " A-x?3 ",
"holdingSecurityID": " -3B ! ",
"holdingLotID": " "]
let actual = try MHolding.getPrimaryKey(finRow)
let expected = MHolding.Key(accountID: " A-x?3 ", securityID: " -3B ! ", lotID: " ", shareCount: nil, shareBasis: nil, acquiredAt: nil)
XCTAssertEqual(expected, actual)
}

Expand Down

0 comments on commit 8b9cdaa

Please sign in to comment.