Package com.foundationdb.server.service.restdml

Source Code of com.foundationdb.server.service.restdml.InsertProcessor

/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.server.service.restdml;

import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import com.foundationdb.server.types.FormatOptions;
import com.foundationdb.server.types.service.TypesRegistryService;
import com.foundationdb.server.service.externaldata.TableRowTracker;
import com.fasterxml.jackson.databind.JsonNode;
import com.foundationdb.server.types.value.ValueSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.foundationdb.ais.model.AkibanInformationSchema;
import com.foundationdb.ais.model.CacheValueGenerator;
import com.foundationdb.ais.model.Column;
import com.foundationdb.ais.model.Join;
import com.foundationdb.ais.model.TableName;
import com.foundationdb.qp.operator.API;
import com.foundationdb.qp.operator.Cursor;
import com.foundationdb.qp.operator.Operator;
import com.foundationdb.server.error.FKValueMismatchException;
import com.foundationdb.server.service.externaldata.JsonRowWriter;
import com.foundationdb.server.service.externaldata.JsonRowWriter.WriteCapturePKRow;
import com.foundationdb.server.service.session.Session;
import com.foundationdb.server.store.SchemaManager;
import com.foundationdb.server.store.Store;
import com.foundationdb.util.AkibanAppender;

public class InsertProcessor extends DMLProcessor {
    private InsertGenerator insertGenerator;
    private FormatOptions options;
    private static final Logger LOG = LoggerFactory.getLogger(InsertProcessor.class);

    public InsertProcessor (
            Store store, SchemaManager schemaManager,
            TypesRegistryService typesRegistryService,
            FormatOptions options) {
        super (store, schemaManager, typesRegistryService);
        this.options = options;
    }
   
    private static final CacheValueGenerator<InsertGenerator> CACHED_INSERT_GENERATOR =
            new CacheValueGenerator<InsertGenerator>() {
                @Override
                public InsertGenerator valueFor(AkibanInformationSchema ais) {
                    return new InsertGenerator(ais);
                }
            };

    public String processInsert(Session session, AkibanInformationSchema ais, TableName rootTable, JsonNode node) {
        ProcessContext context = new ProcessContext ( ais, session, rootTable);
        insertGenerator = getGenerator(CACHED_INSERT_GENERATOR, context);
        StringBuilder builder = new StringBuilder();
        AkibanAppender appender = AkibanAppender.of(builder);
        processContainer (node, appender, context);
        return appender.toString();
    }
   
    private void processContainer (JsonNode node, AkibanAppender appender, ProcessContext context) {
        boolean first = true;
        Map<Column, ValueSource> pkValues = null;
       
        if (node.isObject()) {
            processTable (node, appender, context);
        } else if (node.isArray()) {
            appender.append('[');
            for (JsonNode arrayElement : node) {
                if (first) {
                    pkValues = context.pkValues;
                    first = false;
                } else {
                    appender.append(',');
                }
                if (arrayElement.isObject()) {
                    processTable (arrayElement, appender, context);
                    context.pkValues = pkValues;
                    context.queryBindings.clear();
                    context.allValues.clear();
                }
                // else throw Bad Json Format Exception
            }
            appender.append(']');
        } // else throw Bad Json Format Exception
       
    }
   
    private void processTable (JsonNode node, AkibanAppender appender, ProcessContext context) {
        // Pass one, insert fields from the table
        Iterator<Entry<String,JsonNode>> i = node.fields();
        while (i.hasNext()) {
            Entry<String,JsonNode> field = i.next();
            if (field.getValue().isValueNode()) {
                Column column = getColumn(context.table, field.getKey());
                context.allValues.put(column, field.getValue().isNull() ? null : field.getValue().asText());
            }
        }
        runInsert(context, appender);
        boolean first = true;
        // pass 2: insert the child nodes
        i = node.fields();
        while (i.hasNext()) {
            Entry<String,JsonNode> field = i.next();
            if (field.getValue().isContainerNode()) {
                if (first) {
                    first = false;
                    // Delete the closing } for the object
                    StringBuilder builder = (StringBuilder)appender.getAppendable();
                    builder.deleteCharAt(builder.length()-1);
                }
                TableName tableName = TableName.parse(context.tableName.getSchemaName(), field.getKey());
                ProcessContext newContext = new ProcessContext(context.ais(), context.session, tableName);
                newContext.pkValues = context.pkValues;
                appender.append(",\"");
                appender.append(newContext.table.getNameForOutput());
                appender.append("\":");
                processContainer (field.getValue(), appender, newContext);
            }
        }
        // we appended at least one sub-object, so replace the object close brace.
        if (!first) {
            appender.append('}');
        }
    }
     private void runInsert(ProcessContext context, AkibanAppender appender) {
        assert context != null : "Bad Json format";
        LOG.trace("Insert row into: {}, values {}", context.tableName, context.queryContext);
        // Fill in parent columns if this is a child table
        if(context.pkValues != null && context.table.getParentJoin() != null) {
            Join join = context.table.getParentJoin();
            for (Entry<Column, ValueSource> entry : context.pkValues.entrySet()) {
                Column parentCol = entry.getKey();
                Column childCol = join.getMatchingChild(parentCol);
                String fkValue = valueToString(entry.getValue());
                String curValue = context.allValues.get(childCol);
                if(curValue == null) {
                    context.allValues.put(childCol, fkValue);
                } else if(!fkValue.equals(curValue)) {
                    throw new FKValueMismatchException(join.getMatchingChild(entry.getKey()).getName());
                }
            }
        }
        Operator insert = insertGenerator.create(context.allValues, context.table.getName());
        Cursor cursor = API.cursor(insert, context.queryContext, context.queryBindings);
        JsonRowWriter writer = new JsonRowWriter(new TableRowTracker(context.table, 0));
        WriteCapturePKRow rowWriter = new WriteCapturePKRow();
        writer.writeRows(cursor, appender, context.anyUpdates ? "\n" : "", rowWriter, options);
        context.pkValues = rowWriter.getPKValues();
        context.anyUpdates = true;
    }
   
    private String valueToString(ValueSource value) {
        AkibanAppender appender = AkibanAppender.of(new StringBuilder());
        value.getType().format(value, appender);
        return appender.toString();
    }
}
TOP

Related Classes of com.foundationdb.server.service.restdml.InsertProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.