Skip to content

Commit b1bfa8d

Browse files
committed
data api
1 parent 4bed794 commit b1bfa8d

File tree

5 files changed

+140
-7
lines changed

5 files changed

+140
-7
lines changed

src/lib/sqlite/dataApi.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import { waitTillStroageReady } from './initStorages';
12
import { sendMsgToWorker } from './messageBus';
23
import {
34
WorkerMessageTypes,
45
type DataRow,
56
type QueryRequestData,
6-
type QueryResponseData
7+
type QueryResponseData,
8+
type QueryStorageRequestData,
9+
type QueryStorageResponseData
710
} from './types';
811

912
export async function runQuery(sql: string): Promise<DataRow[]> {
@@ -22,3 +25,20 @@ export async function runQuery(sql: string): Promise<DataRow[]> {
2225

2326
return data.rows;
2427
}
28+
29+
export async function runStorageQuery(storageId: string, args: QueryStorageRequestData) {
30+
await waitTillStroageReady(storageId);
31+
32+
const res = await sendMsgToWorker({
33+
storageId: storageId,
34+
type: WorkerMessageTypes.QUERY_STORAGE,
35+
data: args,
36+
expectedType: WorkerMessageTypes.QUERY_STORAGE_RESPONSE
37+
});
38+
39+
const data = res.data as QueryStorageResponseData;
40+
41+
if (data?.errorMsg) throw new Error(data.errorMsg);
42+
43+
return data.rows;
44+
}

src/lib/sqlite/types.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ export enum WorkerMessageTypes {
1010
FILL_STORAGE = 'FILL_STORAGE',
1111
FILL_STORAGE_RESPONSE = 'FILL_STORAGE_RESPONSE',
1212
QUERY = 'QUERY',
13-
QUERY_RESPONSE = 'QUERY_RESPONSE'
13+
QUERY_RESPONSE = 'QUERY_RESPONSE',
14+
QUERY_STORAGE = 'QUERY_STORAGE',
15+
QUERY_STORAGE_RESPONSE = 'QUERY_STORAGE_RESPONSE'
1416
}
1517

1618
export type DataRow = { [key: string]: string | number | boolean | null };
@@ -54,3 +56,18 @@ export type QueryResponseData = {
5456
rows: DataRow[];
5557
errorMsg?: string;
5658
};
59+
60+
export type OrderByDir = 'asc' | 'desc';
61+
62+
export type QueryStorageRequestData = {
63+
offset?: number;
64+
limit?: number;
65+
orderByCol?: string;
66+
orderByDir?: OrderByDir;
67+
searchTerm?: string;
68+
};
69+
70+
export type QueryStorageResponseData = {
71+
rows: DataRow[];
72+
errorMsg?: string;
73+
};

src/lib/sqlite/worker/handleQuery.ts

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import getErrorMessage from '$lib/util/getErrorMsg';
2-
import type { DataRow, QueryRequestData, QueryResponseData, WorkerMessage } from '../types';
2+
import type {
3+
DataRow,
4+
QueryRequestData,
5+
QueryResponseData,
6+
QueryStorageRequestData,
7+
QueryStorageResponseData,
8+
WorkerMessage
9+
} from '../types';
310
import { db } from './initDb';
411

512
export function handleQuery(msg: WorkerMessage<QueryRequestData>): QueryResponseData {
@@ -32,3 +39,73 @@ export function handleQuery(msg: WorkerMessage<QueryRequestData>): QueryResponse
3239
};
3340
}
3441
}
42+
43+
type SQLiteColInfo = {
44+
cid: number;
45+
dflt_value: string | null;
46+
name: string;
47+
notnull: 0 | 1;
48+
pk: 0 | 1;
49+
type: string;
50+
};
51+
52+
function prepareSearchTerm(searchTerm: string, storageId: string) {
53+
const colInfo = db.selectObjects(`PRAGMA table_info(${storageId});`) as SQLiteColInfo[];
54+
55+
const coalescedCols = colInfo.map((c) => `coalesce(${c.name}, '')`).join(' || ');
56+
57+
return {
58+
where: `where (lower(${coalescedCols}) LIKE $searchTerm)`,
59+
bindVal: `%${searchTerm.replaceAll('%', '/%').toLowerCase()}%`
60+
};
61+
}
62+
63+
export function handleStorageQuery(
64+
msg: WorkerMessage<QueryStorageRequestData>
65+
): QueryStorageResponseData {
66+
try {
67+
let sql = `select * from ${msg.storageId} #WHERE# #ORDER_BY# #LIMIT#`;
68+
69+
if (msg.data.orderByCol) {
70+
const dir = msg.data.orderByDir?.toLowerCase() === 'desc' ? 'desc' : 'asc';
71+
72+
sql = sql.replace('#ORDER_BY#', `order by ${msg.data.orderByCol} ${dir}`);
73+
} else {
74+
sql = sql.replace('#ORDER_BY#', 'order by 1');
75+
}
76+
77+
const binds: { [key: string]: number | string } = {
78+
$limit: msg.data.limit ?? 999999999
79+
};
80+
81+
if (msg.data.offset) {
82+
sql = sql.replace('#LIMIT#', `limit $limit offset $offset`);
83+
binds['$offset'] = msg.data.offset;
84+
} else {
85+
sql = sql.replace('#LIMIT#', 'limit $limit');
86+
}
87+
88+
if (msg.data.searchTerm) {
89+
const { where, bindVal } = prepareSearchTerm(msg.data.searchTerm, msg.storageId);
90+
sql = sql.replace('#WHERE#', where);
91+
binds['$searchTerm'] = bindVal;
92+
} else {
93+
sql = sql.replace('#WHERE#', ``);
94+
}
95+
96+
console.log('handleStorageQuery sql:', sql, binds);
97+
98+
const data = db.selectObjects(sql, binds);
99+
100+
return {
101+
rows: data
102+
};
103+
} catch (err) {
104+
const errMsg = `Error getting rows for ${msg.storageId}: ${err}`;
105+
console.error(errMsg);
106+
return {
107+
rows: [],
108+
errorMsg: errMsg
109+
};
110+
}
111+
}

