/* * Copyright (c) 2015 FUJI Goro (gfx). * * 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.github.gfx.android.orma; import com.google.gson.annotations.JsonAdapter; import com.github.gfx.android.orma.exception.InvalidModelException; import com.github.gfx.android.orma.exception.NoValueException; import com.github.gfx.android.orma.gson.SingleAssociationTypeAdapterFactory; import com.github.gfx.android.orma.internal.Schemas; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.CheckResult; import android.support.annotation.NonNull; import android.support.annotation.RestrictTo; import io.reactivex.Single; /** * Lazy has-one association. The {@code Model} is assumed to have a primary key with the `long` type. * This is typically created from factory methods. * * @param <Model> The type of a model */ @JsonAdapter(SingleAssociationTypeAdapterFactory.class) public class SingleAssociation<Model> implements Parcelable { final long id; final Single<Model> single; @RestrictTo(RestrictTo.Scope.LIBRARY) public SingleAssociation(long id, @NonNull Model model) { this.id = id; this.single = Single.just(model); } @RestrictTo(RestrictTo.Scope.LIBRARY) public SingleAssociation(long id, @NonNull Single<Model> single) { this.id = id; this.single = single; } // may be called from *_Schema public SingleAssociation(@NonNull final OrmaConnection conn, @NonNull final Schema<Model> schema, final long id) { this.id = id; single = Single.fromCallable(new ModelFactory<Model>() { @NonNull @Override public Model call() { return conn.findByRowId(schema, id); } }); } /** * The most typical factory method to create a {@code SingleAssociation} instance, * just wrapping the model with it. * * @param model A model to wrap, which must have a valid primary key * @param <T> The type of the model to wrap * @return An instance of {@code SingleAssociation} */ @SuppressWarnings("unchecked") @NonNull public static <T> SingleAssociation<T> just(@NonNull T model) { Schema<T> schema = Schemas.get((Class<T>) model.getClass()); return just(schema, model); } @NonNull public static <T> SingleAssociation<T> just(long id, @NonNull T model) { return new SingleAssociation<>(id, model); } @NonNull public static <T> SingleAssociation<T> just(@NonNull Schema<T> schema, @NonNull T model) { return new SingleAssociation<>((long) schema.getPrimaryKey().getSerialized(model), model); } @NonNull public static <T> SingleAssociation<T> just(final long id) { return new SingleAssociation<>(id, Single.<T>error(new NoValueException("No value set for id=" + id))); } // use just(id) instead @Deprecated @NonNull public static <T> SingleAssociation<T> id(final long id) { return just(id); } /** * @return The primary key of the associated model. */ public long getId() { return id; } @CheckResult @NonNull public Single<Model> single() { return single; } /** * A shortcut of {@code singleAssociation.single().blockingGet()}. * * @return A model that the instance refers to. */ @NonNull public Model get() throws NoValueException { return single.blockingGet(); } @Deprecated @NonNull public Model value() throws NoValueException { return single.blockingGet(); } @Override public String toString() { return "SingleAssociation{" + "id=" + id + '}'; } // Parcelable public static Parcelable.ClassLoaderCreator<SingleAssociation<?>> CREATOR = new ClassLoaderCreator<SingleAssociation<?>>() { @Override public SingleAssociation<?> createFromParcel(Parcel source) { return createFromParcel(source, null); } @Override public SingleAssociation<?>[] newArray(int size) { return new SingleAssociation<?>[size]; } @Override public SingleAssociation<?> createFromParcel(Parcel source, ClassLoader loader) { long id = source.readLong(); Parcelable parcelable = source.readParcelable(loader); return new SingleAssociation<>(id, parcelable); } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { Model model = single.blockingGet(); if (!(model instanceof Parcelable)) { throw new InvalidModelException("Orma model " + model.getClass() + " is not a Parcelable"); } dest.writeLong(id); dest.writeParcelable((Parcelable) model, flags); } }