diff --git a/web/database/utils/db-utils.js b/web/database/utils/db-utils.js
new file mode 100644
--- /dev/null
+++ b/web/database/utils/db-utils.js
@@ -0,0 +1,25 @@
+// @flow
+
+function parseSQLiteQueryResult<T>(result: QueryExecResult): $ReadOnlyArray<T> {
+  const { columns, values } = result;
+  return values.map(rowResult => {
+    const row: any = Object.fromEntries(
+      columns.map((key, index) => [key, rowResult[index]]),
+    );
+    return row;
+  });
+}
+
+// NOTE: sql.js has behavior that when there are multiple statements in query
+// e.g. "statement1; statement2; statement3;"
+// and statement2 will not return anything, the result will be:
+// [result1, result3], not [result1, undefined, result3]
+function parseSQLiteResult<T>(
+  rawResult: $ReadOnlyArray<QueryExecResult>,
+): $ReadOnlyArray<$ReadOnlyArray<T>> {
+  return rawResult.map((queryResult: QueryExecResult) =>
+    parseSQLiteQueryResult<T>(queryResult),
+  );
+}
+
+export { parseSQLiteResult };