src: cleaned up StorageAccess
This commit is contained in:
@@ -460,37 +460,37 @@ void PersistentStorage::optimizeMemory()
|
||||
m_sqliteStorage.setVersion();
|
||||
}
|
||||
|
||||
Id PersistentStorage::getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const
|
||||
Id PersistentStorage::getNodeIdForFileNode(const FilePath& filePath) const
|
||||
{
|
||||
return m_sqliteStorage.getFileByPath(filePath.str()).id;
|
||||
}
|
||||
|
||||
Id PersistentStorage::getNodeIdForNameHierarchy(const NameHierarchy& nameHierarchy) const
|
||||
{
|
||||
return m_sqliteStorage.getNodeBySerializedName(NameHierarchy::serialize(nameHierarchy)).id;
|
||||
}
|
||||
|
||||
Id PersistentStorage::getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy
|
||||
) const
|
||||
std::vector<Id> PersistentStorage::getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const
|
||||
{
|
||||
Id sourceId = getIdForNodeWithNameHierarchy(fromNameHierarchy);
|
||||
Id targetId = getIdForNodeWithNameHierarchy(toNameHierarchy);
|
||||
return m_sqliteStorage.getEdgeBySourceTargetType(sourceId, targetId, type).id;
|
||||
std::vector<Id> nodeIds;
|
||||
for (const NameHierarchy& name : nameHierarchies)
|
||||
{
|
||||
Id nodeId = getNodeIdForNameHierarchy(name);
|
||||
if (nodeId)
|
||||
{
|
||||
nodeIds.push_back(nodeId);
|
||||
}
|
||||
}
|
||||
return nodeIds;
|
||||
}
|
||||
|
||||
StorageEdge PersistentStorage::getEdgeById(Id edgeId) const
|
||||
{
|
||||
return m_sqliteStorage.getEdgeById(edgeId);
|
||||
}
|
||||
|
||||
NameHierarchy PersistentStorage::getNameHierarchyForNodeWithId(Id nodeId) const
|
||||
NameHierarchy PersistentStorage::getNameHierarchyForNodeId(Id nodeId) const
|
||||
{
|
||||
TRACE();
|
||||
|
||||
return NameHierarchy::deserialize(m_sqliteStorage.getFirstById<StorageNode>(nodeId).serializedName);
|
||||
}
|
||||
|
||||
Node::NodeType PersistentStorage::getNodeTypeForNodeWithId(Id nodeId) const
|
||||
{
|
||||
return Node::intToType(m_sqliteStorage.getFirstById<StorageNode>(nodeId).type);
|
||||
}
|
||||
|
||||
std::vector<NameHierarchy> PersistentStorage::getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const
|
||||
{
|
||||
std::vector<NameHierarchy> nameHierarchies;
|
||||
@@ -501,18 +501,33 @@ std::vector<NameHierarchy> PersistentStorage::getNameHierarchiesForNodeIds(const
|
||||
return nameHierarchies;
|
||||
}
|
||||
|
||||
std::vector<Id> PersistentStorage::getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const
|
||||
Node::NodeType PersistentStorage::getNodeTypeForNodeWithId(Id nodeId) const
|
||||
{
|
||||
std::vector<Id> nodeIds;
|
||||
for (const NameHierarchy& name : nameHierarchies)
|
||||
{
|
||||
Id nodeId = getIdForNodeWithNameHierarchy(name);
|
||||
if (nodeId)
|
||||
{
|
||||
nodeIds.push_back(nodeId);
|
||||
}
|
||||
}
|
||||
return nodeIds;
|
||||
return Node::intToType(m_sqliteStorage.getFirstById<StorageNode>(nodeId).type);
|
||||
}
|
||||
|
||||
bool PersistentStorage::checkNodeExistsByName(const std::string& serializedName) const
|
||||
{
|
||||
return m_sqliteStorage.checkNodeExistsByName(serializedName);
|
||||
}
|
||||
|
||||
Id PersistentStorage::getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy
|
||||
) const
|
||||
{
|
||||
Id sourceId = getNodeIdForNameHierarchy(fromNameHierarchy);
|
||||
Id targetId = getNodeIdForNameHierarchy(toNameHierarchy);
|
||||
return m_sqliteStorage.getEdgeBySourceTargetType(sourceId, targetId, type).id;
|
||||
}
|
||||
|
||||
StorageEdge PersistentStorage::getEdgeById(Id edgeId) const
|
||||
{
|
||||
return m_sqliteStorage.getEdgeById(edgeId);
|
||||
}
|
||||
|
||||
bool PersistentStorage::checkEdgeExists(Id edgeId) const
|
||||
{
|
||||
return m_sqliteStorage.checkEdgeExists(edgeId);
|
||||
}
|
||||
|
||||
std::shared_ptr<TokenLocationCollection> PersistentStorage::getFullTextSearchLocations(
|
||||
@@ -1019,11 +1034,6 @@ std::vector<Id> PersistentStorage::getActiveTokenIdsForId(Id tokenId, Id* declar
|
||||
return activeTokenIds;
|
||||
}
|
||||
|
||||
bool PersistentStorage::checkEdgeExists(Id edgeId) const
|
||||
{
|
||||
return m_sqliteStorage.checkEdgeExists(edgeId);
|
||||
}
|
||||
|
||||
std::vector<Id> PersistentStorage::getNodeIdsForLocationIds(const std::vector<Id>& locationIds) const
|
||||
{
|
||||
TRACE();
|
||||
@@ -1075,33 +1085,6 @@ std::vector<Id> PersistentStorage::getNodeIdsForLocationIds(const std::vector<Id
|
||||
return utility::toVector(edgeIds);
|
||||
}
|
||||
|
||||
std::vector<Id> PersistentStorage::getLocalSymbolIdsForLocationIds(const std::vector<Id>& locationIds) const
|
||||
{
|
||||
std::set<Id> localSymbolIds;
|
||||
|
||||
for (const StorageOccurrence& occurrence: m_sqliteStorage.getOccurrencesForLocationIds(locationIds))
|
||||
{
|
||||
Id elementId = occurrence.elementId;
|
||||
|
||||
if (m_sqliteStorage.getFirstById<StorageNode>(elementId).id == 0 && m_sqliteStorage.getFirstById<StorageEdge>(elementId).id == 0)
|
||||
{
|
||||
localSymbolIds.insert(elementId);
|
||||
}
|
||||
}
|
||||
|
||||
return utility::toVector(localSymbolIds);
|
||||
}
|
||||
|
||||
bool PersistentStorage::checkNodeExistsByName(const std::string& serializedName) const
|
||||
{
|
||||
return m_sqliteStorage.checkNodeExistsByName(serializedName);
|
||||
}
|
||||
|
||||
Id PersistentStorage::getTokenIdForFileNode(const FilePath& filePath) const
|
||||
{
|
||||
return m_sqliteStorage.getFileByPath(filePath.str()).id;
|
||||
}
|
||||
|
||||
std::shared_ptr<TokenLocationCollection> PersistentStorage::getTokenLocationsForTokenIds(
|
||||
const std::vector<Id>& tokenIds) const
|
||||
{
|
||||
|
||||
@@ -96,16 +96,20 @@ public:
|
||||
void optimizeMemory();
|
||||
|
||||
// StorageAccess implementation
|
||||
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||
virtual Id getNodeIdForFileNode(const FilePath& filePath) const;
|
||||
virtual Id getNodeIdForNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||
virtual std::vector<Id> getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const;
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeId(Id nodeId) const;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const;
|
||||
|
||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id nodeId) const;
|
||||
virtual bool checkNodeExistsByName(const std::string& serializedName) const;
|
||||
|
||||
virtual Id getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const;
|
||||
virtual StorageEdge getEdgeById(Id edgeId) const;
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeWithId(Id nodeId) const;
|
||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id nodeId) const;
|
||||
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const;
|
||||
virtual std::vector<Id> getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const;
|
||||
virtual bool checkEdgeExists(Id edgeId) const;
|
||||
|
||||
virtual std::shared_ptr<TokenLocationCollection> getFullTextSearchLocations(
|
||||
const std::string& searchTerm, bool caseSensitive) const;
|
||||
@@ -119,14 +123,7 @@ public:
|
||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds, bool* isActiveNamespace = nullptr) const;
|
||||
|
||||
virtual std::vector<Id> getActiveTokenIdsForId(Id tokenId, Id* declarationId) const;
|
||||
|
||||
virtual bool checkEdgeExists(Id edgeId) const;
|
||||
|
||||
virtual std::vector<Id> getNodeIdsForLocationIds(const std::vector<Id>& locationIds) const;
|
||||
virtual std::vector<Id> getLocalSymbolIdsForLocationIds(const std::vector<Id>& locationIds) const;
|
||||
virtual bool checkNodeExistsByName(const std::string& serializedName) const;
|
||||
|
||||
virtual Id getTokenIdForFileNode(const FilePath& filePath) const;
|
||||
|
||||
virtual std::shared_ptr<TokenLocationCollection> getTokenLocationsForTokenIds(
|
||||
const std::vector<Id>& tokenIds
|
||||
@@ -176,9 +173,7 @@ private:
|
||||
void addNodesToGraph(const std::vector<Id>& nodeIds, Graph* graph) const;
|
||||
void addEdgesToGraph(const std::vector<Id>& edgeIds, Graph* graph) const;
|
||||
void addNodesWithChildrenAndEdgesToGraph(
|
||||
const std::vector<Id>& nodeIds,
|
||||
const std::vector<Id>& edgeIds, Graph* graph
|
||||
) const;
|
||||
const std::vector<Id>& nodeIds, const std::vector<Id>& edgeIds, Graph* graph) const;
|
||||
|
||||
void addAggregationEdgesToGraph(const Id nodeId, const std::vector<StorageEdge>& edgesToAggregate, Graph* graph) const;
|
||||
void addComponentAccessToGraph(Graph* graph) const;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "data/bookmark/BookmarkCategory.h"
|
||||
#include "data/bookmark/EdgeBookmark.h"
|
||||
#include "data/bookmark/NodeBookmark.h"
|
||||
#include "data/parser/ParseLocation.h"
|
||||
#include "data/graph/Node.h"
|
||||
#include "data/search/SearchMatch.h"
|
||||
#include "data/ErrorCountInfo.h"
|
||||
@@ -26,26 +25,26 @@ class TextAccess;
|
||||
class TokenLocation;
|
||||
class TokenLocationCollection;
|
||||
class TokenLocationFile;
|
||||
class TimePoint;
|
||||
|
||||
class StorageAccess
|
||||
{
|
||||
public:
|
||||
virtual ~StorageAccess();
|
||||
|
||||
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const = 0;
|
||||
virtual Id getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const = 0;
|
||||
virtual StorageEdge getEdgeById(Id edgeId) const = 0;
|
||||
virtual Id getNodeIdForFileNode(const FilePath& filePath) const = 0;
|
||||
virtual Id getNodeIdForNameHierarchy(const NameHierarchy& nameHierarchy) const = 0;
|
||||
virtual std::vector<Id> getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const = 0;
|
||||
|
||||
virtual bool checkEdgeExists(Id edgeId) const = 0;
|
||||
virtual NameHierarchy getNameHierarchyForNodeId(Id id) const = 0;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const = 0;
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeWithId(Id id) const = 0;
|
||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id id) const = 0;
|
||||
virtual bool checkNodeExistsByName(const std::string& serializedName) const = 0;
|
||||
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const = 0;
|
||||
virtual std::vector<Id> getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const = 0;
|
||||
virtual Id getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const = 0;
|
||||
virtual StorageEdge getEdgeById(Id edgeId) const = 0;
|
||||
virtual bool checkEdgeExists(Id edgeId) const = 0;
|
||||
|
||||
virtual std::shared_ptr<TokenLocationCollection> getFullTextSearchLocations(
|
||||
const std::string& searchTerm, bool caseSensitive) const = 0;
|
||||
@@ -56,11 +55,7 @@ public:
|
||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds, bool* isActiveNamespace = nullptr) const = 0;
|
||||
|
||||
virtual std::vector<Id> getActiveTokenIdsForId(Id tokenId, Id* declarationId) const = 0;
|
||||
|
||||
virtual std::vector<Id> getNodeIdsForLocationIds(const std::vector<Id>& locationIds) const = 0;
|
||||
virtual std::vector<Id> getLocalSymbolIdsForLocationIds(const std::vector<Id>& locationIds) const = 0;
|
||||
|
||||
virtual Id getTokenIdForFileNode(const FilePath& filePath) const = 0;
|
||||
|
||||
virtual std::shared_ptr<TokenLocationCollection> getTokenLocationsForTokenIds(
|
||||
const std::vector<Id>& tokenIds) const = 0;
|
||||
|
||||
@@ -36,16 +36,72 @@ void StorageAccessProxy::setSubject(StorageAccess* subject)
|
||||
setErrorFilter(m_errorFilter);
|
||||
}
|
||||
|
||||
Id StorageAccessProxy::getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const
|
||||
Id StorageAccessProxy::getNodeIdForFileNode(const FilePath& filePath) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getIdForNodeWithNameHierarchy(nameHierarchy);
|
||||
return m_subject->getNodeIdForFileNode(filePath);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Id StorageAccessProxy::getNodeIdForNameHierarchy(const NameHierarchy& nameHierarchy) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNodeIdForNameHierarchy(nameHierarchy);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<Id> StorageAccessProxy::getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNodeIdsForNameHierarchies(nameHierarchies);
|
||||
}
|
||||
return std::vector<Id>();
|
||||
}
|
||||
|
||||
NameHierarchy StorageAccessProxy::getNameHierarchyForNodeId(Id id) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNameHierarchyForNodeId(id);
|
||||
}
|
||||
|
||||
return NameHierarchy();
|
||||
}
|
||||
|
||||
std::vector<NameHierarchy> StorageAccessProxy::getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNameHierarchiesForNodeIds(nodeIds);
|
||||
}
|
||||
return std::vector<NameHierarchy>();
|
||||
}
|
||||
|
||||
Node::NodeType StorageAccessProxy::getNodeTypeForNodeWithId(Id id) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNodeTypeForNodeWithId(id);
|
||||
}
|
||||
return Node::NODE_NON_INDEXED;
|
||||
}
|
||||
|
||||
bool StorageAccessProxy::checkNodeExistsByName(const std::string& serializedName) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->checkNodeExistsByName(serializedName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Id StorageAccessProxy::getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy
|
||||
) const {
|
||||
@@ -77,52 +133,6 @@ bool StorageAccessProxy::checkEdgeExists(Id edgeId) const
|
||||
return false;
|
||||
}
|
||||
|
||||
NameHierarchy StorageAccessProxy::getNameHierarchyForNodeWithId(Id id) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNameHierarchyForNodeWithId(id);
|
||||
}
|
||||
|
||||
return NameHierarchy();
|
||||
}
|
||||
|
||||
Node::NodeType StorageAccessProxy::getNodeTypeForNodeWithId(Id id) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNodeTypeForNodeWithId(id);
|
||||
}
|
||||
return Node::NODE_NON_INDEXED;
|
||||
}
|
||||
|
||||
bool StorageAccessProxy::checkNodeExistsByName(const std::string& serializedName) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->checkNodeExistsByName(serializedName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<NameHierarchy> StorageAccessProxy::getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNameHierarchiesForNodeIds(nodeIds);
|
||||
}
|
||||
return std::vector<NameHierarchy>();
|
||||
}
|
||||
|
||||
std::vector<Id> StorageAccessProxy::getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getNodeIdsForNameHierarchies(nameHierarchies);
|
||||
}
|
||||
return std::vector<Id>();
|
||||
}
|
||||
|
||||
std::shared_ptr<TokenLocationCollection> StorageAccessProxy::getFullTextSearchLocations(
|
||||
const std::string &searchTerm, bool caseSensitive) const
|
||||
{
|
||||
@@ -194,26 +204,6 @@ std::vector<Id> StorageAccessProxy::getNodeIdsForLocationIds(const std::vector<I
|
||||
return std::vector<Id>();
|
||||
}
|
||||
|
||||
std::vector<Id> StorageAccessProxy::getLocalSymbolIdsForLocationIds(const std::vector<Id>& locationIds) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getLocalSymbolIdsForLocationIds(locationIds);
|
||||
}
|
||||
|
||||
return std::vector<Id>();
|
||||
}
|
||||
|
||||
Id StorageAccessProxy::getTokenIdForFileNode(const FilePath& filePath) const
|
||||
{
|
||||
if (hasSubject())
|
||||
{
|
||||
return m_subject->getTokenIdForFileNode(filePath);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<TokenLocationCollection> StorageAccessProxy::getTokenLocationsForTokenIds(
|
||||
const std::vector<Id>& tokenIds) const
|
||||
{
|
||||
|
||||
@@ -18,19 +18,20 @@ public:
|
||||
void setSubject(StorageAccess* subject);
|
||||
|
||||
// StorageAccess implementation
|
||||
virtual Id getIdForNodeWithNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||
virtual Id getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const;
|
||||
virtual StorageEdge getEdgeById(Id edgeId) const;
|
||||
virtual Id getNodeIdForFileNode(const FilePath& filePath) const;
|
||||
virtual Id getNodeIdForNameHierarchy(const NameHierarchy& nameHierarchy) const;
|
||||
virtual std::vector<Id> getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const;
|
||||
|
||||
virtual bool checkEdgeExists(Id edgeId) const;
|
||||
virtual NameHierarchy getNameHierarchyForNodeId(Id id) const;
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const;
|
||||
|
||||
virtual NameHierarchy getNameHierarchyForNodeWithId(Id id) const;
|
||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id id) const;
|
||||
virtual bool checkNodeExistsByName(const std::string& serializedName) const;
|
||||
|
||||
virtual std::vector<NameHierarchy> getNameHierarchiesForNodeIds(const std::vector<Id> nodeIds) const;
|
||||
virtual std::vector<Id> getNodeIdsForNameHierarchies(const std::vector<NameHierarchy> nameHierarchies) const;
|
||||
virtual Id getIdForEdge(
|
||||
Edge::EdgeType type, const NameHierarchy& fromNameHierarchy, const NameHierarchy& toNameHierarchy) const;
|
||||
virtual StorageEdge getEdgeById(Id edgeId) const;
|
||||
virtual bool checkEdgeExists(Id edgeId) const;
|
||||
|
||||
virtual std::shared_ptr<TokenLocationCollection> getFullTextSearchLocations(
|
||||
const std::string& searchTerm, bool caseSensitive) const;
|
||||
@@ -41,11 +42,7 @@ public:
|
||||
virtual std::shared_ptr<Graph> getGraphForActiveTokenIds(const std::vector<Id>& tokenIds, bool* isActiveNamespace = nullptr) const;
|
||||
|
||||
virtual std::vector<Id> getActiveTokenIdsForId(Id tokenId, Id* declarationId) const;
|
||||
|
||||
virtual std::vector<Id> getNodeIdsForLocationIds(const std::vector<Id>& locationIds) const;
|
||||
virtual std::vector<Id> getLocalSymbolIdsForLocationIds(const std::vector<Id>& locationIds) const;
|
||||
|
||||
virtual Id getTokenIdForFileNode(const FilePath& filePath) const;
|
||||
|
||||
virtual std::shared_ptr<TokenLocationCollection> getTokenLocationsForTokenIds(
|
||||
const std::vector<Id>& tokenIds
|
||||
|
||||
Reference in New Issue
Block a user