/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.metamodel.couchdb;
import java.util.List;
import org.apache.metamodel.MetaModelException;
import org.apache.metamodel.MetaModelHelper;
import org.apache.metamodel.QueryPostprocessDataContext;
import org.apache.metamodel.UpdateScript;
import org.apache.metamodel.UpdateableDataContext;
import org.apache.metamodel.data.DataSet;
import org.apache.metamodel.data.DocumentSource;
import org.apache.metamodel.data.SimpleDataSetHeader;
import org.apache.metamodel.query.FilterItem;
import org.apache.metamodel.query.SelectItem;
import org.apache.metamodel.schema.Column;
import org.apache.metamodel.schema.Schema;
import org.apache.metamodel.schema.Table;
import org.apache.metamodel.schema.builder.DocumentSourceProvider;
import org.apache.metamodel.schema.builder.SchemaBuilder;
import org.apache.metamodel.util.SimpleTableDef;
import org.ektorp.CouchDbConnector;
import org.ektorp.CouchDbInstance;
import org.ektorp.StreamingViewResult;
import org.ektorp.ViewQuery;
import org.ektorp.http.HttpClient;
import org.ektorp.http.StdHttpClient;
import org.ektorp.impl.StdCouchDbInstance;
import com.fasterxml.jackson.databind.JsonNode;
/**
* DataContext implementation for CouchDB
*/
public class CouchDbDataContext extends QueryPostprocessDataContext implements UpdateableDataContext,
DocumentSourceProvider {
public static final String SCHEMA_NAME = "CouchDB";
public static final int DEFAULT_PORT = 5984;
public static final String FIELD_ID = "_id";
public static final String FIELD_REV = "_rev";
// the instance represents a handle to the whole couchdb cluster
private final CouchDbInstance _couchDbInstance;
private final SchemaBuilder _schemaBuilder;
public CouchDbDataContext(StdHttpClient.Builder httpClientBuilder, SimpleTableDef... tableDefs) {
this(httpClientBuilder.build(), tableDefs);
}
public CouchDbDataContext(StdHttpClient.Builder httpClientBuilder) {
this(httpClientBuilder.build());
}
public CouchDbDataContext(HttpClient httpClient, SimpleTableDef... tableDefs) {
this(new StdCouchDbInstance(httpClient), tableDefs);
}
public CouchDbDataContext(HttpClient httpClient) {
this(new StdCouchDbInstance(httpClient));
}
public CouchDbDataContext(CouchDbInstance couchDbInstance) {
_couchDbInstance = couchDbInstance;
_schemaBuilder = new CouchDbInferentialSchemaBuilder();
}
public CouchDbDataContext(CouchDbInstance couchDbInstance, String... databaseNames) {
_couchDbInstance = couchDbInstance;
_schemaBuilder = new CouchDbInferentialSchemaBuilder(databaseNames);
}
public CouchDbDataContext(CouchDbInstance couchDbInstance, SimpleTableDef... tableDefs) {
_couchDbInstance = couchDbInstance;
_schemaBuilder = new CouchDbSimpleTableDefSchemaBuilder(tableDefs);
}
public CouchDbInstance getCouchDbInstance() {
return _couchDbInstance;
}
@Override
protected Schema getMainSchema() throws MetaModelException {
_schemaBuilder.offerSources(this);
return _schemaBuilder.build();
}
@Override
protected String getMainSchemaName() throws MetaModelException {
return _schemaBuilder.getSchemaName();
}
@Override
protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int firstRow, int maxRows) {
// the connector represents a handle to the the couchdb "database".
final String databaseName = table.getName();
final CouchDbConnector connector = _couchDbInstance.createConnector(databaseName, false);
ViewQuery query = new ViewQuery().allDocs().includeDocs(true);
if (maxRows > 0) {
query = query.limit(maxRows);
}
if (firstRow > 1) {
final int skip = firstRow - 1;
query = query.skip(skip);
}
final StreamingViewResult streamingView = connector.queryForStreamingView(query);
final SelectItem[] selectItems = MetaModelHelper.createSelectItems(columns);
return new CouchDbDataSet(selectItems, streamingView);
}
@Override
protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) {
return materializeMainSchemaTable(table, columns, 1, maxRows);
}
@Override
protected org.apache.metamodel.data.Row executePrimaryKeyLookupQuery(Table table, List<SelectItem> selectItems,
Column primaryKeyColumn, Object keyValue) {
if (keyValue == null) {
return null;
}
final String databaseName = table.getName();
final CouchDbConnector connector = _couchDbInstance.createConnector(databaseName, false);
final String keyString = keyValue.toString();
final JsonNode node = connector.find(JsonNode.class, keyString);
if (node == null) {
return null;
}
return CouchDbUtils.jsonNodeToMetaModelRow(node, new SimpleDataSetHeader(selectItems));
}
@Override
protected Number executeCountQuery(Table table, List<FilterItem> whereItems, boolean functionApproximationAllowed) {
if (whereItems.isEmpty()) {
String databaseName = table.getName();
CouchDbConnector connector = _couchDbInstance.createConnector(databaseName, false);
long docCount = connector.getDbInfo().getDocCount();
return docCount;
}
return null;
}
@Override
public void executeUpdate(UpdateScript script) {
CouchDbUpdateCallback callback = new CouchDbUpdateCallback(this);
try {
script.run(callback);
} finally {
callback.close();
}
}
@Override
public DocumentSource getMixedDocumentSourceForSampling() {
return new CouchDbSamplingDocumentSource(_couchDbInstance);
}
@Override
public DocumentSource getDocumentSourceForTable(String sourceCollectionName) {
return new CouchDbDatabaseDocumentSource(_couchDbInstance, sourceCollectionName, -1);
}
}