/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_FS_PARENT_RESULTSTATEMENT_H_
#define DOM_FS_PARENT_RESULTSTATEMENT_H_
#include "FileSystemParentTypes.h"
#include "mozIStorageStatement.h"
#include "mozilla/dom/FileSystemTypes.h"
#include "mozilla/dom/quota/QuotaCommon.h"
#include "mozilla/dom/quota/ResultExtensions.h"
#include "nsCOMPtr.h"
#include "nsString.h"
class mozIStorageConnection;
namespace mozilla::dom::fs {
using Column = uint32_t;
using ResultConnection = nsCOMPtr<mozIStorageConnection>;
/**
* @brief ResultStatement
* - provides error monad Result<T, E> compatible interface to the lower level
* error code-based statement implementation in order to enable remote
* debugging with error stack traces
* - converts between OPFS internal data types and the generic data types of
* the lower level implementation
* - provides a customization point for requests aimed at the lower level
* implementation allowing for example to remap errors or implement mocks
*/
class ResultStatement {
public:
using underlying_t = nsCOMPtr<mozIStorageStatement>;
explicit ResultStatement(underlying_t aStmt) : mStmt(std::move(aStmt)) {}
ResultStatement(
const ResultStatement& aOther)
: ResultStatement(aOther.mStmt) {}
ResultStatement(ResultStatement&& aOther) noexcept
: ResultStatement(std::move(aOther.mStmt)) {}
ResultStatement&
operator=(
const ResultStatement& aOther) =
default;
ResultStatement&
operator=(ResultStatement&& aOther) noexcept {
mStmt = std::move(aOther.mStmt);
return *
this;
}
static Result<ResultStatement, QMResult> Create(
const ResultConnection& aConnection,
const nsACString& aSQLStatement);
// XXX Consider moving all these "inline" methods into a separate file
// called ResultStatementInlines.h. ResultStatement.h wouldn't have to then
// include ResultExtensions.h, QuotaCommon.h and mozIStorageStatement.h
// which are quite large and should be preferable only included from cpp
// files or special headers like ResultStatementInlines.h. So in the end,
// other headers would include ResultStatement.h only and other cpp files
// would include ResultStatementInlines.h. See also IndedexDababase.h and
// IndexedDatabaseInlines.h to see how it's done.
inline nsresult BindEntryIdByName(
const nsACString& aField,
const EntryId& aValue) {
return mStmt->BindUTF8StringAsBlobByName(aField, aValue);
}
inline nsresult BindFileIdByName(
const nsACString& aField,
const FileId& aValue) {
return mStmt->BindUTF8StringAsBlobByName(aField, aValue.Value());
}
inline nsresult BindContentTypeByName(
const nsACString& aField,
const ContentType& aValue) {
if (aValue.IsVoid()) {
return mStmt->BindNullByName(aField);
}
return mStmt->BindUTF8StringByName(aField, aValue);
}
inline nsresult BindNameByName(
const nsACString& aField,
const Name& aValue) {
return mStmt->BindStringAsBlobByName(aField, aValue);
}
inline nsresult BindPageNumberByName(
const nsACString& aField,
PageNumber aValue) {
return mStmt->BindInt32ByName(aField, aValue);
}
inline nsresult BindUsageByName(
const nsACString& aField, Usage aValue) {
return mStmt->BindInt64ByName(aField, aValue);
}
inline nsresult BindBooleanByName(
const nsACString& aField,
bool aValue) {
return mStmt->BindInt32ByName(aField, aValue ? 1 : 0);
}
inline Result<
bool, QMResult> GetBooleanByColumn(Column aColumn) {
int32_t value = 0;
QM_TRY(QM_TO_RESULT(mStmt->GetInt32(aColumn, &value)));
return 0 != value;
}
inline Result<ContentType, QMResult> GetContentTypeByColumn(Column aColumn) {
ContentType value;
QM_TRY(QM_TO_RESULT(mStmt->GetUTF8String(aColumn, value)));
return value;
}
inline Result<EntryId, QMResult> GetEntryIdByColumn(Column aColumn) {
EntryId value;
QM_TRY(QM_TO_RESULT(mStmt->GetBlobAsUTF8String(aColumn, value)));
return value;
}
inline Result<FileId, QMResult> GetFileIdByColumn(Column aColumn) {
nsCString value;
QM_TRY(QM_TO_RESULT(mStmt->GetBlobAsUTF8String(aColumn, value)));
return FileId(std::move(value));
}
inline Result<Name, QMResult> GetNameByColumn(Column aColumn) {
Name value;
QM_TRY(QM_TO_RESULT(mStmt->GetBlobAsString(aColumn, value)));
return value;
}
inline Result<Usage, QMResult> GetUsageByColumn(Column aColumn) {
Usage value = 0;
QM_TRY(QM_TO_RESULT(mStmt->GetInt64(aColumn, &value)));
return value;
}
inline bool IsNullByColumn(Column aColumn)
const {
bool value = mStmt->IsNull(aColumn);
return value;
}
inline nsresult Execute() {
return mStmt->Execute(); }
inline Result<
bool, QMResult> ExecuteStep() {
bool hasEntries =
false;
QM_TRY(QM_TO_RESULT(mStmt->ExecuteStep(&hasEntries)));
return hasEntries;
}
inline Result<
bool, QMResult> YesOrNoQuery() {
bool hasEntries =
false;
QM_TRY(QM_TO_RESULT(mStmt->ExecuteStep(&hasEntries)));
MOZ_ALWAYS_TRUE(hasEntries);
return GetBooleanByColumn(0u);
}
private:
underlying_t mStmt;
};
}
// namespace mozilla::dom::fs
#endif // DOM_FS_PARENT_RESULTSTATEMENT_H_