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

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

//
// Copyright (c) 2020, 2017 Couchbase, Inc All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package com.couchbase.lite;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import java.util.concurrent.atomic.AtomicBoolean;

import com.couchbase.lite.internal.DbContext;
import com.couchbase.lite.internal.fleece.FLConstants;
import com.couchbase.lite.internal.fleece.FLDict;
import com.couchbase.lite.internal.fleece.FLEncoder;
import com.couchbase.lite.internal.fleece.FLValue;
import com.couchbase.lite.internal.fleece.MCollection;
import com.couchbase.lite.internal.fleece.MValue;
import com.couchbase.lite.internal.utils.Preconditions;


/**
 * Internal delegate class for MValue - Mutable Fleece Value
 */
final class MValueDelegate implements MValue.Delegate {

    //-------------------------------------------------------------------------
    // Public methods
    //-------------------------------------------------------------------------
    @Nullable
    @Override
    public Object toNative(@NonNull MValue mv, @Nullable MCollection parent, @NonNull AtomicBoolean cacheIt) {
        final FLValue value = Preconditions.assertNotNull(mv.getValue(), "MValue");
        switch (value.getType()) {
            case FLConstants.ValueType.ARRAY:
                cacheIt.set(true);
                return mValueToArray(mv, parent);
            case FLConstants.ValueType.DICT:
                cacheIt.set(true);
                return mValueToDictionary(mv, parent);
            case FLConstants.ValueType.DATA:
                return new Blob("application/octet-stream", value.asData());
            default:
                return value.asObject();
        }
    }

    @Nullable
    @Override
    public MCollection collectionFromNative(@Nullable Object object) {
        if (object instanceof Dictionary) { return ((Dictionary) object).toMCollection(); }
        else if (object instanceof Array) { return ((Array) object).toMCollection(); }
        else { return null; }
    }

    @Override
    public void encodeNative(@NonNull FLEncoder enc, @Nullable Object object) {
        if (object == null) { enc.writeNull(); }
        else { enc.writeValue(object); }
    }

    //-------------------------------------------------------------------------
    // Private methods
    //-------------------------------------------------------------------------
    @NonNull
    private Object mValueToArray(@NonNull MValue mv, @Nullable MCollection parent) {
        return ((parent == null) || !parent.hasMutableChildren())
            ? new Array(mv, parent)
            : new MutableArray(mv, parent);
    }

    @NonNull
    private Object mValueToDictionary(@NonNull MValue mv, @NonNull MCollection parent) {
        final FLDict flDict = Preconditions.assertNotNull(mv.getValue(), "MValue").asFLDict();
        final DbContext context = (DbContext) parent.getContext();

        final FLValue flType = flDict.get(Blob.META_PROP_TYPE);
        final String type = (flType == null) ? null : flType.asString();
        if (type == null) {
            if (isOldAttachment(parent, flDict)) { return createBlob(flDict, context); }
        }
        else {
            final Object obj = createSpecialObjectOfType(type, flDict, context);
            if (obj != null) { return obj; }
        }

        if (parent.hasMutableChildren()) { return new MutableDictionary(mv, parent); }
        else { return new Dictionary(mv, parent); }
    }

    // At some point in the past, attachments were dictionaries in a top-level
    // element named "_attachments". Those dictionaries contained at least the
    // properties listed here.
    // Unfortunately, at this point, we don't know the name of the parent element.
    // Heuristically, we just look for the properties and cross our fingers.
    private boolean isOldAttachment(@NonNull MCollection parent, @NonNull FLDict flDict) {
        return (flDict.get(Blob.PROP_DIGEST) != null)
            && (flDict.get(Blob.PROP_LENGTH) != null)
            && (flDict.get(Blob.PROP_STUB) != null)
            && (flDict.get(Blob.PROP_REVPOS) != null);
    }

    @Nullable
    private Object createSpecialObjectOfType(
        @Nullable String type,
        @NonNull FLDict properties,
        @NonNull DbContext context) {
        return (!Blob.TYPE_BLOB.equals(type)) ? null : createBlob(properties, context);
    }

    @NonNull
    private Object createBlob(@NonNull FLDict properties, @NonNull DbContext context) {
        return new Blob(Preconditions.assertNotNull(context.getDatabase(), "database"), properties.asDict());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy