[WebIDL] Support callbacks with arbitrary return types
[WebKit-https.git] / Source / WebCore / inspector / InspectorDatabaseAgent.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2015 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "InspectorDatabaseAgent.h"
32
33 #include "Database.h"
34 #include "InspectorDatabaseResource.h"
35 #include "InstrumentingAgents.h"
36 #include "SQLError.h"
37 #include "SQLResultSet.h"
38 #include "SQLResultSetRowList.h"
39 #include "SQLStatementCallback.h"
40 #include "SQLStatementErrorCallback.h"
41 #include "SQLTransaction.h"
42 #include "SQLTransactionCallback.h"
43 #include "SQLTransactionErrorCallback.h"
44 #include "SQLValue.h"
45 #include "VoidCallback.h"
46 #include <inspector/InspectorFrontendRouter.h>
47 #include <inspector/InspectorValues.h>
48 #include <wtf/Vector.h>
49
50 using namespace Inspector;
51
52 namespace WebCore {
53
54 using ExecuteSQLCallback = Inspector::DatabaseBackendDispatcherHandler::ExecuteSQLCallback;
55
56 namespace {
57
58 void reportTransactionFailed(ExecuteSQLCallback& requestCallback, SQLError& error)
59 {
60     auto errorObject = Inspector::Protocol::Database::Error::create()
61         .setMessage(error.message())
62         .setCode(error.code())
63         .release();
64     requestCallback.sendSuccess(nullptr, nullptr, WTFMove(errorObject));
65 }
66
67 class StatementCallback final : public SQLStatementCallback {
68 public:
69     static Ref<StatementCallback> create(Ref<ExecuteSQLCallback>&& requestCallback)
70     {
71         return adoptRef(*new StatementCallback(WTFMove(requestCallback)));
72     }
73
74 private:
75     StatementCallback(Ref<ExecuteSQLCallback>&& requestCallback)
76         : m_requestCallback(WTFMove(requestCallback)) { }
77
78     CallbackResult<void> handleEvent(SQLTransaction&, SQLResultSet& resultSet) final
79     {
80         auto& rowList = resultSet.rows();
81
82         auto columnNames = Inspector::Protocol::Array<String>::create();
83         for (auto& column : rowList.columnNames())
84             columnNames->addItem(column);
85
86         auto values = Inspector::Protocol::Array<InspectorValue>::create();
87         for (auto& value : rowList.values()) {
88             auto inspectorValue = WTF::switchOn(value,
89                 [] (const std::nullptr_t&) { return InspectorValue::null(); },
90                 [] (const String& string) { return InspectorValue::create(string); },
91                 [] (double number) { return InspectorValue::create(number); }
92             );
93             values->addItem(WTFMove(inspectorValue));
94         }
95         m_requestCallback->sendSuccess(WTFMove(columnNames), WTFMove(values), nullptr);
96         return { };
97     }
98
99     Ref<ExecuteSQLCallback> m_requestCallback;
100 };
101
102 class StatementErrorCallback final : public SQLStatementErrorCallback {
103 public:
104     static Ref<StatementErrorCallback> create(Ref<ExecuteSQLCallback>&& requestCallback)
105     {
106         return adoptRef(*new StatementErrorCallback(WTFMove(requestCallback)));
107     }
108
109 private:
110     StatementErrorCallback(Ref<ExecuteSQLCallback>&& requestCallback)
111         : m_requestCallback(WTFMove(requestCallback)) { }
112
113     CallbackResult<bool> handleEvent(SQLTransaction&, SQLError& error) final
114     {
115         reportTransactionFailed(m_requestCallback.copyRef(), error);
116         return true;
117     }
118
119     Ref<ExecuteSQLCallback> m_requestCallback;
120 };
121
122 class TransactionCallback final : public SQLTransactionCallback {
123 public:
124     static Ref<TransactionCallback> create(const String& sqlStatement, Ref<ExecuteSQLCallback>&& requestCallback)
125     {
126         return adoptRef(*new TransactionCallback(sqlStatement, WTFMove(requestCallback)));
127     }
128
129 private:
130     TransactionCallback(const String& sqlStatement, Ref<ExecuteSQLCallback>&& requestCallback)
131         : m_sqlStatement(sqlStatement)
132         , m_requestCallback(WTFMove(requestCallback)) { }
133
134     CallbackResult<void> handleEvent(SQLTransaction& transaction) final
135     {
136         if (!m_requestCallback->isActive())
137             return { };
138
139         Ref<SQLStatementCallback> callback(StatementCallback::create(m_requestCallback.copyRef()));
140         Ref<SQLStatementErrorCallback> errorCallback(StatementErrorCallback::create(m_requestCallback.copyRef()));
141         transaction.executeSql(m_sqlStatement, { }, WTFMove(callback), WTFMove(errorCallback));
142         return { };
143     }
144
145     String m_sqlStatement;
146     Ref<ExecuteSQLCallback> m_requestCallback;
147 };
148
149 class TransactionErrorCallback final : public SQLTransactionErrorCallback {
150 public:
151     static Ref<TransactionErrorCallback> create(Ref<ExecuteSQLCallback>&& requestCallback)
152     {
153         return adoptRef(*new TransactionErrorCallback(WTFMove(requestCallback)));
154     }
155
156 private:
157     TransactionErrorCallback(Ref<ExecuteSQLCallback>&& requestCallback)
158         : m_requestCallback(WTFMove(requestCallback)) { }
159
160     CallbackResult<void> handleEvent(SQLError& error) final
161     {
162         reportTransactionFailed(m_requestCallback.get(), error);
163         return { };
164     }
165
166     Ref<ExecuteSQLCallback> m_requestCallback;
167 };
168
169 class TransactionSuccessCallback final : public VoidCallback {
170 public:
171     static Ref<TransactionSuccessCallback> create()
172     {
173         return adoptRef(*new TransactionSuccessCallback());
174     }
175
176     CallbackResult<void> handleEvent() final { return { }; }
177
178 private:
179     TransactionSuccessCallback() { }
180 };
181
182 } // namespace
183
184 void InspectorDatabaseAgent::didOpenDatabase(RefPtr<Database>&& database, const String& domain, const String& name, const String& version)
185 {
186     if (auto* resource = findByFileName(database->fileName())) {
187         resource->setDatabase(WTFMove(database));
188         return;
189     }
190
191     auto resource = InspectorDatabaseResource::create(WTFMove(database), domain, name, version);
192     m_resources.add(resource->id(), resource.ptr());
193     // Resources are only bound while visible.
194     if (m_enabled)
195         resource->bind(m_frontendDispatcher.get());
196 }
197
198 void InspectorDatabaseAgent::clearResources()
199 {
200     m_resources.clear();
201 }
202
203 InspectorDatabaseAgent::InspectorDatabaseAgent(WebAgentContext& context)
204     : InspectorAgentBase(ASCIILiteral("Database"), context)
205     , m_frontendDispatcher(std::make_unique<Inspector::DatabaseFrontendDispatcher>(context.frontendRouter))
206     , m_backendDispatcher(Inspector::DatabaseBackendDispatcher::create(context.backendDispatcher, this))
207 {
208     m_instrumentingAgents.setInspectorDatabaseAgent(this);
209 }
210
211 InspectorDatabaseAgent::~InspectorDatabaseAgent()
212 {
213     m_instrumentingAgents.setInspectorDatabaseAgent(nullptr);
214 }
215
216 void InspectorDatabaseAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
217 {
218 }
219
220 void InspectorDatabaseAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
221 {
222     ErrorString unused;
223     disable(unused);
224 }
225
226 void InspectorDatabaseAgent::enable(ErrorString&)
227 {
228     if (m_enabled)
229         return;
230     m_enabled = true;
231
232     for (auto& resource : m_resources.values())
233         resource->bind(m_frontendDispatcher.get());
234 }
235
236 void InspectorDatabaseAgent::disable(ErrorString&)
237 {
238     if (!m_enabled)
239         return;
240     m_enabled = false;
241 }
242
243 void InspectorDatabaseAgent::getDatabaseTableNames(ErrorString& error, const String& databaseId, RefPtr<Inspector::Protocol::Array<String>>& names)
244 {
245     if (!m_enabled) {
246         error = ASCIILiteral("Database agent is not enabled");
247         return;
248     }
249
250     names = Inspector::Protocol::Array<String>::create();
251
252     if (auto* database = databaseForId(databaseId)) {
253         for (auto& tableName : database->tableNames())
254             names->addItem(tableName);
255     }
256 }
257
258 void InspectorDatabaseAgent::executeSQL(ErrorString&, const String& databaseId, const String& query, Ref<ExecuteSQLCallback>&& requestCallback)
259 {
260     if (!m_enabled) {
261         requestCallback->sendFailure("Database agent is not enabled");
262         return;
263     }
264
265     auto* database = databaseForId(databaseId);
266     if (!database) {
267         requestCallback->sendFailure("Database not found");
268         return;
269     }
270
271     database->transaction(TransactionCallback::create(query, requestCallback.copyRef()),
272         TransactionErrorCallback::create(requestCallback.copyRef()),
273         TransactionSuccessCallback::create());
274 }
275
276 String InspectorDatabaseAgent::databaseId(Database* database)
277 {
278     for (auto& resource : m_resources) {
279         if (resource.value->database() == database)
280             return resource.key;
281     }
282     return String();
283 }
284
285 InspectorDatabaseResource* InspectorDatabaseAgent::findByFileName(const String& fileName)
286 {
287     for (auto& resource : m_resources.values()) {
288         if (resource->database()->fileName() == fileName)
289             return resource.get();
290     }
291     return nullptr;
292 }
293
294 Database* InspectorDatabaseAgent::databaseForId(const String& databaseId)
295 {
296     auto* resource = m_resources.get(databaseId);
297     if (!resource)
298         return nullptr;
299     return resource->database();
300 }
301
302 } // namespace WebCore