-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathDBAdapter.ts
118 lines (105 loc) · 4.08 KB
/
DBAdapter.ts
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
/**
* Set of generic interfaces to allow PowerSync compatibility with
* different SQLite DB implementations.
*/
import { BaseListener, BaseObserverInterface } from '../utils/BaseObserver.js';
/**
* TODO most of these types could be exported to a common `types` package
* which is used by the DB adapter libraries as well.
*/
/**
* Object returned by SQL Query executions.
*/
export type QueryResult = {
/** Represents the auto-generated row id if applicable. */
insertId?: number;
/** Number of affected rows if result of a update query. */
rowsAffected: number;
/** if status is undefined or 0 this object will contain the query results */
rows?: {
/** Raw array with all dataset */
_array: any[];
/** The length of the dataset */
length: number;
/** A convenience function to acess the index based the row object
* @param idx the row index
* @returns the row structure identified by column names
*/
item: (idx: number) => any;
};
};
export interface DBGetUtils {
/** Execute a read-only query and return results. */
getAll<T>(sql: string, parameters?: any[]): Promise<T[]>;
/** Execute a read-only query and return the first result, or null if the ResultSet is empty. */
getOptional<T>(sql: string, parameters?: any[]): Promise<T | null>;
/** Execute a read-only query and return the first result, error if the ResultSet is empty. */
get<T>(sql: string, parameters?: any[]): Promise<T>;
}
export interface LockContext extends DBGetUtils {
/** Execute a single write statement. */
execute: (query: string, params?: any[] | undefined) => Promise<QueryResult>;
}
export interface Transaction extends LockContext {
/** Commit multiple changes to the local DB using the Transaction context. */
commit: () => Promise<QueryResult>;
/** Roll back multiple attempted changes using the Transaction context. */
rollback: () => Promise<QueryResult>;
}
/**
* Update table operation numbers from SQLite
*/
export enum RowUpdateType {
SQLITE_INSERT = 18,
SQLITE_DELETE = 9,
SQLITE_UPDATE = 23
}
export interface TableUpdateOperation {
opType: RowUpdateType;
rowId: number;
}
/**
* Notification of an update to one or more tables, for the purpose of realtime change notifications.
*/
export interface UpdateNotification extends TableUpdateOperation {
table: string;
}
export interface BatchedUpdateNotification {
rawUpdates: UpdateNotification[];
tables: string[];
groupedUpdates: Record<string, TableUpdateOperation[]>;
}
export interface DBAdapterListener extends BaseListener {
/**
* Listener for table updates.
* Allows for single table updates in order to maintain API compatibility
* without the need for a major version bump
* The DB adapter can also batch update notifications if supported.
*/
tablesUpdated: (updateNotification: BatchedUpdateNotification | UpdateNotification) => void;
}
export interface DBLockOptions {
timeoutMs?: number;
}
export interface DBAdapter extends BaseObserverInterface<DBAdapterListener>, DBGetUtils {
close: () => void;
execute: (query: string, params?: any[]) => Promise<QueryResult>;
executeBatch: (query: string, params?: any[][]) => Promise<QueryResult>;
name: string;
readLock: <T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions) => Promise<T>;
readTransaction: <T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions) => Promise<T>;
writeLock: <T>(fn: (tx: LockContext) => Promise<T>, options?: DBLockOptions) => Promise<T>;
writeTransaction: <T>(fn: (tx: Transaction) => Promise<T>, options?: DBLockOptions) => Promise<T>;
/**
* This method refreshes the schema information across all connections. This is for advanced use cases, and should generally not be needed.
*/
refreshSchema: () => Promise<void>;
}
export function isBatchedUpdateNotification(
update: BatchedUpdateNotification | UpdateNotification
): update is BatchedUpdateNotification {
return 'tables' in update;
}
export function extractTableUpdates(update: BatchedUpdateNotification | UpdateNotification) {
return isBatchedUpdateNotification(update) ? update.tables : [update.table];
}