Search in sources :

Example 1 with Bound

use of com.google.firebase.firestore.core.Bound in project firebase-android-sdk by firebase.

the class Query method boundFromDocumentSnapshot.

/**
 * Create a Bound from a query given the document.
 *
 * <p>Note that the Bound will always include the key of the document and so only the provided
 * document will compare equal to the returned position.
 *
 * <p>Will throw if the document does not contain all fields of the order by of the query or if
 * any of the fields in the order by are an uncommitted server timestamp.
 */
private Bound boundFromDocumentSnapshot(String methodName, DocumentSnapshot snapshot, boolean inclusive) {
    checkNotNull(snapshot, "Provided snapshot must not be null.");
    if (!snapshot.exists()) {
        throw new IllegalArgumentException("Can't use a DocumentSnapshot for a document that doesn't exist for " + methodName + "().");
    }
    Document document = snapshot.getDocument();
    List<Value> components = new ArrayList<>();
    // orders), multiple documents could match the position, yielding duplicate results.
    for (OrderBy orderBy : query.getOrderBy()) {
        if (orderBy.getField().equals(com.google.firebase.firestore.model.FieldPath.KEY_PATH)) {
            components.add(Values.refValue(firestore.getDatabaseId(), document.getKey()));
        } else {
            Value value = document.getField(orderBy.getField());
            if (ServerTimestamps.isServerTimestamp(value)) {
                throw new IllegalArgumentException("Invalid query. You are trying to start or end a query using a document for which " + "the field '" + orderBy.getField() + "' is an uncommitted server timestamp. (Since the value of this field is " + "unknown, you cannot start/end a query with it.)");
            } else if (value != null) {
                components.add(value);
            } else {
                throw new IllegalArgumentException("Invalid query. You are trying to start or end a query using a document for which " + "the field '" + orderBy.getField() + "' (used as the orderBy) does not exist.");
            }
        }
    }
    return new Bound(components, inclusive);
}
Also used : OrderBy(com.google.firebase.firestore.core.OrderBy) Value(com.google.firestore.v1.Value) ArrayValue(com.google.firestore.v1.ArrayValue) ArrayList(java.util.ArrayList) Bound(com.google.firebase.firestore.core.Bound) Document(com.google.firebase.firestore.model.Document)

Example 2 with Bound

use of com.google.firebase.firestore.core.Bound in project firebase-android-sdk by firebase.

the class Query method boundFromFields.

/**
 * Converts a list of field values to Bound.
 */
private Bound boundFromFields(String methodName, Object[] values, boolean inclusive) {
    // Use explicit order by's because it has to match the query the user made
    List<OrderBy> explicitOrderBy = query.getExplicitOrderBy();
    if (values.length > explicitOrderBy.size()) {
        throw new IllegalArgumentException("Too many arguments provided to " + methodName + "(). The number of arguments must be less " + "than or equal to the number of orderBy() clauses.");
    }
    List<Value> components = new ArrayList<>();
    for (int i = 0; i < values.length; i++) {
        Object rawValue = values[i];
        OrderBy orderBy = explicitOrderBy.get(i);
        if (orderBy.getField().equals(com.google.firebase.firestore.model.FieldPath.KEY_PATH)) {
            if (!(rawValue instanceof String)) {
                throw new IllegalArgumentException("Invalid query. Expected a string for document ID in " + methodName + "(), but got " + rawValue + ".");
            }
            String documentId = (String) rawValue;
            if (!query.isCollectionGroupQuery() && documentId.contains("/")) {
                throw new IllegalArgumentException("Invalid query. When querying a collection and ordering by FieldPath.documentId(), " + "the value passed to " + methodName + "() must be a plain document ID, but '" + documentId + "' contains a slash.");
            }
            ResourcePath path = query.getPath().append(ResourcePath.fromString(documentId));
            if (!DocumentKey.isDocumentKey(path)) {
                throw new IllegalArgumentException("Invalid query. When querying a collection group and ordering by " + "FieldPath.documentId(), the value passed to " + methodName + "() must result in a valid document path, but '" + path + "' is not because it contains an odd number of segments.");
            }
            DocumentKey key = DocumentKey.fromPath(path);
            components.add(Values.refValue(firestore.getDatabaseId(), key));
        } else {
            Value wrapped = firestore.getUserDataReader().parseQueryValue(rawValue);
            components.add(wrapped);
        }
    }
    return new Bound(components, inclusive);
}
Also used : OrderBy(com.google.firebase.firestore.core.OrderBy) ResourcePath(com.google.firebase.firestore.model.ResourcePath) Value(com.google.firestore.v1.Value) ArrayValue(com.google.firestore.v1.ArrayValue) ArrayList(java.util.ArrayList) DocumentKey(com.google.firebase.firestore.model.DocumentKey) Bound(com.google.firebase.firestore.core.Bound)

Example 3 with Bound

