Skip to content

Commit f45fea3

Browse files
committed
feat: added query explain support to example app and to main native module
1 parent 6239fa8 commit f45fea3

File tree

12 files changed

+284
-76
lines changed

12 files changed

+284
-76
lines changed
Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,57 @@
1-
import React, { useState } from 'react';
1+
import React from 'react';
22
import { Database } from 'cbl-reactnative';
33
import execute from '@/service/query/execute';
4-
import CBLDatabaseActionContainer from '@/components/CBLDatabaseActionContainer';
5-
import { useStyleScheme } from '@/components/Themed';
6-
import { StyledTextInput } from '@/components/StyledTextInput';
7-
import HeaderView from '@/components/HeaderView';
4+
import explain from '@/service/query/explain';
5+
import CBLDatabaseQueryActionContainer from '@/components/CBLDatabaseQueryActionContainer';
86

97
export default function QuerySqlPlusPlusScreen() {
10-
const [query, setQuery] = useState<string>('');
11-
const styles = useStyleScheme();
8+
function reset() {}
129

13-
function reset() {
14-
setQuery('');
15-
}
16-
17-
async function update(database: Database): Promise<string[]> {
10+
async function runQuery(
11+
database: Database,
12+
sqlQuery: string,
13+
isExplain: boolean
14+
): Promise<string[]> {
1815
try {
1916
const date = new Date().toISOString();
20-
const results = await execute(query, null, database);
2117
const dict: string[] = [];
22-
for (const result of results) {
23-
dict.push(`${date}::<<${JSON.stringify(result)}>>`);
18+
if (isExplain) {
19+
const result = await explain(sqlQuery, null, database);
20+
dict.push(`${date}::<<${result}>>`);
21+
return dict;
22+
} else {
23+
const results = await execute(sqlQuery, null, database);
24+
for (const result of results) {
25+
dict.push(`${date}::<<${JSON.stringify(result)}>>`);
26+
}
27+
return dict;
2428
}
25-
return dict;
2629
} catch (error) {
2730
// @ts-ignore
2831
return [error.message];
2932
}
3033
}
3134

35+
function updatePressed(
36+
database: Database,
37+
sqlQuery: string
38+
): Promise<string[]> {
39+
return runQuery(database, sqlQuery, false);
40+
}
41+
42+
function explainPressed(
43+
database: Database,
44+
sqlQuery: string
45+
): Promise<string[]> {
46+
return runQuery(database, sqlQuery, true);
47+
}
48+
3249
return (
33-
<CBLDatabaseActionContainer
50+
<CBLDatabaseQueryActionContainer
3451
screenTitle={'Query Workbench'}
35-
handleUpdatePressed={update}
52+
handleUpdatePressed={updatePressed}
53+
handleExplainedPressed={explainPressed}
3654
handleResetPressed={reset}
37-
>
38-
<HeaderView name="Query Editor" iconName="database-search" />
39-
<StyledTextInput
40-
autoCapitalize="none"
41-
style={[
42-
styles.textInput,
43-
{ height: undefined, minHeight: 120, marginTop: 5, marginBottom: 15 },
44-
]}
45-
placeholder="SQL++ Query"
46-
onChangeText={(newText) => setQuery(newText)}
47-
defaultValue={query}
48-
multiline={true}
49-
/>
50-
</CBLDatabaseActionContainer>
55+
/>
5156
);
5257
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import React, { useContext, useState } from 'react';
2+
import DatabaseContext from '@/providers/DatabaseContext';
3+
import { useNavigation } from '@react-navigation/native';
4+
import { useStyleScheme } from '@/components/Themed';
5+
import useNavigationBarTitleResetOption from '@/hooks/useNavigationBarTitleResetOption';
6+
import { SafeAreaView } from 'react-native';
7+
import ResultListView from '@/components/ResultsListView';
8+
import DatabaseNameForm from '@/components/DatabaseNameForm';
9+
import { CBLDatabaseQueryActionContainerProps } from '@/types/CBLDatabaseQueryActionContainerProps.type';
10+
import { Database } from 'cbl-reactnative';
11+
import HeaderToolbarView from '@/components/HeaderToolbarView';
12+
import { StyledTextInput } from '@/components/StyledTextInput';
13+
14+
export default function CBLDatabaseQueryActionContainer({
15+
screenTitle,
16+
handleUpdatePressed,
17+
handleExplainedPressed,
18+
handleResetPressed,
19+
children,
20+
}: CBLDatabaseQueryActionContainerProps) {
21+
const { databases } = useContext(DatabaseContext)!;
22+
const [databaseName, setDatabaseName] = useState<string>('');
23+
const [sqlQuery, setSqlQuery] = useState<string>('');
24+
const [resultMessage, setResultsMessage] = useState<string[]>([]);
25+
const navigation = useNavigation();
26+
const styles = useStyleScheme();
27+
useNavigationBarTitleResetOption(screenTitle, navigation, reset);
28+
29+
function isFormValidate(): boolean {
30+
let isValid = true;
31+
if (databaseName === '') {
32+
setResultsMessage((prev) => [
33+
...prev,
34+
'Error: Database name is required',
35+
]);
36+
isValid = false;
37+
} else if (sqlQuery === '') {
38+
setResultsMessage((prev) => [...prev, 'Error: SQL Query is required']);
39+
isValid = false;
40+
}
41+
return isValid;
42+
}
43+
44+
async function update(isExplain: boolean) {
45+
if (isFormValidate()) {
46+
try {
47+
if (
48+
databaseName in databases &&
49+
databases[databaseName] instanceof Database
50+
) {
51+
const database = databases[databaseName];
52+
let resultMessages: string[] = [];
53+
if (isExplain) {
54+
resultMessages = await handleExplainedPressed(database, sqlQuery);
55+
} else {
56+
resultMessages = await handleUpdatePressed(database, sqlQuery);
57+
}
58+
setResultsMessage((prev) => [...prev, ...resultMessages]);
59+
} else {
60+
setResultsMessage((prev) => [
61+
...prev,
62+
`Error: Database <${databaseName}> not found in context. Make sure database was opened first prior to trying to use it.`,
63+
]);
64+
}
65+
} catch (error) {
66+
// @ts-ignore
67+
setResultsMessage((prev) => [...prev, error.message]);
68+
}
69+
}
70+
}
71+
72+
function reset() {
73+
setDatabaseName('');
74+
setSqlQuery('');
75+
setResultsMessage([]);
76+
handleResetPressed();
77+
}
78+
79+
function updatePressed() {
80+
return update(false);
81+
}
82+
83+
function explainPressed() {
84+
return update(true);
85+
}
86+
87+
const icons = [
88+
{
89+
iconName: 'text-box-search',
90+
onPress: explainPressed,
91+
},
92+
{
93+
iconName: 'play',
94+
onPress: updatePressed,
95+
},
96+
];
97+
return (
98+
<SafeAreaView style={styles.container}>
99+
<DatabaseNameForm
100+
setDatabaseName={setDatabaseName}
101+
databaseName={databaseName}
102+
/>
103+
<HeaderToolbarView
104+
name="Query Editor"
105+
iconName="database-search"
106+
icons={icons}
107+
/>
108+
<StyledTextInput
109+
autoCapitalize="none"
110+
style={[
111+
styles.textInput,
112+
{ height: undefined, minHeight: 120, marginTop: 5, marginBottom: 15 },
113+
]}
114+
placeholder="SQL++ Query"
115+
onChangeText={(newText) => setSqlQuery(newText)}
116+
defaultValue={sqlQuery}
117+
multiline={true}
118+
/>
119+
{children && children}
120+
<ResultListView messages={resultMessage} />
121+
</SafeAreaView>
122+
);
123+
}

expo-example/components/ResultsListView.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ import { ResultsListViewProps } from '@/types/resultsListViewProps.type';
66
import { Divider } from '@gluestack-ui/themed';
77

88
export default function ResultListView({ messages }: ResultsListViewProps) {
9+
const date = new Date().toISOString();
910
return (
1011
<>
1112
<HeaderView name={'Results'} iconName={'information'} />
12-
<ScrollView style={{ marginLeft: 16 }}>
13+
<ScrollView style={{ marginLeft: 16, marginTop: 2 }}>
1314
{messages?.map((message, index) => (
1415
<>
15-
<Text key={`message-${index}`}>{message}</Text>
16+
<Text key={`message-${index}-${date}`}>{message}</Text>
1617
<Divider
17-
style={{ marginTop: 5, marginBottom: 10, marginLeft: 2 }}
18+
key={`divider-${index}-${date}`}
19+
style={{ marginTop: 16, marginBottom: 16, marginLeft: 2 }}
1820
/>
1921
</>
2022
))}

expo-example/hooks/useQueryNavigationSections.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function useQueryNavigationSections() {
99
title: 'SQL++ Query Editor',
1010
path: '/query/sqlPlusPlus',
1111
},
12-
{ id: 2, title: 'Query Explain', path: '/query/explain' },
12+
{ id: 2, title: 'Query Parameters', path: '/query/parameters' },
1313
{ id: 3, title: 'Live Query', path: '/query/live' },
1414
],
1515
},

expo-example/ios/expoexample.xcodeproj/project.pbxproj

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
1212
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
1313
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
14-
54E95176AF2545EA8B3EA692 /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = 812BDA730ED9445083B424A2 /* noop-file.swift */; };
14+
963CF31A941C4CD3A9357BE8 /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF70CC4CA1714790B122C123 /* noop-file.swift */; };
1515
96905EF65AED1B983A6B3ABC /* libPods-expoexample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-expoexample.a */; };
1616
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; };
1717
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
18-
DF81746DCC72DD690EFF9FD1 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = DD595584059DD6DC2D219353 /* PrivacyInfo.xcprivacy */; };
18+
F7C0828CFD6C492440B9DEBB /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4E9636163AEDF6B0BCEB0A9F /* PrivacyInfo.xcprivacy */; };
1919
/* End PBXBuildFile section */
2020

