File size: 4,876 Bytes
5fa7a59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
function openDb() {
  return new Promise((resolve, reject) => {
    const req = indexedDB.open('paper_trading_viz', 2)
    req.onupgradeneeded = () => {
      const db = req.result
      if (!db.objectStoreNames.contains('meta')) db.createObjectStore('meta', { keyPath: 'id' })
      if (!db.objectStoreNames.contains('raw_decisions')) {
        const raw = db.createObjectStore('raw_decisions', { keyPath: 'id' })
        if (!raw.indexNames.contains('group')) raw.createIndex('group', 'group', { unique: false })
        if (!raw.indexNames.contains('updated_at')) raw.createIndex('updated_at', 'updated_at', { unique: false })
      }
    }
    req.onsuccess = () => resolve(req.result)
    req.onerror = () => reject(req.error)
  })
}

// removed aggregates helpers

export async function readSyncMeta() {
  const db = await openDb()
  return new Promise((resolve, reject) => {
    const tx = db.transaction('meta', 'readonly')
    const store = tx.objectStore('meta')
    const req = store.get('raw_sync')
    req.onsuccess = () => resolve(req.result || null)
    req.onerror = () => reject(req.error)
  })
}

export async function writeSyncMeta(remoteUpdatedAt, lastSyncedAt) {
  const db = await openDb()
  return new Promise((resolve, reject) => {
    const tx = db.transaction('meta', 'readwrite')
    const store = tx.objectStore('meta')
    store.put({ id: 'raw_sync', remoteUpdatedAt: remoteUpdatedAt || null, lastSyncedAt: lastSyncedAt || new Date().toISOString() })
    tx.oncomplete = () => resolve(true)
    tx.onerror = () => reject(tx.error)
  })
}

export async function writeRawDecisions(rows) {
  const db = await openDb()
  return new Promise((resolve, reject) => {
    const tx = db.transaction('raw_decisions', 'readwrite')
    const store = tx.objectStore('raw_decisions')
    const clearReq = store.clear()
    clearReq.onsuccess = () => {
      for (const r of rows) {
        const key = r.id
        const group = `${r.agent_name}|${r.asset}|${r.model}`
        store.put({ ...r, id: key, group })
      }
      tx.oncomplete = () => resolve(true)
      tx.onerror = () => reject(tx.error)
    }
    clearReq.onerror = () => reject(clearReq.error)
  })
}

export async function upsertRawDecisions(rows) {
  const db = await openDb()
  return new Promise((resolve, reject) => {
    const tx = db.transaction('raw_decisions', 'readwrite')
    const store = tx.objectStore('raw_decisions')
    for (const r of rows) {
      const key = r.id
      const group = `${r.agent_name}|${r.asset}|${r.model}`
      store.put({ ...r, id: key, group })
    }
    tx.oncomplete = () => resolve(true)
    tx.onerror = () => reject(tx.error)
  })
}

export async function readRawByGroup(groupKey) {
  const db = await openDb()
  return new Promise((resolve, reject) => {
    const tx = db.transaction('raw_decisions', 'readonly')
    const store = tx.objectStore('raw_decisions')
    const idx = store.index('group')
    const req = idx.openCursor(IDBKeyRange.only(groupKey))
    const rows = []
    req.onsuccess = e => {
      const cursor = e.target.result
      if (cursor) { rows.push(cursor.value); cursor.continue() } else { resolve(rows) }
    }
    req.onerror = () => reject(req.error)
  })
}

export async function readAllRawDecisions() {
  const db = await openDb()
  return new Promise((resolve, reject) => {
    const tx = db.transaction('raw_decisions', 'readonly')
    const store = tx.objectStore('raw_decisions')
    const rows = []
    const cursorReq = store.openCursor()
    cursorReq.onsuccess = e => {
      const cursor = e.target.result
      if (cursor) { rows.push(cursor.value); cursor.continue() } else { resolve(rows) }
    }
    cursorReq.onerror = () => reject(cursorReq.error)
  })
}

export async function readRawUpdatedAtMax() {
  const db = await openDb()
  return new Promise((resolve, reject) => {
    const tx = db.transaction('raw_decisions', 'readonly')
    const store = tx.objectStore('raw_decisions')
    const index = store.index('updated_at')
    const req = index.openCursor(null, 'prev')
    req.onsuccess = e => {
      const cursor = e.target.result
      resolve(cursor ? cursor.value.updated_at : null)
    }
    req.onerror = () => reject(req.error)
  })
}

export async function clearAllStores() {
  const db = await openDb()
  return new Promise((resolve, reject) => {
    const stores = []
    if (db.objectStoreNames.contains('meta')) stores.push('meta')
    if (db.objectStoreNames.contains('raw_decisions')) stores.push('raw_decisions')
    if (stores.length === 0) { resolve(true); return }
    const tx = db.transaction(stores, 'readwrite')
    if (db.objectStoreNames.contains('meta')) tx.objectStore('meta').clear()
    if (db.objectStoreNames.contains('raw_decisions')) tx.objectStore('raw_decisions').clear()
    tx.oncomplete = () => resolve(true)
    tx.onerror = () => reject(tx.error)
  })
}