51 ExecutionStrategyType,
52 KeyspaceSchema<SettingsProviderType>,
53 FetchLedgerCacheType> {
56 ExecutionStrategyType,
58 FetchLedgerCacheType>;
60 using DefaultCassandraFamily::executor_;
61 using DefaultCassandraFamily::ledgerSequence_;
62 using DefaultCassandraFamily::log_;
63 using DefaultCassandraFamily::range_;
64 using DefaultCassandraFamily::schema_;
70 using DefaultCassandraFamily::DefaultCassandraFamily;
85 if (not range_.has_value()) {
87 schema_->insertLedgerRange,
false, ledgerSequence_
90 schema_->insertLedgerRange,
true, ledgerSequence_
95 schema_->updateLedgerRange.bind(ledgerSequence_,
true, ledgerSequence_ - 1)
97 log_.warn() <<
"Update failed for ledger " << ledgerSequence_;
101 log_.info() <<
"Committed ledger " << ledgerSequence_;
107 ripple::AccountID
const& issuer,
108 std::optional<std::uint32_t>
const& taxon,
109 std::uint32_t
const ledgerSequence,
110 std::uint32_t
const limit,
111 std::optional<ripple::uint256>
const& cursorIn,
112 boost::asio::yield_context yield
115 std::vector<ripple::uint256> nftIDs;
116 if (taxon.has_value()) {
118 nftIDs = fetchNFTIDsByTaxon(issuer, *taxon, limit, cursorIn, yield);
121 auto const startTaxon =
122 cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0;
123 auto const startTokenID = cursorIn.value_or(ripple::uint256(0));
125 Statement
const firstQuery = schema_->selectNFTIDsByIssuerTaxon.bind(issuer);
126 firstQuery.
bindAt(1, startTaxon);
127 firstQuery.
bindAt(2, startTokenID);
130 auto const firstRes = executor_.read(yield, firstQuery);
131 if (firstRes.has_value()) {
133 nftIDs.push_back(nftID);
136 if (nftIDs.size() < limit) {
137 auto const remainingLimit = limit - nftIDs.size();
138 Statement
const secondQuery = schema_->selectNFTsAfterTaxonKeyspaces.bind(issuer);
139 secondQuery.
bindAt(1, startTaxon);
142 auto const secondRes = executor_.read(yield, secondQuery);
143 if (secondRes.has_value()) {
145 nftIDs.push_back(nftID);
149 return populateNFTsAndCreateCursor(nftIDs, ledgerSequence, limit, yield);
165 std::vector<ripple::uint256>
167 [[maybe_unused]] std::uint32_t number,
168 [[maybe_unused]] std::uint32_t pageSize,
169 [[maybe_unused]] std::uint32_t seq,
170 [[maybe_unused]] boost::asio::yield_context yield
173 ASSERT(
false,
"Fetching account roots is not supported by the Keyspaces backend.");
178 std::vector<ripple::uint256>
180 ripple::AccountID
const& issuer,
181 std::uint32_t
const taxon,
182 std::uint32_t
const limit,
183 std::optional<ripple::uint256>
const& cursorIn,
184 boost::asio::yield_context yield
187 std::vector<ripple::uint256> nftIDs;
188 Statement
const statement = schema_->selectNFTIDsByIssuerTaxon.bind(issuer);
189 statement.
bindAt(1, taxon);
190 statement.
bindAt(2, cursorIn.value_or(ripple::uint256(0)));
193 auto const res = executor_.read(yield, statement);
194 if (res.has_value() && res->hasRows()) {
196 nftIDs.push_back(nftID);
201 std::vector<ripple::uint256>
202 fetchNFTIDsWithoutTaxon(
203 ripple::AccountID
const& issuer,
204 std::uint32_t
const limit,
205 std::optional<ripple::uint256>
const& cursorIn,
206 boost::asio::yield_context yield
209 std::vector<ripple::uint256> nftIDs;
211 auto const startTaxon =
212 cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0;
213 auto const startTokenID = cursorIn.value_or(ripple::uint256(0));
215 Statement firstQuery = schema_->selectNFTIDsByIssuerTaxon.
bind(issuer);
216 firstQuery.bindAt(1, startTaxon);
217 firstQuery.bindAt(2, startTokenID);
218 firstQuery.bindAt(3, Limit{limit});
220 auto const firstRes = executor_.read(yield, firstQuery);
221 if (firstRes.has_value()) {
223 nftIDs.push_back(nftID);
226 if (nftIDs.size() < limit) {
227 auto const remainingLimit = limit - nftIDs.size();
228 Statement secondQuery = schema_->selectNFTsAfterTaxonKeyspaces.
bind(issuer);
229 secondQuery.bindAt(1, startTaxon);
230 secondQuery.bindAt(2, Limit{remainingLimit});
232 auto const secondRes = executor_.read(yield, secondQuery);
233 if (secondRes.has_value()) {
235 nftIDs.push_back(nftID);
246 populateNFTsAndCreateCursor(
247 std::vector<ripple::uint256>
const& nftIDs,
248 std::uint32_t
const ledgerSequence,
249 std::uint32_t
const limit,
250 boost::asio::yield_context yield
253 if (nftIDs.empty()) {
254 LOG(log_.debug()) <<
"No rows returned";
259 if (nftIDs.size() == limit)
260 ret.cursor = nftIDs.back();
263 std::vector<Statement> selectNFTStatements;
264 selectNFTStatements.reserve(nftIDs.size());
268 std::back_inserter(selectNFTStatements),
269 [&](
auto const& nftID) {
return schema_->selectNFT.bind(nftID, ledgerSequence); }
272 std::vector<Statement> selectNFTURIStatements;
273 selectNFTURIStatements.reserve(nftIDs.size());
277 std::back_inserter(selectNFTURIStatements),
278 [&](
auto const& nftID) {
return schema_->selectNFTURI.bind(nftID, ledgerSequence); }
281 auto const nftInfos = executor_.readEach(yield, selectNFTStatements);
282 auto const nftUris = executor_.readEach(yield, selectNFTURIStatements);
285 for (
auto i = 0u; i < nftIDs.size(); ++i) {
286 if (
auto const maybeRow = nftInfos[i].
template get<uint32_t, ripple::AccountID, bool>();
287 maybeRow.has_value()) {
288 auto [seq, owner, isBurned] = *maybeRow;
289 NFT nft(nftIDs[i], seq, owner, isBurned);
290 if (
auto const maybeUri = nftUris[i].
template get<ripple::Blob>();
291 maybeUri.has_value())
293 ret.nfts.push_back(nft);
NFTsAndCursor fetchNFTsByIssuer(ripple::AccountID const &issuer, std::optional< std::uint32_t > const &taxon, std::uint32_t const ledgerSequence, std::uint32_t const limit, std::optional< ripple::uint256 > const &cursorIn, boost::asio::yield_context yield) const override
Fetches all NFTs issued by a given address.
Definition KeyspaceBackend.hpp:106