use of com.google.firebase.firestore.core.Bound in project firebase-android-sdk by firebase.

the class RemoteSerializer method decodeQueryTarget.

public com.google.firebase.firestore.core.Target decodeQueryTarget(String parent, StructuredQuery query) {
    ResourcePath path = decodeQueryPath(parent);
    String collectionGroup = null;
    int fromCount = query.getFromCount();
    if (fromCount > 0) {
        hardAssert(fromCount == 1, "StructuredQuery.from with more than one collection is not supported.");
        CollectionSelector from = query.getFrom(0);
        if (from.getAllDescendants()) {
            collectionGroup = from.getCollectionId();
        } else {
            path = path.append(from.getCollectionId());
        }
    }
    List<Filter> filterBy;
    if (query.hasWhere()) {
        filterBy = decodeFilters(query.getWhere());
    } else {
        filterBy = Collections.emptyList();
    }
    List<OrderBy> orderBy;
    int orderByCount = query.getOrderByCount();
    if (orderByCount > 0) {
        orderBy = new ArrayList<>(orderByCount);
        for (int i = 0; i < orderByCount; i++) {
            orderBy.add(decodeOrderBy(query.getOrderBy(i)));
        }
    } else {
        orderBy = Collections.emptyList();
    }
    long limit = com.google.firebase.firestore.core.Target.NO_LIMIT;
    if (query.hasLimit()) {
        limit = query.getLimit().getValue();
    }
    Bound startAt = null;
    if (query.hasStartAt()) {
        startAt = new Bound(query.getStartAt().getValuesList(), query.getStartAt().getBefore());
    }
    Bound endAt = null;
    if (query.hasEndAt()) {
        endAt = new Bound(query.getEndAt().getValuesList(), !query.getEndAt().getBefore());
    }
    return new com.google.firebase.firestore.core.Target(path, collectionGroup, filterBy, orderBy, limit, startAt, endAt);
}
Also used : OrderBy(com.google.firebase.firestore.core.OrderBy) Bound(com.google.firebase.firestore.core.Bound) DocumentsTarget(com.google.firestore.v1.Target.DocumentsTarget) Target(com.google.firestore.v1.Target) QueryTarget(com.google.firestore.v1.Target.QueryTarget) ResourcePath(com.google.firebase.firestore.model.ResourcePath) CollectionSelector(com.google.firestore.v1.StructuredQuery.CollectionSelector) FieldFilter(com.google.firebase.firestore.core.FieldFilter) CompositeFilter(com.google.firestore.v1.StructuredQuery.CompositeFilter) UnaryFilter(com.google.firestore.v1.StructuredQuery.UnaryFilter) Filter(com.google.firebase.firestore.core.Filter)

Example 4 with Bound

use of com.google.firebase.firestore.core.Bound in project firebase-android-sdk by firebase.

the class BundleSerializer method decodeBundledQuery.

private BundledQuery decodeBundledQuery(JSONObject bundledQuery) throws JSONException {
    JSONObject structuredQuery = bundledQuery.getJSONObject("structuredQuery");
    verifyNoSelect(structuredQuery);
    ResourcePath parent = decodeName(bundledQuery.getString("parent"));
    JSONArray from = structuredQuery.getJSONArray("from");
    verifyCollectionSelector(from);
    JSONObject collectionSelector = from.getJSONObject(0);
    boolean allDescendants = collectionSelector.optBoolean("allDescendants", false);
    @Nullable String collectionGroup = null;
    if (allDescendants) {
        collectionGroup = collectionSelector.getString("collectionId");
    } else {
        parent = parent.append(collectionSelector.getString("collectionId"));
    }
    List<Filter> filters = decodeWhere(structuredQuery.optJSONObject("where"));
    List<OrderBy> orderBys = decodeOrderBy(structuredQuery.optJSONArray("orderBy"));
    @Nullable Bound startAt = decodeStartAtBound(structuredQuery.optJSONObject("startAt"));
    @Nullable Bound endAt = decodeEndAtBound(structuredQuery.optJSONObject("endAt"));
    verifyNoOffset(structuredQuery);
    int limit = decodeLimit(structuredQuery);
    Query.LimitType limitType = decodeLimitType(bundledQuery);
    return new BundledQuery(new Target(parent, collectionGroup, filters, orderBys, limit, startAt, endAt), limitType);
}
Also used : OrderBy(com.google.firebase.firestore.core.OrderBy) Query(com.google.firebase.firestore.core.Query) JSONArray(org.json.JSONArray) Bound(com.google.firebase.firestore.core.Bound) ByteString(com.google.protobuf.ByteString) Target(com.google.firebase.firestore.core.Target) ResourcePath(com.google.firebase.firestore.model.ResourcePath) JSONObject(org.json.JSONObject) FieldFilter(com.google.firebase.firestore.core.FieldFilter) Filter(com.google.firebase.firestore.core.Filter) Nullable(androidx.annotation.Nullable)

Example 5 with Bound

use of com.google.firebase.firestore.core.Bound in project firebase-android-sdk by firebase.

the class SQLiteIndexManager method getDocumentsMatchingTarget.

@Override
public Set<DocumentKey> getDocumentsMatchingTarget(Target target) {
    hardAssert(started, "IndexManager not started");
    List<String> subQueries = new ArrayList<>();
    List<Object> bindings = new ArrayList<>();
    for (Target subTarget : getSubTargets(target)) {
        FieldIndex fieldIndex = getFieldIndex(subTarget);
        if (fieldIndex == null) {
            return null;
        }
        @Nullable List<Value> arrayValues = subTarget.getArrayValues(fieldIndex);
        @Nullable Collection<Value> notInValues = subTarget.getNotInValues(fieldIndex);
        @Nullable Bound lowerBound = subTarget.getLowerBound(fieldIndex);
        @Nullable Bound upperBound = subTarget.getUpperBound(fieldIndex);
        if (Logger.isDebugEnabled()) {
            Logger.debug(TAG, "Using index '%s' to execute '%s' (Arrays: %s, Lower bound: %s, Upper bound: %s)", fieldIndex, subTarget, arrayValues, lowerBound, upperBound);
        }
        Object[] lowerBoundEncoded = encodeBound(fieldIndex, subTarget, lowerBound);
        String lowerBoundOp = lowerBound != null && lowerBound.isInclusive() ? ">=" : ">";
        Object[] upperBoundEncoded = encodeBound(fieldIndex, subTarget, upperBound);
        String upperBoundOp = upperBound != null && upperBound.isInclusive() ? "<=" : "<";
        Object[] notInEncoded = encodeValues(fieldIndex, subTarget, notInValues);
        Object[] subQueryAndBindings = generateQueryAndBindings(subTarget, fieldIndex.getIndexId(), arrayValues, lowerBoundEncoded, lowerBoundOp, upperBoundEncoded, upperBoundOp, notInEncoded);
        subQueries.add(String.valueOf(subQueryAndBindings[0]));
        bindings.addAll(Arrays.asList(subQueryAndBindings).subList(1, subQueryAndBindings.length));
    }
    String queryString;
    if (subQueries.size() == 1) {
        // If there's only one subQuery, just execute the one subQuery.
        queryString = subQueries.get(0);
    } else {
        // Construct "SELECT * FROM (subQuery1 UNION subQuery2 UNION ...) LIMIT N"
        queryString = "SELECT * FROM (" + TextUtils.join(" UNION ", subQueries) + ")";
        if (target.getLimit() != -1) {
            queryString = queryString + " LIMIT " + target.getLimit();
        }
    }
    hardAssert(bindings.size() < 1000, "Cannot perform query with more than 999 bind elements");
    SQLitePersistence.Query query = db.query(queryString).binding(bindings.toArray());
    Set<DocumentKey> result = new HashSet<>();
    query.forEach(row -> result.add(DocumentKey.fromPath(ResourcePath.fromString(row.getString(0)))));
    Logger.debug(TAG, "Index scan returned %s documents", result.size());
    return result;
}
Also used : FieldIndex(com.google.firebase.firestore.model.FieldIndex) ArrayList(java.util.ArrayList) Bound(com.google.firebase.firestore.core.Bound) Target(com.google.firebase.firestore.core.Target) Value(com.google.firestore.v1.Value) DocumentKey(com.google.firebase.firestore.model.DocumentKey) Nullable(androidx.annotation.Nullable) HashSet(java.util.HashSet)

Aggregations

Bound (com.google.firebase.firestore.core.Bound)5 OrderBy (com.google.firebase.firestore.core.OrderBy)4 ResourcePath (com.google.firebase.firestore.model.ResourcePath)3 Value (com.google.firestore.v1.Value)3 ArrayList (java.util.ArrayList)3 Nullable (androidx.annotation.Nullable)2 FieldFilter (com.google.firebase.firestore.core.FieldFilter)2 Filter (com.google.firebase.firestore.core.Filter)2 Target (com.google.firebase.firestore.core.Target)2 DocumentKey (com.google.firebase.firestore.model.DocumentKey)2 ArrayValue (com.google.firestore.v1.ArrayValue)2 Query (com.google.firebase.firestore.core.Query)1 Document (com.google.firebase.firestore.model.Document)1 FieldIndex (com.google.firebase.firestore.model.FieldIndex)1 CollectionSelector (com.google.firestore.v1.StructuredQuery.CollectionSelector)1 CompositeFilter (com.google.firestore.v1.StructuredQuery.CompositeFilter)1 UnaryFilter (com.google.firestore.v1.StructuredQuery.UnaryFilter)1 Target (com.google.firestore.v1.Target)1 DocumentsTarget (com.google.firestore.v1.Target.DocumentsTarget)1 QueryTarget (com.google.firestore.v1.Target.QueryTarget)1