Skip to content
This repository was archived by the owner on Oct 25, 2023. It is now read-only.

Sort nodes by "crated-at" time in node iterator, latest first #430

Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion archaeologist/src/background/search/similarity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export function addNode(node: TNode): void {
}

export async function register(storage: StorageApi) {
const iter = storage.node.iterate()
const iter = await storage.node.iterate()
while (true) {
const node = await iter.next()
if (node) {
Expand Down
2 changes: 1 addition & 1 deletion archaeologist/src/background/suggestAssociations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export async function suggestAssociations(
limit?: number
): Promise<TNode[]> {
const beagle = Beagle.fromString(phrase)
const iter = storage.node.iterate()
const iter = await storage.node.iterate()
const suggested: TNode[] = []
limit = limit ?? 8
// FIXME(akindyakov): This is a dirty hack to limit time of search by limiting
Expand Down
2 changes: 1 addition & 1 deletion archaeologist/src/omnibox/omnibox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const lookUpAndSuggestFor = lodash.debounce(
suggest: (suggestResults: browser.Omnibox.SuggestResult[]) => void
): Promise<void> => {
const beagle = Beagle.fromString(text)
const iter = storage.node.iterate()
const iter = await storage.node.iterate()
const suggestions: browser.Omnibox.SuggestResult[] = []
for (
let node = await iter.next();
Expand Down
54 changes: 38 additions & 16 deletions archaeologist/src/storage_api_browser_ext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,23 @@ type GenericLav<Kind extends string, Value, Auxiliary = undefined> = {
}
}

/**
* Structure describes a node in minimalistic maner to build a full list of all
* nodes out of it. All node fields mentioned here are immutable throughout of
* a node life.
*/
type NodeTag = {
// A unique node identifier, there is no more than one item in the list with
// the same nid.
nid: Nid

// The rest of the fields are added here for quick sorting purposes.

// Node creation date, exact copy of the `created_at` fild of the `TNode`.
created_at: unixtime.Type
}
type AllNidsYek = GenericYek<'all-nids', undefined>
type AllNidsLav = GenericLav<'all-nids', Nid[]>
type AllNidsLav = GenericLav<'all-nids', NodeTag[]>

type NidToNodeYek = GenericYek<'nid->node', Nid>
type NidToNodeLav = GenericLav<
Expand Down Expand Up @@ -438,7 +453,12 @@ async function createNode(
let records: YekLav[] = [
await store.prepareAppend(
{ yek: { kind: 'all-nids', key: undefined } },
{ lav: { kind: 'all-nids', value: [node.nid] } }
{
lav: {
kind: 'all-nids',
value: [{ nid: node.nid, created_at: node.created_at }],
},
}
),
{
yek: { yek: { kind: 'nid->node', key: node.nid } },
Expand Down Expand Up @@ -714,27 +734,26 @@ async function bulkDeleteNodes(

class Iterator implements INodeIterator {
private store: YekLavStore
private nids: Promise<Nid[]>
private nids: Nid[]
private index: number

constructor(store: YekLavStore) {
constructor(store: YekLavStore, nids: Nid[]) {
this.store = store
this.index = 0
this.nids = nids
}

const yek: AllNidsYek = {
yek: { kind: 'all-nids', key: undefined },
}
this.nids = store
.get(yek)
.then((lav: AllNidsLav | undefined) => lav?.lav.value ?? [])
static async create(store: YekLavStore): Promise<Iterator> {
const nids = await getAllNids(store, {})
return new Iterator(store, nids)
}

async next(): Promise<TNode | null> {
const nids = await this.nids
const nids = this.nids
if (this.index >= nids.length) {
return null
}
const nid: Nid = nids[nids.length - this.index - 1]
const nid: Nid = nids[0]
const yek: NidToNodeYek = { yek: { kind: 'nid->node', key: nid } }
const lav: NidToNodeLav | undefined = await this.store.get(yek)
if (lav == null) {
Expand All @@ -748,7 +767,7 @@ class Iterator implements INodeIterator {
}
abort(): void {
this.index = 0
this.nids = Promise.resolve([])
this.nids = []
}
}

Expand Down Expand Up @@ -912,8 +931,11 @@ export async function getAllNids(
if (lav == null) {
return []
}
const value: Nid[] = lav.lav.value
return value.reverse()
const tags = lav?.lav.value ?? []
// Sort tags by creation date, latest first
tags.sort((a, b) => b.created_at - a.created_at)
const nids = tags.map((t) => t.nid)
return nids
}

export function makeBrowserExtStorageApi(
Expand All @@ -938,7 +960,7 @@ export function makeBrowserExtStorageApi(
getAllNids: (args: NodeGetAllNidsArgs) => getAllNids(store, args),
update: (args: NodeUpdateArgs) => updateNode(store, args),
create: (args: NodeCreateArgs) => createNode(store, args, account),
iterate: () => new Iterator(store),
iterate: () => Iterator.create(store),
delete: (args: NodeDeleteArgs) => deleteNode(store, args),
bulkDelete: (args: NodeBulkDeleteArgs) => bulkDeleteNodes(store, args),
batch: {
Expand Down
5 changes: 3 additions & 2 deletions elementary/src/grid/SearchGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @jsxImportSource @emotion/react */

import React, { useEffect, useRef, useState } from 'react'
import { useAsyncEffect } from 'use-async-effect'

import styled from '@emotion/styled'

Expand Down Expand Up @@ -73,9 +74,9 @@ export const SearchGrid = ({
iter: INodeIterator
beagle: Beagle
} | null>(null)
useEffect(() => {
useAsyncEffect(async () => {
setUpSearch({
iter: storage.node.iterate(),
iter: await storage.node.iterate(),
beagle: Beagle.fromString(q || undefined),
})
}, [q])
Expand Down
2 changes: 1 addition & 1 deletion smuggler-api/src/api_datacenter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ export function makeDatacenterStorageApi(): StorageApi {
},
update: updateNode,
create: createNode,
iterate: () => _getNodesSliceIter({}),
iterate: async () => _getNodesSliceIter({}),
delete: deleteNode,
bulkDelete: bulkDeleteNodes,
batch: {
Expand Down
2 changes: 1 addition & 1 deletion smuggler-api/src/storage_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export type StorageApi = {
args: NodeCreateArgs,
signal?: AbortSignal
) => Promise<NewNodeResponse>
iterate: () => INodeIterator
iterate: () => Promise<INodeIterator>
delete: (args: NodeDeleteArgs, signal?: AbortSignal) => Promise<Ack>
bulkDelete: (
args: NodeBulkDeleteArgs,
Expand Down
21 changes: 14 additions & 7 deletions smuggler-api/src/storage_api_msg_proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,23 @@ export type ForwardToRealImpl = (
) => Promise<StorageApiMsgReturnValue>

class MsgProxyNodeIterator implements INodeIterator {
private nids: Promise<Nid[]>
private nids: Nid[]
private index: number
private forward: (
payload: StorageApiMsgPayload
) => Promise<StorageApiMsgReturnValue>

constructor(forward: ForwardToRealImpl) {
constructor(forward: ForwardToRealImpl, nids: Nid[]) {
this.forward = forward
this.nids = nids
this.index = 0
}

static async create(
forward: ForwardToRealImpl
): Promise<MsgProxyNodeIterator> {
const apiName = 'node.getAllNids'
this.nids = this.forward({ apiName, args: {} }).then(
const nids = await forward({ apiName, args: {} }).then(
(value: StorageApiMsgReturnValue) => {
if (apiName !== value.apiName) {
throw mismatchError(apiName, value.apiName)
Expand All @@ -140,11 +147,11 @@ class MsgProxyNodeIterator implements INodeIterator {
return ret
}
)
this.index = 0
return new MsgProxyNodeIterator(forward, nids)
}

async next(): Promise<TNode | null> {
const nids = await this.nids
const nids = this.nids
if (this.index >= nids.length) {
return null
}
Expand All @@ -162,7 +169,7 @@ class MsgProxyNodeIterator implements INodeIterator {
}
abort(): void {
this.index = 0
this.nids = Promise.resolve([])
this.nids = []
}
}

Expand Down Expand Up @@ -204,7 +211,7 @@ export function makeMsgProxyStorageApi(forward: ForwardToRealImpl): StorageApi {
const ret: NewNodeResponse = resp.ret
return ret
},
iterate: () => new MsgProxyNodeIterator(forward),
iterate: () => MsgProxyNodeIterator.create(forward),
delete: async (args: NodeDeleteArgs) => {
const apiName = 'node.delete'
const resp = await forward({ apiName, args })
Expand Down
4 changes: 2 additions & 2 deletions truthsayer/src/export/DownloadAsFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function DownloadAsFile({ className }: { className?: string }) {
const [processingStatus, setProcessingStatus] = useState<boolean>(false)
const saveAsPlainText = useCallback(async () => {
setProcessingStatus(true)
const iter = ctx.storage.node.iterate()
const iter = await ctx.storage.node.iterate()
const chunks: string[] = []
while (true) {
const node = await iter.next()
Expand Down Expand Up @@ -105,7 +105,7 @@ export function DownloadAsFile({ className }: { className?: string }) {
}, [ctx.account, ctx.storage.node])
const saveAsJson = useCallback(async () => {
setProcessingStatus(true)
const iter = ctx.storage.node.iterate()
const iter = await ctx.storage.node.iterate()
const chunks: Record<Nid, TNodeJson> = {}
while (true) {
const node = await iter.next()
Expand Down