src/lib/sqlite/worker/worker.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import {
88
type FillStorageRequestData,
99
type FillStorageResponseData,
1010
type QueryRequestData,
11-
type QueryResponseData
11+
type QueryResponseData,
12+
type QueryStorageRequestData
1213
} from '../types';
13-
import { handleQuery } from './handleQuery';
14+
import { handleQuery, handleStorageQuery } from './handleQuery';
1415
import { initDb } from './initDb';
1516
import { handleCreateTable, handleFillStorage, handleTableExists } from './storageHandlers';
1617

@@ -94,6 +95,20 @@ function sendMsgToMain(obj: WorkerMessage<unknown>) {
9495
sendMsgToMain(queryResult);
9596
break;
9697

98+
case WorkerMessageTypes.QUERY_STORAGE:
99+
const queryStorageData = await handleStorageQuery(
100+
data as WorkerMessage<QueryStorageRequestData>
101+
);
102+
const queryStorageResult: WorkerMessage<QueryResponseData> = {
103+
type: WorkerMessageTypes.QUERY_STORAGE_RESPONSE,
104+
messageId: data.messageId,
105+
storageId: data.storageId,
106+
data: queryStorageData
107+
};
108+
109+
sendMsgToMain(queryStorageResult);
110+
break;
111+
97112
default:
98113
throw new Error(`Unknown message type: ${data.type}`);
99114
}

src/routes/+page.svelte

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import type { Customer } from '$lib/server/db';
3-
import { runQuery } from '$lib/sqlite/dataApi';
3+
import { runQuery, runStorageQuery } from '$lib/sqlite/dataApi';
44
import { waitTillStroageReady } from '$lib/sqlite/initStorages';
55
import { onMount } from 'svelte';
66
@@ -10,7 +10,11 @@
1010
onMount(async () => {
1111
await waitTillStroageReady('customers_v1');
1212
storageReady = true;
13-
customers = (await runQuery('SELECT * FROM customers_v1 limit 10')) as Customer[];
13+
customers = (await runStorageQuery('customers_v1', {
14+
orderByCol: 'contact',
15+
orderByDir: 'desc',
16+
searchTerm: 'Paul'
17+
})) as Customer[];
1418
console.log(customers);
1519
});
1620
</script>

0 commit comments

Comments
 (0)