12aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton/*
22aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * Copyright (C) 2009 The Android Open Source Project
32aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton *
42aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License");
52aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * you may not use this file except in compliance with the License.
62aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * You may obtain a copy of the License at
72aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton *
82aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton *      http://www.apache.org/licenses/LICENSE-2.0
92aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton *
102aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * Unless required by applicable law or agreed to in writing, software
112aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS,
122aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * See the License for the specific language governing permissions and
142aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * limitations under the License.
152aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton */
162aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
172aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonpackage com.android.loaderapp.model;
182aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
192aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonimport android.content.ContentProviderOperation;
202aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonimport android.content.ContentValues;
212aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonimport android.content.Entity;
222aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonimport android.content.ContentProviderOperation.Builder;
232aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonimport android.content.Entity.NamedContentValues;
242aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonimport android.net.Uri;
252aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonimport android.provider.BaseColumns;
262aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
272aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonimport java.util.ArrayList;
282aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonimport java.util.HashMap;
292aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
302aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
312aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton/**
322aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * Describes a set of {@link ContentProviderOperation} that need to be
332aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton * executed to transform a database from one {@link Entity} to another.
342aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton */
352aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton@Deprecated
362aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamiltonpublic class EntityDiff extends ArrayList<ContentProviderOperation> {
372aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    private EntityDiff() {
382aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    }
392aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
402aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    /**
412aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton     * Build the set of {@link ContentProviderOperation} needed to translate
422aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton     * from "before" to "after". Tries its best to keep operations to
432aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton     * minimal number required. Assumes that all {@link ContentValues} are
442aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton     * keyed using {@link BaseColumns#_ID} values.
452aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton     */
462aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    public static EntityDiff buildDiff(Entity before, Entity after, Uri targetUri,
472aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            String childForeignKey) {
482aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        final EntityDiff diff = new EntityDiff();
492aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
502aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        Builder builder;
512aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        ContentValues values;
522aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
532aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        if (before == null) {
542aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            // Before doesn't exist, so insert "after" values
552aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            builder = ContentProviderOperation.newInsert(targetUri);
562aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            builder.withValues(after.getEntityValues());
572aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            diff.add(builder.build());
582aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
592aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            for (NamedContentValues child : after.getSubValues()) {
602aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                // Add builder with reference to original _id when needed
612aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                builder = ContentProviderOperation.newInsert(child.uri);
622aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                builder.withValues(child.values);
632aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                if (childForeignKey != null) {
642aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    builder.withValueBackReference(childForeignKey, 0);
652aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                }
662aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                diff.add(builder.build());
672aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            }
682aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
692aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        } else if (after == null) {
702aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            // After doesn't exist, so delete "before" values
712aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            for (NamedContentValues child : before.getSubValues()) {
722aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                builder = ContentProviderOperation.newDelete(child.uri);
732aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                builder.withSelection(getSelectIdClause(child.values), null);
742aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                diff.add(builder.build());
752aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            }
762aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
772aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            builder = ContentProviderOperation.newDelete(targetUri);
782aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            builder.withSelection(getSelectIdClause(before.getEntityValues()), null);
792aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            diff.add(builder.build());
802aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
812aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        } else {
822aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            // Somewhere between, so update any changed values
832aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            values = after.getEntityValues();
842aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            if (!before.getEntityValues().equals(values)) {
852aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                // Top-level values changed, so update
862aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                builder = ContentProviderOperation.newUpdate(targetUri);
872aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                builder.withSelection(getSelectIdClause(values), null);
882aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                builder.withValues(values);
892aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                diff.add(builder.build());
902aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            }
912aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
922aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            // Build lookup maps for children on both sides
932aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            final HashMap<String, NamedContentValues> beforeChildren = buildChildrenMap(before);
942aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            final HashMap<String, NamedContentValues> afterChildren = buildChildrenMap(after);
952aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
962aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            // Walk through "before" children looking for deletes and updates
972aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            for (NamedContentValues beforeChild : beforeChildren.values()) {
982aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                final String key = buildChildKey(beforeChild);
992aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                final NamedContentValues afterChild = afterChildren.get(key);
1002aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
1012aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                if (afterChild == null) {
1022aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    // After child doesn't exist, so delete "before" child
1032aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    builder = ContentProviderOperation.newDelete(beforeChild.uri);
1042aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    builder.withSelection(getSelectIdClause(beforeChild.values), null);
1052aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    diff.add(builder.build());
1062aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                } else if (!beforeChild.values.equals(afterChild.values)) {
1072aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    // After child still exists, and is different, so update
1082aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    values = afterChild.values;
1092aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    builder = ContentProviderOperation.newUpdate(afterChild.uri);
1102aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    builder.withSelection(getSelectIdClause(values), null);
1112aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    builder.withValues(values);
1122aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                    diff.add(builder.build());
1132aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                }
1142aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
1152aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                // Remove the now-handled "after" child
1162aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                afterChildren.remove(key);
1172aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            }
1182aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
1192aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            // Walk through remaining "after" children, which are inserts
1202aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            for (NamedContentValues afterChild : afterChildren.values()) {
1212aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                builder = ContentProviderOperation.newInsert(afterChild.uri);
1222aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                builder.withValues(afterChild.values);
1232aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                diff.add(builder.build());
1242aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            }
1252aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        }
1262aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
1272aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        return diff;
1282aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    }
1292aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
1302aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    private static String buildChildKey(NamedContentValues child) {
1312aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        return child.uri.toString() + child.values.getAsString(BaseColumns._ID);
1322aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    }
1332aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
1342aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    private static String getSelectIdClause(ContentValues values) {
1352aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        return BaseColumns._ID + "=" + values.getAsLong(BaseColumns._ID);
1362aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    }
1372aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton
1382aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    private static HashMap<String, NamedContentValues> buildChildrenMap(Entity entity) {
1392aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        final ArrayList<NamedContentValues> children = entity.getSubValues();
1402aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        final HashMap<String, NamedContentValues> childrenMap = new HashMap<String, NamedContentValues>(
1412aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton                children.size());
1422aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        for (NamedContentValues child : children) {
1432aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            final String key = buildChildKey(child);
1442aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton            childrenMap.put(key, child);
1452aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        }
1462aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton        return childrenMap;
1472aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton    }
1482aee0983597c8b0e65766c4b278d4b1c7d13605fJeff Hamilton}
149