use srf parsing/conversion in porfolio
This commit is contained in:
parent
44dfafd574
commit
189d09720b
1 changed files with 13 additions and 126 deletions
139
src/cache/store.zig
vendored
139
src/cache/store.zig
vendored
|
|
@ -693,7 +693,6 @@ pub fn serializePortfolio(allocator: std.mem.Allocator, lots: []const Lot) ![]co
|
|||
|
||||
/// Deserialize a portfolio from SRF data. Caller owns the returned Portfolio.
|
||||
pub fn deserializePortfolio(allocator: std.mem.Allocator, data: []const u8) !Portfolio {
|
||||
const LotType = @import("../models/portfolio.zig").LotType;
|
||||
var lots: std.ArrayList(Lot) = .empty;
|
||||
errdefer {
|
||||
for (lots.items) |lot| {
|
||||
|
|
@ -706,134 +705,22 @@ pub fn deserializePortfolio(allocator: std.mem.Allocator, data: []const u8) !Por
|
|||
}
|
||||
|
||||
var reader = std.Io.Reader.fixed(data);
|
||||
const parsed = srf.parse(&reader, allocator, .{ .alloc_strings = false }) catch return error.InvalidData;
|
||||
defer parsed.deinit();
|
||||
var it = srf.iterator(&reader, allocator, .{ .alloc_strings = false }) catch return error.InvalidData;
|
||||
defer it.deinit();
|
||||
|
||||
for (parsed.records) |record| {
|
||||
var lot = Lot{
|
||||
.symbol = "",
|
||||
.shares = 0,
|
||||
.open_date = Date.epoch,
|
||||
.open_price = 0,
|
||||
};
|
||||
var sym_raw: ?[]const u8 = null;
|
||||
var note_raw: ?[]const u8 = null;
|
||||
var account_raw: ?[]const u8 = null;
|
||||
var sec_type_raw: ?[]const u8 = null;
|
||||
var ticker_raw: ?[]const u8 = null;
|
||||
while (try it.next()) |fields| {
|
||||
var lot = fields.to(Lot) catch continue;
|
||||
|
||||
for (record.fields) |field| {
|
||||
if (std.mem.eql(u8, field.key, "symbol")) {
|
||||
if (field.value) |v| sym_raw = switch (v) {
|
||||
.string => |s| s,
|
||||
else => null,
|
||||
};
|
||||
} else if (std.mem.eql(u8, field.key, "shares")) {
|
||||
if (field.value) |v| lot.shares = Store.numVal(v);
|
||||
} else if (std.mem.eql(u8, field.key, "open_date")) {
|
||||
if (field.value) |v| {
|
||||
const str = switch (v) {
|
||||
.string => |s| s,
|
||||
else => continue,
|
||||
};
|
||||
lot.open_date = Date.parse(str) catch continue;
|
||||
}
|
||||
} else if (std.mem.eql(u8, field.key, "open_price")) {
|
||||
if (field.value) |v| lot.open_price = Store.numVal(v);
|
||||
} else if (std.mem.eql(u8, field.key, "close_date")) {
|
||||
if (field.value) |v| {
|
||||
const str = switch (v) {
|
||||
.string => |s| s,
|
||||
else => continue,
|
||||
};
|
||||
lot.close_date = Date.parse(str) catch null;
|
||||
}
|
||||
} else if (std.mem.eql(u8, field.key, "close_price")) {
|
||||
if (field.value) |v| lot.close_price = Store.numVal(v);
|
||||
} else if (std.mem.eql(u8, field.key, "note")) {
|
||||
if (field.value) |v| note_raw = switch (v) {
|
||||
.string => |s| s,
|
||||
else => null,
|
||||
};
|
||||
} else if (std.mem.eql(u8, field.key, "account")) {
|
||||
if (field.value) |v| account_raw = switch (v) {
|
||||
.string => |s| s,
|
||||
else => null,
|
||||
};
|
||||
} else if (std.mem.eql(u8, field.key, "security_type")) {
|
||||
if (field.value) |v| sec_type_raw = switch (v) {
|
||||
.string => |s| s,
|
||||
else => null,
|
||||
};
|
||||
} else if (std.mem.eql(u8, field.key, "maturity_date")) {
|
||||
if (field.value) |v| {
|
||||
const str = switch (v) {
|
||||
.string => |s| s,
|
||||
else => continue,
|
||||
};
|
||||
lot.maturity_date = Date.parse(str) catch null;
|
||||
}
|
||||
} else if (std.mem.eql(u8, field.key, "rate")) {
|
||||
if (field.value) |v| {
|
||||
const r = Store.numVal(v);
|
||||
if (r > 0) lot.rate = r;
|
||||
}
|
||||
} else if (std.mem.eql(u8, field.key, "drip")) {
|
||||
if (field.value) |v| {
|
||||
switch (v) {
|
||||
.string => |s| lot.drip = std.mem.eql(u8, s, "true") or std.mem.eql(u8, s, "1"),
|
||||
.number => |n| lot.drip = n > 0,
|
||||
.boolean => |b| lot.drip = b,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
} else if (std.mem.eql(u8, field.key, "ticker")) {
|
||||
if (field.value) |v| ticker_raw = switch (v) {
|
||||
.string => |s| s,
|
||||
else => null,
|
||||
};
|
||||
} else if (std.mem.eql(u8, field.key, "price")) {
|
||||
if (field.value) |v| {
|
||||
const p = Store.numVal(v);
|
||||
if (p > 0) lot.price = p;
|
||||
}
|
||||
} else if (std.mem.eql(u8, field.key, "price_date")) {
|
||||
if (field.value) |v| {
|
||||
const str = switch (v) {
|
||||
.string => |s| s,
|
||||
else => continue,
|
||||
};
|
||||
lot.price_date = Date.parse(str) catch null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Dupe owned strings before iterator.deinit() frees the backing buffer
|
||||
lot.symbol = try allocator.dupe(u8, lot.symbol);
|
||||
if (lot.note) |n| lot.note = try allocator.dupe(u8, n);
|
||||
if (lot.account) |a| lot.account = try allocator.dupe(u8, a);
|
||||
if (lot.ticker) |t| lot.ticker = try allocator.dupe(u8, t);
|
||||
|
||||
// Determine lot type
|
||||
if (sec_type_raw) |st| {
|
||||
lot.security_type = LotType.fromString(st);
|
||||
}
|
||||
|
||||
// Cash lots don't require a symbol -- generate a placeholder
|
||||
if (lot.security_type == .cash) {
|
||||
if (sym_raw == null) {
|
||||
lot.symbol = try allocator.dupe(u8, "CASH");
|
||||
} else {
|
||||
lot.symbol = try allocator.dupe(u8, sym_raw.?);
|
||||
}
|
||||
} else if (sym_raw) |s| {
|
||||
lot.symbol = try allocator.dupe(u8, s);
|
||||
} else continue;
|
||||
|
||||
if (note_raw) |n| {
|
||||
lot.note = try allocator.dupe(u8, n);
|
||||
}
|
||||
|
||||
if (account_raw) |a| {
|
||||
lot.account = try allocator.dupe(u8, a);
|
||||
}
|
||||
|
||||
if (ticker_raw) |t| {
|
||||
lot.ticker = try allocator.dupe(u8, t);
|
||||
// Cash lots without a symbol get a placeholder
|
||||
if (lot.security_type == .cash and lot.symbol.len == 0) {
|
||||
allocator.free(lot.symbol);
|
||||
lot.symbol = try allocator.dupe(u8, "CASH");
|
||||
}
|
||||
|
||||
try lots.append(allocator, lot);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue