All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.couchbase.lite.QueryRow Maven / Gradle / Ivy

package com.couchbase.lite;

import com.couchbase.lite.internal.InterfaceAudience;
import com.couchbase.lite.internal.RevisionInternal;
import com.couchbase.lite.store.QueryRowStore;
import com.couchbase.lite.util.Utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A result row from a CouchbaseLite view query.
 * Full-text and geo queries return subclasses -- see CBLFullTextQueryRow and CBLGeoQueryRow.
 */
public class QueryRow {

    /**
     * The row's key: this is the first parameter passed to the emit() call that generated the row.
     */
    private Object key;

    /**
     * The row's value: this is the second parameter passed to the emit() call that generated the row.
     */
    private Object value;

    /**
     * The database sequence number of the associated doc/revision.
     */
    private long sequence;

    /**
     * The ID of the document that caused this view row to be emitted.
     * This is the value of the "id" property of the JSON view row.
     * It will be the same as the .documentID property, unless the map function caused a
     * related document to be linked by adding an "_id" key to the emitted value; in this
     * case .documentID will refer to the linked document, while sourceDocumentID always
     * refers to the original document.
     * In a reduced or grouped query the value will be nil, since the rows don't correspond
     * to individual documents.
     */
    private String sourceDocID;

    /**
     * The properties of the document this row was mapped from.
     * To get this, you must have set the .prefetch property on the query; else this will be nil.
     * (You can still get the document properties via the .document property, of course. But it
     * takes a separate call to the database. So if you're doing it for every row, using
     * .prefetch and .documentProperties is faster.)
     */
    //private Map documentProperties;
    RevisionInternal documentRevision;

    private QueryRowStore queryRowStore;

    private Database database;

    /**
     * Constructor
     * 

* The database property will be filled in when I'm added to a QueryEnumerator. */ @InterfaceAudience.Private public QueryRow(String docID, long sequence, Object key, Object value, RevisionInternal docRevision, QueryRowStore queryRowStore) { // Don't initialize _database yet. I might be instantiated on a background thread (if the // query is async) which has a different CBLDatabase instance than the original caller. // Instead, the database property will be filled in when I'm added to a CBLQueryEnumerator. this.sourceDocID = docID; this.sequence = sequence; this.key = key; this.value = value; this.documentRevision = docRevision; this.queryRowStore = queryRowStore; } protected Database getDatabase() { return database; } protected void setDatabase(Database database) { this.database = database; } /** * The document this row was mapped from. This will be nil if a grouping was enabled in * the query, because then the result rows don't correspond to individual documents. */ @InterfaceAudience.Public public Document getDocument() { if (getDocumentId() == null) { return null; } assert (database != null); Document document = database.getDocument(getDocumentId()); document.loadCurrentRevisionFrom(this); return document; } /** * The row's key: this is the first parameter passed to the emit() call that generated the row. */ @InterfaceAudience.Public public Object getKey() { return key; } /** * The row's value: this is the second parameter passed to the emit() call that generated the row. */ @InterfaceAudience.Public public Object getValue() { return value; } /** * The ID of the document described by this view row. This is not necessarily the same as the * document that caused this row to be emitted; see the discussion of the .sourceDocumentID * property for details. */ @InterfaceAudience.Public public String getDocumentId() { // Get the doc id from either the embedded document contents, or the '_id' value key. // Failing that, there's no document linking, so use the regular old _sourceDocID String docID = null; if (documentRevision != null) docID = documentRevision.getDocID(); if (docID == null) { if (value != null) { if (value instanceof Map) { Map props = (Map) value; docID = (String) props.get("_id"); } } } if (docID == null) docID = sourceDocID; return docID; } /** * The ID of the document that caused this view row to be emitted. This is the value of * the "id" property of the JSON view row. It will be the same as the .documentID property, * unless the map function caused a related document to be linked by adding an "_id" key to * the emitted value; in this case .documentID will refer to the linked document, while * sourceDocumentID always refers to the original document. In a reduced or grouped query * the value will be nil, since the rows don't correspond to individual documents. */ @InterfaceAudience.Public public String getSourceDocumentId() { return sourceDocID; } /** * The revision ID of the document this row was mapped from. */ @InterfaceAudience.Public public String getDocumentRevisionId() { // Get the revision id from either the embedded document contents, // or the '_rev' or 'rev' value key: String rev = null; if (documentRevision != null) rev = documentRevision.getRevID(); if (rev == null) { if (value instanceof Map) { Map mapValue = (Map) value; rev = (String) mapValue.get("_rev"); if (rev == null) { rev = (String) mapValue.get("rev"); } } } return rev; } /** * The properties of the document this row was mapped from. * To get this, you must have set the -prefetch property on the query; else this will be nil. * The map returned is immutable (run through Collections.unmodifiableMap) */ @InterfaceAudience.Public public Map getDocumentProperties() { return documentRevision != null ? documentRevision.getProperties() : null; } /** * The local sequence number of the associated doc/revision. */ @InterfaceAudience.Public public long getSequenceNumber() { return sequence; } /** * Returns all conflicting revisions of the document, or nil if the * document is not in conflict. *

* The first object in the array will be the default "winning" revision that shadows the others. * This is only valid in an allDocuments query whose allDocsMode is set to Query.AllDocsMode.SHOW_CONFLICTS * or Query.AllDocsMode.ONLY_CONFLICTS; otherwise it returns an empty list. */ @InterfaceAudience.Public public List getConflictingRevisions() { Document doc = database.getDocument(sourceDocID); Map valueTmp = (Map) value; List conflicts = (List) valueTmp.get("_conflicts"); if (conflicts == null) { conflicts = new ArrayList(); } List conflictingRevisions = new ArrayList(); for (String conflictRevisionId : conflicts) { SavedRevision revision = doc.getRevision(conflictRevisionId); conflictingRevisions.add(revision); } return conflictingRevisions; } /** * Compare this against the given QueryRow for equality. *

* Implentation Note: This is used implicitly by -[LiveQuery update] to decide whether * the query result has changed enough to notify the client. So it's important that it * not give false positives, else the app won't get notified of changes. * * @param object the QueryRow to compare this instance with. * @return true if equal, false otherwise. */ @Override @InterfaceAudience.Public public boolean equals(Object object) { if (object == this) { return true; } if (!(object instanceof QueryRow)) { return false; } QueryRow other = (QueryRow) object; if (database == other.database && Utils.isEqual(key, other.getKey()) && Utils.isEqual(sourceDocID, other.getSourceDocumentId()) && Utils.isEqual(documentRevision, other.documentRevision)) { // If values were emitted, compare them. Otherwise we have nothing to go on so check // if _anything_ about the doc has changed (i.e. the sequences are different.) if (value != null || other.getValue() != null) { return value.equals(other.getValue()); } else { return sequence == other.sequence; } } return false; } /** * Return a string representation of this QueryRow. * The string is returned in JSON format. * * @return the JSON string representing this QueryRow */ @Override @InterfaceAudience.Public public String toString() { return asJSONDictionary().toString(); } /** * @exclude */ @InterfaceAudience.Private public Map asJSONDictionary() { Map result = new HashMap(); if (value != null || sourceDocID != null) { result.put("key", key); result.put("value", value); result.put("id", sourceDocID); result.put("doc", getDocumentProperties()); } else { result.put("key", key); result.put("error", "not_found"); } return result; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy