Skip to content
This repository has been archived by the owner on Aug 11, 2024. It is now read-only.

Commit

Permalink
Fix handling of draft addresses when loading from SQLite (#1140)
Browse files Browse the repository at this point in the history
Fixes #1135

Drafts are only very rarely being drawn in the deck view but when it
_does_ happen we were calculating the address incorrectly.

I relaxed the (old) constraint that preventing drafts from showing up in
the deck view most of the time (I think you should be able to see these
like any other note, otherwise they will never resurface) and clarified
the address resolution when loading from SQLite.
  • Loading branch information
bfollington authored Mar 20, 2024
1 parent 27b06dd commit 3e1a0e3
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 24 deletions.
3 changes: 2 additions & 1 deletion xcode/Subconscious/Shared/Components/Deck/DeckView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,8 @@ struct DeckModel: ModelProtocol {

guard let entry = environment.database.readRandomUnseenEntry(
owner: us,
seen: state.seen.map { entry in entry.address }
seen: state.seen.map { entry in entry.address },
minimumBodyLength: 64
) else {
return .topupDeck
}
Expand Down
69 changes: 46 additions & 23 deletions xcode/Subconscious/Shared/Services/DatabaseService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -696,16 +696,15 @@ final class DatabaseService {
throw DatabaseServiceError.notReady
}

// Exclude any local-only notes from the feed
let ignoredDids = [Did.local.description]
let ignoredDids: [Did] = []

let results = try database.execute(
sql: """
SELECT did, slashlink, excerpt, headers
FROM memo
WHERE did NOT IN (SELECT value FROM json_each(?))
AND substr(slug, 1, 1) != '_'
ORDER BY modified DESC
SELECT memo.did, peer.petname, memo.slug, memo.excerpt, memo.headers FROM memo
LEFT JOIN peer ON memo.did = peer.did
WHERE memo.did NOT IN (SELECT value FROM json_each(?))
AND substr(memo.slug, 1, 1) != '_'
ORDER BY memo.modified DESC
LIMIT ?
""",
parameters: [
Expand All @@ -716,20 +715,22 @@ final class DatabaseService {
return try results.compactMap({ row in
guard
let did = row.col(0)?.toString()?.toDid(),
let slashlink = row.col(1)?
let slug = row.col(2)?
.toString()?
.toSlashlink()?
.relativizeIfNeeded(did: owner)
.toSlug()
else {
return nil
}

let petname = row.col(1)?.toString()?.toPetname()
let address = bestAddress(did: did, slug: slug, petname: petname, owner: owner)

let excerpt = Subtext(markup: row.col(2)?.toString() ?? "")
let headers = try parseHeadersJson(json: row.col(3)?.toString() ?? "")
let excerpt = Subtext(markup: row.col(3)?.toString() ?? "")
let headers = try parseHeadersJson(json: row.col(4)?.toString() ?? "")

return EntryStub(
did: did,
address: slashlink,
address: address,
excerpt: excerpt,
headers: headers
)
Expand Down Expand Up @@ -1429,35 +1430,45 @@ final class DatabaseService {
.first
}

func readRandomUnseenEntry(owner: Did?, seen: [Slashlink]) -> EntryStub? {
func readRandomUnseenEntry(
owner: Did?,
seen: [Slashlink],
minimumBodyLength: Int = 0
) -> EntryStub? {
guard self.state == .ready else {
return nil
}

return try? database.execute(
sql: """
SELECT did, slashlink, excerpt, headers
FROM memo
SELECT memo.did, peer.petname, memo.slug, memo.excerpt, memo.headers FROM memo
LEFT JOIN peer ON memo.did = peer.did
WHERE substr(memo.slug, 1, 1) != '_'
AND length(excerpt) > 64
AND slashlink NOT IN (SELECT value FROM json_each(?))
AND length(memo.excerpt) > ?
AND memo.slashlink NOT IN (SELECT value FROM json_each(?))
ORDER BY RANDOM()
LIMIT 1
""",
parameters: [.json(seen.map { s in s.description }, or: "[]")]
parameters: [
.integer(minimumBodyLength),
.json(seen.map { s in s.description }, or: "[]")
]
)
.compactMap({ row in
guard
let did = row.col(0)?.toString()?.toDid(),
let address = row.col(1)?
let slug = row.col(2)?
.toString()?
.toSlashlink()
.toSlug()
else {
return nil
}

let petname = row.col(1)?.toString()?.toPetname()
let address = bestAddress(did: did, slug: slug, petname: petname, owner: owner)

let excerpt = Subtext(markup: row.col(2)?.toString() ?? "")
let headers = try parseHeadersJson(json: row.col(3)?.toString() ?? "")
let excerpt = Subtext(markup: row.col(3)?.toString() ?? "")
let headers = try parseHeadersJson(json: row.col(4)?.toString() ?? "")

return EntryStub(
did: did,
Expand All @@ -1468,6 +1479,18 @@ final class DatabaseService {
})
.first
}

func bestAddress(did: Did, slug: Slug, petname: Petname?, owner: Did?) -> Slashlink {
switch petname {
case .some(let name):
return Slashlink(petname: name, slug: slug)
case .none:
return Slashlink(
peer: .did(did),
slug: slug
).relativizeIfNeeded(did: owner)
}
}

/// Select a random entry
func readRandomEntry(owner: Did?) -> EntryStub? {
Expand Down
225 changes: 225 additions & 0 deletions xcode/Subconscious/SubconsciousTests/Tests_DatabaseService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,231 @@ class Tests_DatabaseService: XCTestCase {
)
}

func testListAllMemos() throws {
let service = try createDatabaseService()
_ = try service.migrate()

// Add some entries to DB
let now = Date.now

let foo = Memo(
contentType: "text/subtext",
created: now,
modified: now,
fileExtension: "subtext",
additionalHeaders: [],
body: "Foo"
)
try service.writeMemo(
MemoRecord(
did: Did.local,
petname: nil,
slug: Slug("foo")!,
memo: foo,
size: foo.toHeaderSubtext().size()!
)
)


let did = Did("did:key:abc123")!
let did2 = Did("did:key:def456")!
try service.writePeer(PeerRecord(petname: Petname("abc")!, identity: did))

let bar = Memo(
contentType: "text/subtext",
created: now,
modified: now,
fileExtension: "subtext",
additionalHeaders: [],
body: "Bar"
)
try service.writeMemo(
MemoRecord(
did: did,
petname: Petname("abc")!,
slug: Slug("bar")!,
memo: bar
)
)

let qux = Memo(
contentType: "text/subtext",
created: now,
modified: now,
fileExtension: "subtext",
additionalHeaders: [],
body: "Qux"
)
try service.writeMemo(
MemoRecord(
did: did2,
petname: nil,
slug: Slug("qux")!,
memo: qux,
size: qux.toHeaderSubtext().size()!
)
)

let baz = Memo(
contentType: "text/subtext",
created: now,
modified: now,
fileExtension: "subtext",
additionalHeaders: [],
body: "Baz"
)
try service.writeMemo(
MemoRecord(
did: Did.local,
petname: nil,
slug: Slug("baz")!,
memo: baz,
size: baz.toHeaderSubtext().size()!
)
)

let recent = try service.listAll(owner: did, limit: 3)

XCTAssertEqual(recent.count, 3)

XCTAssertEqual(recent[0].did, Did.local)
XCTAssertEqual(recent[1].did, did)
XCTAssertEqual(recent[2].did, did2)

let slashlinks = Set(
recent.compactMap({ stub in
stub.address
})
)
XCTAssertEqual(slashlinks.count, 3)
XCTAssertTrue(
slashlinks.contains(
Slashlink(
peer: Peer.did(did2),
slug: Slug("qux")!
)
)
)
XCTAssertTrue(
slashlinks.contains(
Slashlink(
peer: Peer.did(Did.local),
slug: Slug("foo")!
)
)
)
XCTAssertTrue(
slashlinks.contains(
Slashlink(
petname: Petname("abc")!,
slug: Slug("bar")!
)
)
)
}

func testListUnseen() throws {
let service = try createDatabaseService()
_ = try service.migrate()

// Add some entries to DB
let now = Date.now

let foo = Memo(
contentType: "text/subtext",
created: now,
modified: now,
fileExtension: "subtext",
additionalHeaders: [],
body: "Foo"
)
try service.writeMemo(
MemoRecord(
did: Did.local,
petname: nil,
slug: Slug("foo")!,
memo: foo,
size: foo.toHeaderSubtext().size()!
)
)


let did = Did("did:key:abc123")!
let did2 = Did("did:key:def456")!
try service.writePeer(PeerRecord(petname: Petname("abc")!, identity: did))

let bar = Memo(
contentType: "text/subtext",
created: now,
modified: now,
fileExtension: "subtext",
additionalHeaders: [],
body: "Bar"
)
try service.writeMemo(
MemoRecord(
did: did,
petname: Petname("abc")!,
slug: Slug("bar")!,
memo: bar
)
)

let qux = Memo(
contentType: "text/subtext",
created: now,
modified: now,
fileExtension: "subtext",
additionalHeaders: [],
body: "Qux"
)
try service.writeMemo(
MemoRecord(
did: did2,
petname: nil,
slug: Slug("qux")!,
memo: qux,
size: qux.toHeaderSubtext().size()!
)
)

let baz = Memo(
contentType: "text/subtext",
created: now,
modified: now,
fileExtension: "subtext",
additionalHeaders: [],
body: "Baz"
)
try service.writeMemo(
MemoRecord(
did: Did.local,
petname: nil,
slug: Slug("baz")!,
memo: baz,
size: baz.toHeaderSubtext().size()!
)
)

let recent = service.readRandomUnseenEntry(
owner: did,
seen: [
Slashlink(
slug: Slug("baz")!
),
Slashlink(
slug: Slug("foo")!
),
Slashlink(
petname: Petname("abc")!,
slug: Slug("foo")!
)
]
)

XCTAssert(recent?.address.slug == Slug("qux"))
}

func testReadRandomEntryInDateRange() throws {
let service = try createDatabaseService()
_ = try service.migrate()
Expand Down

0 comments on commit 3e1a0e3

Please sign in to comment.