Skip to content

Commit a3fd38b

Browse files
author
Wojtach
committed
feat: added view for live query
1 parent 45168e0 commit a3fd38b

File tree

4 files changed

+182
-2
lines changed

4 files changed

+182
-2
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import React, { useContext, useState } from 'react';
2+
import { MutableDocument, Query } from 'cbl-reactnative';
3+
import { useStyleScheme } from '@/components/Themed/Themed';
4+
import { Button, Text, SafeAreaView, View } from 'react-native';
5+
import ResultListView from '@/components/ResultsListView/ResultsListView';
6+
import DatabaseScopeCollectionActionForm from '@/components/DatabaseScopeCollectionActionForm/DatabaseScopeCollectionActionForm';
7+
import useNavigationBarTitleOption from '@/hooks/useNativgationBarTitle';
8+
import { useNavigation } from '@react-navigation/native';
9+
import DatabaseContext from '@/providers/DatabaseContext';
10+
11+
export default function CollectionStatusScreen() {
12+
const { databases } = useContext(DatabaseContext)!;
13+
const [databaseName, setDatabaseName] = useState<string>('');
14+
const [scopeName, setScopeName] = useState<string>('');
15+
const [collectionName, setCollectionName] = useState<string>('');
16+
17+
const [isListenerAdded, setIsListenerAdded] = useState(false);
18+
const [token, setToken] = useState<string>('');
19+
const [query, setQuery] = useState<Query | null>(null);
20+
21+
const styles = useStyleScheme();
22+
const navigation = useNavigation();
23+
useNavigationBarTitleOption('Collection Change Listener', navigation);
24+
const [informationMessages, setInformationMessages] = useState<string[]>([]);
25+
26+
async function update(): Promise<void> {
27+
if (isListenerAdded && token !== '') {
28+
setInformationMessages(['::Information:: Listener already added.']);
29+
return;
30+
}
31+
32+
const database = databases[databaseName];
33+
if (!database) {
34+
setInformationMessages((prev) => [
35+
...prev,
36+
`::ERROR: Database ${databaseName} not found`,
37+
]);
38+
return;
39+
}
40+
41+
if (isListenerAdded || !!token) {
42+
setInformationMessages((prev) => [
43+
...prev,
44+
`::Information: Query Change listener already started`,
45+
]);
46+
return;
47+
}
48+
49+
try {
50+
const collection = await database.collection(collectionName, scopeName);
51+
52+
if (!collection) {
53+
setInformationMessages((prev) => [
54+
...prev,
55+
`::ERROR: ${scopeName}.${collectionName} not found`,
56+
]);
57+
return;
58+
}
59+
60+
setInformationMessages((prev) => [
61+
...prev,
62+
`::Information: Query Starting Change listener...`,
63+
]);
64+
65+
const queryString = `SELECT * FROM ${scopeName}.${collectionName} WHERE type = 'live-query'`;
66+
const query = database.createQuery(queryString);
67+
68+
const listenerToken = await query.addChangeListener((change) => {
69+
const date = new Date().toISOString();
70+
if (change.error) {
71+
setInformationMessages((prev) => [
72+
...prev,
73+
`${date} ::Change Listener Error:: ${change.error}`,
74+
]);
75+
return;
76+
}
77+
78+
if (change.results.length > 0) {
79+
const results = change.results.map((doc) => JSON.stringify(doc));
80+
setInformationMessages((prev) => [
81+
...prev,
82+
`${date} ::Information:: Query changed with: `,
83+
...results,
84+
]);
85+
} else {
86+
setInformationMessages((prev) => [
87+
...prev,
88+
`${date} ::Information:: No data in results`,
89+
]);
90+
}
91+
});
92+
93+
setQuery(query);
94+
setIsListenerAdded(true);
95+
setToken(listenerToken);
96+
setInformationMessages((prev) => [
97+
...prev,
98+
'::Information:: Query Listening for changes',
99+
]);
100+
} catch (error) {
101+
// @ts-ignore
102+
setInformationMessages((prev) => [...prev, `::ERROR: ${error.message}`]);
103+
}
104+
}
105+
106+
async function addDocument() {
107+
if (!(databaseName in databases)) {
108+
setInformationMessages((prev) => [
109+
...prev,
110+
'::Error:: Database is not set up',
111+
]);
112+
return;
113+
}
114+
115+
const database = databases[databaseName];
116+
const collection = await database.collection(collectionName, scopeName);
117+
118+
if (!collection) {
119+
setInformationMessages((prev) => [
120+
...prev,
121+
'::Error:: Database is not set up',
122+
]);
123+
return;
124+
}
125+
126+
const id = Math.floor(Math.random() * 1000).toString();
127+
const doc = new MutableDocument(`doc-${id}`);
128+
doc.setString('__id', id);
129+
doc.setString('type', 'live-query');
130+
await collection.save(doc);
131+
setInformationMessages((prev) => [
132+
...prev,
133+
`::Information:: Document with id ${doc.getId()} added.`,
134+
]);
135+
}
136+
137+
async function stop(): Promise<void> {
138+
const database = databases[databaseName];
139+
if (database != null && isListenerAdded && query) {
140+
await query.removeChangeListener(token);
141+
setIsListenerAdded(false);
142+
setInformationMessages([`::Information: Removed change listener`]);
143+
}
144+
setToken('');
145+
setDatabaseName('');
146+
setCollectionName('');
147+
setScopeName('');
148+
setQuery(null);
149+
}
150+
151+
return (
152+
<SafeAreaView style={styles.container}>
153+
<DatabaseScopeCollectionActionForm
154+
databaseName={databaseName}
155+
setDatabaseName={setDatabaseName}
156+
scopeName={scopeName}
157+
setScopeName={setScopeName}
158+
collectionName={collectionName}
159+
setCollectionName={setCollectionName}
160+
handleUpdatePressed={update}
161+
handleStopPressed={stop}
162+
/>
163+
<View
164+
style={{ flexDirection: 'column', paddingTop: 10, paddingBottom: 10 }}
165+
>
166+
<Text style={styles.header}>Step 1. Run listener</Text>
167+
<Text style={styles.header}>
168+
Step 2. Tap "Create document" button to see changes
169+
</Text>
170+
</View>
171+
<Button onPress={addDocument} title="Create document" color="#428cff" />
172+
<ResultListView
173+
style={styles}
174+
useScrollView={true}
175+
messages={informationMessages}
176+
/>
177+
</SafeAreaView>
178+
);
179+
}

expo-example/hooks/useQueryNavigationSections.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export function useQueryNavigationSections() {
1010
path: '/query/sqlPlusPlus',
1111
},
1212
{ id: 2, title: 'Query Parameters', path: '/query/parameters' },
13+
{ id: 3, title: 'Live Query', path: '/query/liveQuery' },
1314
],
1415
},
1516
];

0 commit comments

Comments
 (0)