2121
/* Begin PBXFileReference section */
@@ -25,14 +25,14 @@
2525
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = expoexample/Images.xcassets; sourceTree = "<group>"; };
2626
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = expoexample/Info.plist; sourceTree = "<group>"; };
2727
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = expoexample/main.m; sourceTree = "<group>"; };
28+
4E9636163AEDF6B0BCEB0A9F /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = expoexample/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
29+
52C3A2694BF7497D9B3CD3F5 /* expoexample-Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "expoexample-Bridging-Header.h"; path = "expoexample/expoexample-Bridging-Header.h"; sourceTree = "<group>"; };
2830
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-expoexample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-expoexample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
2931
6C2E3173556A471DD304B334 /* Pods-expoexample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-expoexample.debug.xcconfig"; path = "Target Support Files/Pods-expoexample/Pods-expoexample.debug.xcconfig"; sourceTree = "<group>"; };
3032
7A4D352CD337FB3A3BF06240 /* Pods-expoexample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-expoexample.release.xcconfig"; path = "Target Support Files/Pods-expoexample/Pods-expoexample.release.xcconfig"; sourceTree = "<group>"; };
31-
812BDA730ED9445083B424A2 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "expoexample/noop-file.swift"; sourceTree = "<group>"; };
3233
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = expoexample/SplashScreen.storyboard; sourceTree = "<group>"; };
3334
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
34-
DA8DBA27B15B4D46A9CBADE9 /* expoexample-Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "expoexample-Bridging-Header.h"; path = "expoexample/expoexample-Bridging-Header.h"; sourceTree = "<group>"; };
35-
DD595584059DD6DC2D219353 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = expoexample/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
35+
CF70CC4CA1714790B122C123 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "expoexample/noop-file.swift"; sourceTree = "<group>"; };
3636
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
3737
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-expoexample/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
3838
/* End PBXFileReference section */
@@ -59,9 +59,9 @@
5959
13B07FB61A68108700A75B9A /* Info.plist */,
6060
13B07FB71A68108700A75B9A /* main.m */,
6161
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */,
62-
812BDA730ED9445083B424A2 /* noop-file.swift */,
63-
DA8DBA27B15B4D46A9CBADE9 /* expoexample-Bridging-Header.h */,
64-
DD595584059DD6DC2D219353 /* PrivacyInfo.xcprivacy */,
62+
CF70CC4CA1714790B122C123 /* noop-file.swift */,
63+
52C3A2694BF7497D9B3CD3F5 /* expoexample-Bridging-Header.h */,
64+
4E9636163AEDF6B0BCEB0A9F /* PrivacyInfo.xcprivacy */,
6565
);
6666
name = expoexample;
6767
sourceTree = "<group>";
@@ -147,13 +147,13 @@
147147
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "expoexample" */;
148148
buildPhases = (
149149
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,
150-
AFAA9126224107F0275B5D76 /* [Expo] Configure project */,
150+
15F278EF833B933853C8ECB8 /* [Expo] Configure project */,
151151
13B07F871A680F5B00A75B9A /* Sources */,
152152
13B07F8C1A680F5B00A75B9A /* Frameworks */,
153153
13B07F8E1A680F5B00A75B9A /* Resources */,
154154
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
155155
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,
156-
662020EEF1CD2A9B11BCA9E0 /* [CP] Embed Pods Frameworks */,
156+
EC3CC923263A7AEA31493FDC /* [CP] Embed Pods Frameworks */,
157157
);
158158
buildRules = (
159159
);
@@ -203,7 +203,7 @@
203203
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */,
204204
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
205205
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */,
206-
DF81746DCC72DD690EFF9FD1 /* PrivacyInfo.xcprivacy in Resources */,
206+
F7C0828CFD6C492440B9DEBB /* PrivacyInfo.xcprivacy in Resources */,
207207
);
208208
runOnlyForDeploymentPostprocessing = 0;
209209
};
@@ -247,25 +247,24 @@
247247
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
248248
showEnvVarsInLog = 0;
249249
};
250-
662020EEF1CD2A9B11BCA9E0 /* [CP] Embed Pods Frameworks */ = {
250+
15F278EF833B933853C8ECB8 /* [Expo] Configure project */ = {
251251
isa = PBXShellScriptBuildPhase;
252+
alwaysOutOfDate = 1;
252253
buildActionMask = 2147483647;
253254
files = (
254255
);
256+
inputFileListPaths = (
257+
);
255258
inputPaths = (
256-
"${PODS_ROOT}/Target Support Files/Pods-expoexample/Pods-expoexample-frameworks.sh",
257-
"${PODS_XCFRAMEWORKS_BUILD_DIR}/CouchbaseLite-Swift-Enterprise/CouchbaseLiteSwift.framework/CouchbaseLiteSwift",
258-
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
259259
);
260-
name = "[CP] Embed Pods Frameworks";
260+
name = "[Expo] Configure project";
261+
outputFileListPaths = (
262+
);
261263
outputPaths = (
262-
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CouchbaseLiteSwift.framework",
263-
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
264264
);
265265
runOnlyForDeploymentPostprocessing = 0;
266266
shellPath = /bin/sh;
267-
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-expoexample/Pods-expoexample-frameworks.sh\"\n";
268-
showEnvVarsInLog = 0;
267+
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-expoexample/expo-configure-project.sh\"\n";
269268
};
270269
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
271270
isa = PBXShellScriptBuildPhase;
@@ -297,24 +296,25 @@
297296
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-expoexample/Pods-expoexample-resources.sh\"\n";
298297
showEnvVarsInLog = 0;
299298
};
300-
AFAA9126224107F0275B5D76 /* [Expo] Configure project */ = {
299+
EC3CC923263A7AEA31493FDC /* [CP] Embed Pods Frameworks */ = {
301300
isa = PBXShellScriptBuildPhase;
302-
alwaysOutOfDate = 1;
303301
buildActionMask = 2147483647;
304302
files = (
305303
);
306-
inputFileListPaths = (
307-
);
308304
inputPaths = (
305+
"${PODS_ROOT}/Target Support Files/Pods-expoexample/Pods-expoexample-frameworks.sh",
306+
"${PODS_XCFRAMEWORKS_BUILD_DIR}/CouchbaseLite-Swift-Enterprise/CouchbaseLiteSwift.framework/CouchbaseLiteSwift",
307+
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
309308
);
310-
name = "[Expo] Configure project";
311-
outputFileListPaths = (
312-
);
309+
name = "[CP] Embed Pods Frameworks";
313310
outputPaths = (
311+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CouchbaseLiteSwift.framework",
312+
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
314313
);
315314
runOnlyForDeploymentPostprocessing = 0;
316315
shellPath = /bin/sh;
317-
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-expoexample/expo-configure-project.sh\"\n";
316+
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-expoexample/Pods-expoexample-frameworks.sh\"\n";
317+
showEnvVarsInLog = 0;
318318
};
319319
/* End PBXShellScriptBuildPhase section */
320320

@@ -326,7 +326,7 @@
326326
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
327327
13B07FC11A68108700A75B9A /* main.m in Sources */,
328328
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */,
329-
54E95176AF2545EA8B3EA692 /* noop-file.swift in Sources */,
329+
963CF31A941C4CD3A9357BE8 /* noop-file.swift in Sources */,
330330
);
331331
runOnlyForDeploymentPostprocessing = 0;
332332
};

expo-example/ios/expoexample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)