70 ExecutionStrategyType,
71 KeyspaceSchema<SettingsProviderType>,
72 FetchLedgerCacheType> {
75 ExecutionStrategyType,
77 FetchLedgerCacheType>;
79 using DefaultCassandraFamily::executor_;
80 using DefaultCassandraFamily::ledgerSequence_;
81 using DefaultCassandraFamily::log_;
82 using DefaultCassandraFamily::range_;
83 using DefaultCassandraFamily::schema_;
89 using DefaultCassandraFamily::DefaultCassandraFamily;
104 if (not range_.has_value()) {
106 schema_->insertLedgerRange,
false, ledgerSequence_
109 schema_->insertLedgerRange,
true, ledgerSequence_
114 schema_->updateLedgerRange.bind(ledgerSequence_,
true, ledgerSequence_ - 1)
116 log_.warn() <<
"Update failed for ledger " << ledgerSequence_;
120 log_.info() <<
"Committed ledger " << ledgerSequence_;
126 ripple::AccountID
const& issuer,
127 std::optional<std::uint32_t>
const& taxon,
128 std::uint32_t
const ledgerSequence,
129 std::uint32_t
const limit,
130 std::optional<ripple::uint256>
const& cursorIn,
131 boost::asio::yield_context yield
134 std::vector<ripple::uint256> nftIDs;
135 if (taxon.has_value()) {
137 nftIDs = fetchNFTIDsByTaxon(issuer, *taxon, limit, cursorIn, yield);
140 auto const startTaxon =
141 cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0;
142 auto const startTokenID = cursorIn.value_or(ripple::uint256(0));
144 Statement
const firstQuery = schema_->selectNFTIDsByIssuerTaxon.bind(issuer);
145 firstQuery.
bindAt(1, startTaxon);
146 firstQuery.
bindAt(2, startTokenID);
149 auto const firstRes = executor_.read(yield, firstQuery);
150 if (firstRes.has_value()) {
152 nftIDs.push_back(nftID);
155 if (nftIDs.size() < limit) {
156 auto const remainingLimit = limit - nftIDs.size();
157 Statement
const secondQuery = schema_->selectNFTsAfterTaxonKeyspaces.bind(issuer);
158 secondQuery.
bindAt(1, startTaxon);
161 auto const secondRes = executor_.read(yield, secondQuery);
162 if (secondRes.has_value()) {
164 nftIDs.push_back(nftID);
168 return populateNFTsAndCreateCursor(nftIDs, ledgerSequence, limit, yield);
184 std::vector<ripple::uint256>
186 [[maybe_unused]] std::uint32_t number,
187 [[maybe_unused]] std::uint32_t pageSize,
188 [[maybe_unused]] std::uint32_t seq,
189 [[maybe_unused]] boost::asio::yield_context yield
192 ASSERT(
false,
"Fetching account roots is not supported by the Keyspaces backend.");
197 std::vector<ripple::uint256>
199 ripple::AccountID
const& issuer,
200 std::uint32_t
const taxon,
201 std::uint32_t
const limit,
202 std::optional<ripple::uint256>
const& cursorIn,
203 boost::asio::yield_context yield
206 std::vector<ripple::uint256> nftIDs;
207 Statement
const statement = schema_->selectNFTIDsByIssuerTaxon.bind(issuer);
208 statement.
bindAt(1, taxon);
209 statement.
bindAt(2, cursorIn.value_or(ripple::uint256(0)));
212 auto const res = executor_.read(yield, statement);
213 if (res.has_value() && res->hasRows()) {
215 nftIDs.push_back(nftID);
220 std::vector<ripple::uint256>
221 fetchNFTIDsWithoutTaxon(
222 ripple::AccountID
const& issuer,
223 std::uint32_t
const limit,
224 std::optional<ripple::uint256>
const& cursorIn,
225 boost::asio::yield_context yield
228 std::vector<ripple::uint256> nftIDs;
230 auto const startTaxon =
231 cursorIn.has_value() ? ripple::nft::toUInt32(ripple::nft::getTaxon(*cursorIn)) : 0;
232 auto const startTokenID = cursorIn.value_or(ripple::uint256(0));
234 Statement firstQuery = schema_->selectNFTIDsByIssuerTaxon.
bind(issuer);
235 firstQuery.bindAt(1, startTaxon);
236 firstQuery.bindAt(2, startTokenID);
237 firstQuery.bindAt(3, Limit{limit});
239 auto const firstRes = executor_.read(yield, firstQuery);
240 if (firstRes.has_value()) {
242 nftIDs.push_back(nftID);
245 if (nftIDs.size() < limit) {
246 auto const remainingLimit = limit - nftIDs.size();
247 Statement secondQuery = schema_->selectNFTsAfterTaxonKeyspaces.
bind(issuer);
248 secondQuery.bindAt(1, startTaxon);
249 secondQuery.bindAt(2, Limit{remainingLimit});
251 auto const secondRes = executor_.read(yield, secondQuery);
252 if (secondRes.has_value()) {
254 nftIDs.push_back(nftID);
265 populateNFTsAndCreateCursor(
266 std::vector<ripple::uint256>
const& nftIDs,
267 std::uint32_t
const ledgerSequence,
268 std::uint32_t
const limit,
269 boost::asio::yield_context yield
272 if (nftIDs.empty()) {
273 LOG(log_.debug()) <<
"No rows returned";
278 if (nftIDs.size() == limit)
279 ret.cursor = nftIDs.back();
282 std::vector<Statement> selectNFTStatements;
283 selectNFTStatements.reserve(nftIDs.size());
287 std::back_inserter(selectNFTStatements),
288 [&](
auto const& nftID) {
return schema_->selectNFT.bind(nftID, ledgerSequence); }
291 std::vector<Statement> selectNFTURIStatements;
292 selectNFTURIStatements.reserve(nftIDs.size());
296 std::back_inserter(selectNFTURIStatements),
297 [&](
auto const& nftID) {
return schema_->selectNFTURI.bind(nftID, ledgerSequence); }
300 auto const nftInfos = executor_.readEach(yield, selectNFTStatements);
301 auto const nftUris = executor_.readEach(yield, selectNFTURIStatements);
304 for (
auto i = 0u; i < nftIDs.size(); ++i) {
305 if (
auto const maybeRow = nftInfos[i].
template get<uint32_t, ripple::AccountID, bool>();
306 maybeRow.has_value()) {
307 auto [seq, owner, isBurned] = *maybeRow;
308 NFT nft(nftIDs[i], seq, owner, isBurned);
309 if (
auto const maybeUri = nftUris[i].
template get<ripple::Blob>();
310 maybeUri.has_value())
312 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:125