diff --git a/mars-core/src/main/java/com/whaleal/mars/core/index/IndexHelper.java b/mars-core/src/main/java/com/whaleal/mars/core/index/IndexHelper.java index 568d023d..3640f289 100755 --- a/mars-core/src/main/java/com/whaleal/mars/core/index/IndexHelper.java +++ b/mars-core/src/main/java/com/whaleal/mars/core/index/IndexHelper.java @@ -252,4 +252,5 @@ String findField(EntityModel entityModel, IndexOptions options, String path) { return new PathTarget(mapper, entityModel, path, !options.disableValidation()).translatedPath(); } + } diff --git a/mars-core/src/main/java/com/whaleal/mars/core/index/IndexUtil.java b/mars-core/src/main/java/com/whaleal/mars/core/index/IndexUtil.java new file mode 100644 index 00000000..290bc582 --- /dev/null +++ b/mars-core/src/main/java/com/whaleal/mars/core/index/IndexUtil.java @@ -0,0 +1,225 @@ +/** + * Copyright 2020-present Shanghai Jinmu Information Technology Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by Shanghai Jinmu Information Technology Co., Ltd.(The name of the development team is Whaleal.) + * + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +package com.whaleal.mars.core.index; + +import com.mongodb.client.model.CollationAlternate; +import com.mongodb.client.model.CollationCaseFirst; +import com.mongodb.client.model.CollationMaxVariable; +import com.mongodb.client.model.CollationStrength; +import com.whaleal.mars.core.internal.diagnostics.logging.LogFactory; +import com.whaleal.mars.core.internal.diagnostics.logging.Logger; +import com.whaleal.mars.session.option.IndexOptions; +import org.bson.Document; +import org.bson.conversions.Bson; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * @author wh + * + */ +public class IndexUtil { + + private static final Logger LOGGER = LogFactory.getLogger(IndexUtil.class); + + public static Index of( Document indexDoc ) { + Document o = indexDoc; + + IndexOptions indexOptions = new IndexOptions(); + if (o.get("background") != null) { + + //todo 具体值可能为多种类型 如 "true" true 1 1.0 "1.0" "5.0" 甚至为 任意字符"xxx"尤其是老版本 情况很多 这里并不能全部列举 + // C语言决策. C语言编程假定任何非零和非空值为真,并且如果它是零或null,那么它被假定为假值 + // 主要为 boolean 类型 String 类型 数值类型 + if (o.get("background") instanceof Boolean) { + indexOptions.background((Boolean) o.get("background")); + } else if (o.get("background") instanceof String) { + indexOptions.background(true); + } else if (o.get("background") instanceof Number) { + // 非 0 为真 + double v; + try { + v = Double.valueOf(o.get("background").toString()); + if (v > 0) { + indexOptions.background(true); + } else indexOptions.background(v < 0); + } catch (Exception e) { + LOGGER.warn(String.format("Index background Option parse error from index name %s with background value %s ", o.get("name"), o.get("background"))); + indexOptions.background(true); + } + } + + } + + if (o.get("unique") != null) { + indexOptions.unique((Boolean) o.get("unique")); + } + if (o.get("name") != null) { + indexOptions.name((String) o.get("name")); + } + + if (o.get("partialFilterExpression") != null) { + indexOptions.partialFilterExpression((Bson) o.get("partialFilterExpression")); + } + if (o.get("sparse") != null) { + indexOptions.sparse((Boolean) o.get("sparse")); + } + if (o.get("expireAfterSeconds") != null) { + Long expireAfter = ((Double) Double.parseDouble(o.get("expireAfterSeconds").toString())).longValue(); + //秒以下会丢失 + indexOptions.expireAfter(expireAfter, TimeUnit.SECONDS); + } + + if (o.get("hidden") != null) { + indexOptions.hidden((Boolean) o.get("hidden")); + } + + if (o.get("storageEngine") != null) { + //不常用到 + indexOptions.storageEngine((Bson) o.get("storageEngine")); + } + + //---------deal with Collation + + if (o.get("collation") != null) { + com.mongodb.client.model.Collation.Builder collationBuilder = com.mongodb.client.model.Collation.builder(); + Document collation = (Document) o.get("collation"); + if (collation.get("locale") != null) { + collationBuilder.locale(collation.getString("locale")); + } + if (collation.get("caseLevel") != null) { + collationBuilder.caseLevel(collation.getBoolean("caseLevel")); + } + if (collation.get("caseFirst") != null) { + collationBuilder.collationCaseFirst(CollationCaseFirst.fromString(collation.getString("caseFirst"))); + } + if (collation.get("strength") != null) { + collationBuilder.collationStrength(CollationStrength.fromInt( + ((Double) Double.parseDouble(collation.get("strength").toString())).intValue() + )); + } + if (collation.get("numericOrdering") != null) { + collationBuilder.numericOrdering(collation.getBoolean("numericOrdering")); + } + if (collation.get("alternate") != null) { + collationBuilder.collationAlternate(CollationAlternate.fromString(collation.getString("alternate"))); + } + if (collation.get("maxVariable") != null) { + collationBuilder.collationMaxVariable(CollationMaxVariable.fromString(collation.getString("maxVariable"))); + } + if (collation.get("normalization") != null) { + collationBuilder.normalization(collation.getBoolean("normalization")); + } + if (collation.get("backwards") != null) { + collationBuilder.backwards(collation.getBoolean("backwards")); + } + indexOptions.collation(collationBuilder.build()); + } + + //---------deal with Text + + + if (o.get("weights") != null) { + indexOptions.weights((Bson) o.get("weights")); + } + if (o.get("textIndexVersion") != null) { + indexOptions.textVersion(((Double) Double.parseDouble(o.get("textIndexVersion").toString())).intValue()); + } + if (o.get("default_language") != null) { + indexOptions.defaultLanguage((String) o.get("default_language")); + } + if (o.get("language_override") != null) { + indexOptions.languageOverride(o.get("language_override").toString()); + } + + //--------deal with wildcard + + if (o.get("wildcardProjection") != null) { + indexOptions.wildcardProjection((Bson) o.get("wildcardProjection")); + } + + //---------deal with geoHaystack + if (o.get("bucketSize") != null) { + indexOptions.bucketSize(Double.parseDouble(o.get("bucketSize").toString())); + } + //---------deal with 2d + + if (o.get("bits") != null) { + indexOptions.bits(((Double) Double.parseDouble(o.get("bits").toString())).intValue()); + } + if (o.get("max") != null) { + indexOptions.max((Double.parseDouble(o.get("max").toString()))); + } + if (o.get("min") != null) { + indexOptions.min((Double.parseDouble(o.get("min").toString()))); + } + + //---------------deal with 2dsphere + + if (o.get("2dsphereIndexVersion") != null) { + indexOptions.sphereVersion(((Double) Double.parseDouble((o.get("2dsphereIndexVersion").toString()))).intValue()); + } + + //------ let it be backgroud + indexOptions.background(true); + + Document key = (Document) o.get("key"); + + Index index = new Index(); + + Set< String > strings = key.keySet(); + + for (String keyName : strings) { + index.on(keyName, IndexDirection.fromValue(key.get(keyName))); + + } + index.setOptions(indexOptions); + + return index; + + } + + + public static List< Index > of( List< Document > indexesDoc ) { + List< Index > indexes = new ArrayList<>(); + for (Document doc : indexesDoc) { + Index index = IndexUtil.of(doc); + + indexes.add(index); + } + return indexes; + } + + +} diff --git a/mars-core/src/main/java/com/whaleal/mars/core/query/MarsQueryException.java b/mars-core/src/main/java/com/whaleal/mars/core/query/MarsQueryException.java new file mode 100644 index 00000000..5fc622ce --- /dev/null +++ b/mars-core/src/main/java/com/whaleal/mars/core/query/MarsQueryException.java @@ -0,0 +1,61 @@ +/** + * Copyright 2020-present Shanghai Jinmu Information Technology Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by Shanghai Jinmu Information Technology Co., Ltd.(The name of the development team is Whaleal.) + * + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ +package com.whaleal.mars.core.query; + + + +/** + * Error during query. + * + * @author wh + */ +public class MarsQueryException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * Creates a QueryException with a message + * + * @param message the message to record + */ + public MarsQueryException(String message) { + super(message); + } + + /** + * Creates a QueryException with a message and a cause + * + * @param message the message to record + * @param cause the underlying cause + */ + public MarsQueryException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/mars-core/src/main/java/com/whaleal/mars/session/DatastoreImpl.java b/mars-core/src/main/java/com/whaleal/mars/session/DatastoreImpl.java index 3788beff..00f799f4 100644 --- a/mars-core/src/main/java/com/whaleal/mars/session/DatastoreImpl.java +++ b/mars-core/src/main/java/com/whaleal/mars/session/DatastoreImpl.java @@ -68,6 +68,7 @@ import com.whaleal.mars.core.index.Index; import com.whaleal.mars.core.index.IndexDirection; import com.whaleal.mars.core.index.IndexHelper; +import com.whaleal.mars.core.index.IndexUtil; import com.whaleal.mars.core.internal.diagnostics.logging.LogFactory; import com.whaleal.mars.core.internal.diagnostics.logging.Logger; import com.whaleal.mars.core.query.*; @@ -94,7 +95,6 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; - import static com.whaleal.icefrog.core.lang.Precondition.*; @@ -392,7 +392,7 @@ protected < T > FindIterable< T > doFind( Query query, @Nullable Class< T > enti Precondition.hasText(collectionName, "CollectionName must not be null or empty"); MongoCollection< T > collection = this.getCollection(entityClass, collectionName); - //ClientSession session = this.startSession(); + collection = query.getReadConcern() == null ? collection : collection.withReadConcern(query.getReadConcern()); @@ -493,8 +493,7 @@ private < T > T doInsertOne( T entity, InsertOneOptions options, String collecti Precondition.notNull(entity, "entity must not be null"); Precondition.hasText(collectionName, "collectionName must not be null"); - // 开启与数据库的连接 - //ClientSession session = this.startSession(); + //根据传入的集合名和实体类获取对应的MongoCollection对象 MongoCollection< T > collection = this.getCollection((Class< T >) entity.getClass(), collectionName); @@ -551,7 +550,6 @@ private < T > List< T > doInsertMany( List< T > entities, InsertManyOptions opti throw new IllegalArgumentException("entities in operation can't be null or empty "); } - //ClientSession session = this.startSession(); Class< T > type = null; @@ -585,7 +583,7 @@ public < T > UpdateResult updateEntity( Query query, T entity, UpdateOptions opt if (entityDoc == null) { throw new IllegalArgumentException(); } - //ClientSession session = this.startSession(); + MongoCollection< ? > collection = this.getCollection(entity.getClass(), collectionName); collection = prepareConcern(collection, options); @@ -639,7 +637,7 @@ public < T > UpdateResult update( Query query, UpdateDefinition update, Class< T } - ClientSession session = this.startSession(); + MongoCollection< T > collection = this.getCollection(entityClass, collectionName); collection = prepareConcern(collection, options); @@ -647,9 +645,12 @@ public < T > UpdateResult update( Query query, UpdateDefinition update, Class< T //todo // 针对所有的 UpdateDefinition //getUpdateObject () 方法 在这里都需要处理 - return null; + throw new UnsupportedOperationException("UpdatePipeline is not supported in current version ") ; + //return null; } else { - UpdateResult result = updateDefinitionExecute(session, collection, query, options, update.getUpdateObject()); + + + UpdateResult result = updateDefinitionExecute( collection, query,options, update.getUpdateObject()); return result; } @@ -840,8 +841,6 @@ public < S, T > T findAndReplace( Query query, S replacement, FindOneAndReplaceO isTrue(query.getSkip() <= 0, "Query must not define skip."); - //MarsSession marsSession = this.startSession(); - if (entityType == resultType) { @@ -887,12 +886,11 @@ public < T > T findAndDelete( Query query, Class< T > entityClass, String collec notNull(entityClass, "EntityClass must not be null!"); notNull(collectionName, "CollectionName must not be null!"); - //MarsSession marsSession = this.startSession(); + MongoCollection< T > collection = this.database.getCollection(collectionName, entityClass); T oneAndDelete = this.operations.findOneAndDelete(collection, query.getQueryObject(), options.getOriginOptions()); - //T oneAndDelete = this.database.getCollection(collectionName, entityClass).findOneAndDelete(marsSession, query.getQueryObject(), options.getOriginOptions()); return oneAndDelete; @@ -923,14 +921,15 @@ private < T > T doFindAndModify( String collectionName, Query query, Class< T > @Override public void createIndex( Index index, String collectionName ) { - ClientSession session = this.startSession(); + //ClientSession session = this.startSession(); MongoCollection collection = database.getCollection(collectionName); // CrudExecutor crudExecutor = CrudExecutorFactory.create(CrudEnum.INDEX_CREATE_ONE); - createIndexExecute(session, collection, null, index.getIndexOptions(), index); + //createIndexExecute( collection, index.getIndexOptions(), index); + this.operations.createIndex(collection , new IndexModel(index.getIndexKeys(),index.getIndexOptions())); } @@ -947,41 +946,55 @@ public < T > void ensureIndexes( Class< T > entityClass, String collectionName ) @Override public void dropIndex( Index index, String collectionName ) { - ClientSession session = this.startSession(); + //ClientSession session = this.startSession(); MongoCollection collection = database.getCollection(collectionName); // CrudExecutor crudExecutor = CrudExecutorFactory.create(CrudEnum.INDEX_DROP_ONE); - dropOneIndexExecute(session, collection, null, null, index); + //dropOneIndexExecute(collection, index); + + collection.dropIndex(index.getIndexKeys()); + + this.operations.dropIndex(collection,index.getIndexKeys()); } @Override public void dropIndexes( String collectionName ) { - ClientSession session = this.startSession(); + //ClientSession session = this.startSession(); MongoCollection collection = database.getCollection(collectionName); // CrudExecutor crudExecutor = CrudExecutorFactory.create(CrudEnum.INDEX_DROP_MANY); - dropManyIndexExecute(session, collection, null, null, null); + //dropManyIndexExecute(session, collection, null, null, null); + + //collection.dropIndexes(); + this.operations.dropIndexes(collection); } @Override public List< Index > getIndexes( String collectionName ) { - ClientSession session = this.startSession(); + //ClientSession session = this.startSession(); MongoCollection collection = database.getCollection(collectionName); // CrudExecutor crudExecutor = CrudExecutorFactory.create(CrudEnum.INDEX_FIND); - List< Index > execute = findManyIndexExecute(session, collection, null, null, null); + //List< Index > execute = findManyIndexExecute(session, collection, null, null, null); + + //session.close(); + MongoCursor iterator = this.operations.getIndexes(collection).iterator(); - return execute; + List indexes = new ArrayList<>(); + while (iterator.hasNext()){ + indexes.add(IndexUtil.of(iterator.next())); + } + return indexes; } @@ -1359,6 +1372,8 @@ public MongoCollection< Document > doCreateView( String name, String collectionN database.createView(session, name, collectionName, getDocuments(pipeline.getInnerStage()), options); return database.getCollection(name, Document.class); } finally { + + lock.unlock(); } @@ -1841,32 +1856,32 @@ private < T > Optional< T > doFindOne( Query query, @Nullable Class< T > entityC public < T > QueryCursor< T > findDistinct( Query query, String field, String collectionName, Class< ? > entityClass, Class< T > resultClass ) { - ClientSession session = this.startSession(); + MongoCollection< ? > collection = this.getCollection(entityClass, collectionName); - QueryCursor< T > result = this.findDistinctExecute(session, collection, query, field, resultClass); + QueryCursor< T > result = this.findDistinctExecute( collection, query, field, resultClass); return result; } - private < T > QueryCursor< T > findDistinctExecute( ClientSession session, MongoCollection collection, Query query, String field, Class< T > resultClass ) { + private < T > QueryCursor< T > findDistinctExecute( MongoCollection collection, Query query, String field, Class< T > resultClass ) { DistinctIterable< T > distinctIterable; if (query != null) { - distinctIterable = collection.distinct(session, field, query.getQueryObject(), resultClass); + distinctIterable = collection.distinct( field, query.getQueryObject(), resultClass); if (query.getCollation().orElse(null) != null) { distinctIterable = distinctIterable.collation(query.getCollation().get()); } } else { - distinctIterable = collection.distinct(session, field, null, resultClass); + distinctIterable = collection.distinct(field, null, resultClass); } return new QueryCursor< T >(distinctIterable.iterator()); } + @Deprecated private < T > T insertOneExecute( ClientSession session, MongoCollection collection, InsertOneOptions options, Object data ) { - InsertOneResult insertOneResult; if (options == null) { @@ -1894,6 +1909,7 @@ private < T > T insertOneExecute( ClientSession session, MongoCollection collect return (T) insertOneResult; } + @Deprecated private < T > Collection< T > insertManyExecute( ClientSession session, MongoCollection collection, InsertManyOptions options, Collection< T > data ) { // InsertManyResult insertManyResult = new InsertManyResult(); @@ -1935,6 +1951,7 @@ private < T > Collection< T > insertManyExecute( ClientSession session, MongoCol return data; } + @Deprecated private < T > T updateExecute( ClientSession session, MongoCollection collection, Query query, UpdateOptions options, Object data ) { if (!(options instanceof UpdateOptions)) { @@ -1971,41 +1988,45 @@ private < T > T updateExecute( ClientSession session, MongoCollection collection } - private < T > T updateDefinitionExecute( ClientSession session, MongoCollection collection, Query query, Options options, Object data ) { - + @Deprecated + private < T > UpdateResult updateDefinitionExecute( MongoCollection collection, Query query, UpdateOptions options, Document data ) { +/* Document dd = (Document) data; dd.containsKey(UpdatePipeline.Updatepipeline); - List< Document > list = dd.getList(UpdatePipeline.Updatepipeline, Document.class); + List< Document > list = dd.getList(UpdatePipeline.Updatepipeline, Document.class);*/ - if (!(options instanceof UpdateOptions)) { + /* if (!(options instanceof UpdateOptions)) { throw new ClassCastException(); - } + }*/ - UpdateOptions option = (UpdateOptions) options; + //UpdateOptions option = (UpdateOptions) options; UpdateResult updateResult; - if (option.isMulti()) { + if (options.isMulti()) { - if (session == null) { + updateResult = this.operations.updateMany(collection , query.getQueryObject(), (Document)data, options.getOriginOptions()); + /* if (session == null) { updateResult = collection.updateMany(query.getQueryObject(), (Document) data, option.getOriginOptions()); } else { updateResult = collection.updateMany(session, query.getQueryObject(), (Document) data, option.getOriginOptions()); - } + }*/ - return (T) updateResult; + return updateResult; } else { + updateResult = this.operations.updateOne(collection ,query.getQueryObject() ,(Document) data, options.getOriginOptions()); + /* if (session == null) { updateResult = collection.updateOne(query.getQueryObject(), (Document) data, option.getOriginOptions()); } else { updateResult = collection.updateOne(session, query.getQueryObject(), (Document) data, option.getOriginOptions()); - } + }*/ - return (T) updateResult; + return updateResult; } @@ -2013,7 +2034,8 @@ private < T > T updateDefinitionExecute( ClientSession session, MongoCollection } - private < T > T createIndexExecute( ClientSession session, MongoCollection collection, Query query, Options options, Object data ) { + @Deprecated + private < T > T createIndexExecute( MongoCollection collection , Options options, Object data ) { Index index = (Index) data; @@ -2021,45 +2043,30 @@ private < T > T createIndexExecute( ClientSession session, MongoCollection colle if (indexOptions == null) { - if (session == null) { collection.createIndex(index.getIndexKeys()); - } else { - - collection.createIndex(session, index.getIndexKeys()); - - } } else { - if (session == null) { + collection.createIndex(index.getIndexKeys(), indexOptions.getOriginOptions()); - } else { - collection.createIndex(session, index.getIndexKeys(), indexOptions.getOriginOptions()); - } + } return null; } - private < T > T dropOneIndexExecute( ClientSession session, MongoCollection collection, Query query, Options options, Object data ) { - - Index index = (Index) data; + @Deprecated + private < T > void dropOneIndexExecute( MongoCollection collection, Index index ) { - if (session == null) { collection.dropIndex(index.getIndexKeys()); - } else { - collection.dropIndex(session, index.getIndexKeys()); - - } - - return null; } + @Deprecated private < T > T dropManyIndexExecute( ClientSession session, MongoCollection collection, Query query, Options options, Object data ) { if (session == null) { @@ -2073,6 +2080,8 @@ private < T > T dropManyIndexExecute( ClientSession session, MongoCollection col return null; } + + @Deprecated private < T > T findManyIndexExecute( ClientSession session, MongoCollection collection, Query query, Options options, Object data ) { ListIndexesIterable indexIterable = null; @@ -2084,14 +2093,8 @@ private < T > T findManyIndexExecute( ClientSession session, MongoCollection col indexIterable = collection.listIndexes(session); } - - MongoCursor iterator = indexIterable.iterator(); - - List indexes = new ArrayList(); - - while (iterator.hasNext()) { Document o = (Document) iterator.next(); @@ -2254,6 +2257,7 @@ private < T > T findManyIndexExecute( ClientSession session, MongoCollection col } + @Deprecated private < T > T createManyIndexExecute( ClientSession session, MongoCollection collection, Query query, Options options, Object data ) { List< Index > indexes = (List) data; @@ -2298,7 +2302,7 @@ private < T > T doTransaction( MarsSessionImpl marsSession, MarsTransaction< T > if (marsSession == null) { throw new IllegalStateException("No session could be found for the transaction."); } - return marsSession.getSession().withTransaction(() -> body.execute(marsSession)); + return marsSession.withTransaction(() -> body.execute(marsSession)); } catch (Exception e) { LOGGER.error(e.getMessage()); return null; @@ -2339,6 +2343,17 @@ private com.mongodb.client.model.CountOptions decorateCountOption( Query query ) public abstract static class DatastoreOperations { + public abstract < T > String createIndex( MongoCollection< T > collection, IndexModel index ); + + public abstract < T > void dropIndex( MongoCollection< T > collection, Document bsonkey ); + + public abstract < T > List< String > createIndexes( MongoCollection< T > collection, List< IndexModel > indexes ); + + public abstract < T > void dropIndexes( MongoCollection< T > collection ); + + public abstract < T > ListIndexesIterable< Document > getIndexes( MongoCollection< T > collection ); + + public abstract < T > long countDocuments( MongoCollection< T > collection, Document queryDocument, com.mongodb.client.model.CountOptions options ); public abstract < T > DeleteResult deleteMany( MongoCollection< T > collection, Document queryDocument, com.mongodb.client.model.DeleteOptions options ); @@ -2347,6 +2362,8 @@ public abstract static class DatastoreOperations { public abstract < E > FindIterable< E > find( MongoCollection< E > collection, Document queryDocument ); + public abstract < E > DistinctIterable< E > distinct( MongoCollection< E > collection, Document query, String fieldName, Class< E > resultClass ); + @Nullable public abstract < T > T findOneAndDelete( MongoCollection< T > collection, Document queryDocument, com.mongodb.client.model.FindOneAndDeleteOptions options ); @@ -2385,6 +2402,34 @@ public abstract < T > UpdateResult updateOne( MongoCollection< T > collection, D * @see com.whaleal.mars.session.MarsSessionImpl */ private class CollectionOperations extends DatastoreOperations { + + @Override + public String createIndex( MongoCollection collection, IndexModel index ) { + return collection.createIndex(index.getKeys(), index.getOptions()); + } + + + @Override + public < T > void dropIndex( MongoCollection< T > collection, Document bsonkey ) { + collection.dropIndex(bsonkey); + } + + @Override + public < T > List< String > createIndexes( MongoCollection< T > collection, List< IndexModel > indexes ) { + return collection.createIndexes(indexes); + } + + @Override + public < T > void dropIndexes( MongoCollection< T > collection ) { + collection.dropIndexes(); + } + + @Override + public < T > ListIndexesIterable< Document > getIndexes( MongoCollection< T > collection ) { + return collection.listIndexes(); + + } + @Override public < T > long countDocuments( MongoCollection< T > collection, Document query, com.mongodb.client.model.CountOptions options ) { return collection.countDocuments(query, options); @@ -2405,6 +2450,12 @@ public < E > FindIterable< E > find( MongoCollection< E > collection, Document q return collection.find(query); } + @Override + public < E > DistinctIterable< E > distinct( MongoCollection< E > collection, Document query, String fieldName, Class< E > resultClass ) { + + return collection.distinct(fieldName, query, resultClass); + } + @Override public < T > T findOneAndDelete( MongoCollection< T > collection, Document queryDocument, com.mongodb.client.model.FindOneAndDeleteOptions options ) { return collection.findOneAndDelete(queryDocument, options); diff --git a/mars-core/src/main/java/com/whaleal/mars/session/MarsSessionImpl.java b/mars-core/src/main/java/com/whaleal/mars/session/MarsSessionImpl.java index 1a20dfc0..4880dabc 100644 --- a/mars-core/src/main/java/com/whaleal/mars/session/MarsSessionImpl.java +++ b/mars-core/src/main/java/com/whaleal/mars/session/MarsSessionImpl.java @@ -32,11 +32,9 @@ import com.mongodb.ClientSessionOptions; import com.mongodb.ServerAddress; import com.mongodb.TransactionOptions; -import com.mongodb.client.ClientSession; -import com.mongodb.client.FindIterable; -import com.mongodb.client.MongoCollection; -import com.mongodb.client.TransactionBody; +import com.mongodb.client.*; import com.mongodb.client.model.FindOneAndReplaceOptions; +import com.mongodb.client.model.IndexModel; import com.mongodb.client.result.DeleteResult; import com.mongodb.client.result.InsertManyResult; import com.mongodb.client.result.InsertOneResult; @@ -229,6 +227,31 @@ public ClientSession getSession() { * */ private class TransactionalOperations extends DatastoreOperations { + @Override + public < T > String createIndex( MongoCollection< T > collection, IndexModel index ) { + return collection.createIndex(session,index.getKeys() ,index.getOptions()); + } + + @Override + public < T > void dropIndex( MongoCollection< T > collection, Document bsonkey ) { + collection.dropIndex(session,bsonkey); + } + + @Override + public < T > List< String > createIndexes( MongoCollection< T > collection, List< IndexModel > indexes ) { + return collection.createIndexes(session,indexes); + } + + @Override + public < T > void dropIndexes( MongoCollection< T > collection ) { + collection.dropIndexes(session); + } + + @Override + public < T > ListIndexesIterable< Document > getIndexes( MongoCollection< T > collection ) { + return null; + } + @Override public long countDocuments( MongoCollection collection, Document queryDocument, com.mongodb.client.model.CountOptions options) { return collection.countDocuments(session, queryDocument, options); @@ -249,6 +272,11 @@ public FindIterable find(MongoCollection collection, Document queryDoc return collection.find(session, queryDocument); } + @Override + public < E > DistinctIterable< E > distinct( MongoCollection< E > collection, Document query, String fieldName, Class< E > resultClass ) { + return collection.distinct(session , fieldName,query,resultClass); + } + @Override public T findOneAndDelete(MongoCollection mongoCollection, Document queryDocument, com.mongodb.client.model.FindOneAndDeleteOptions options) { return mongoCollection.findOneAndDelete(session, queryDocument, options); diff --git a/mars-core/src/main/java/com/whaleal/mars/util/Assert.java b/mars-core/src/main/java/com/whaleal/mars/util/Assert.java new file mode 100644 index 00000000..562c3a37 --- /dev/null +++ b/mars-core/src/main/java/com/whaleal/mars/util/Assert.java @@ -0,0 +1,299 @@ +/** + * Copyright 2020-present Shanghai Jinmu Information Technology Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by Shanghai Jinmu Information Technology Co., Ltd.(The name of the development team is Whaleal.) + * + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ +package com.whaleal.mars.util; + + + + +import com.mongodb.internal.async.SingleResultCallback; +import com.mongodb.lang.Nullable; +import com.whaleal.mars.core.query.MarsQueryException; + +import java.util.Collection; + +import static java.lang.String.format; + +/** + * Provides various assertions for Mars during validation + * + * + */ +public final class Assert { + private Assert() { + } + + /** + * Throws an QueryException with the given error message. + * + * @param error the error message + */ + public static void raiseError(String error) { + throw new MarsQueryException(error); + } + + /** + * Validates that all the parameters are not null + * + * @param names a comma separated String of parameter names + * @param objects the proposed parameter values + */ + public static void parametersNotNull(String names, Object... objects) { + String msgPrefix = "At least one of the parameters"; + + if (objects != null) { + if (objects.length == 1) { + msgPrefix = "Parameter"; + } + + for (Object object : objects) { + if (object == null) { + raiseError(String.format("%s '%s' is null.", msgPrefix, names)); + } + } + } + } + + /** + * Validates that the Iterable is not empty + * + * @param name the parameter name + * @param obj the proposed parameter value + */ + public static void parameterNotEmpty(String name, Iterable obj) { + if (!obj.iterator().hasNext()) { + raiseError(format("Parameter '%s' from type '%s' is expected to NOT be empty", name, obj.getClass().getName())); + } + } + + /** + * Validates that the value is not empty + * + * @param name the parameter name + * @param value the proposed parameter value + */ + public static void parameterNotEmpty(String name, String value) { + if (value != null && value.isEmpty()) { + raiseError(format("Parameter '%s' is expected to NOT be empty.", name)); + } + } + + + /** + * Throw IllegalArgumentException if the value is null. + * + * @param name the parameter name + * @param value the value that should not be null + * @param the value type + * @return the value + * @throws java.lang.IllegalArgumentException if value is null + */ + public static T notNull(final String name, final T value) { + if (value == null) { + throw new IllegalArgumentException(name + " can not be null"); + } + return value; + } + + /** + * Throw IllegalArgumentException if the values is null or contains null. + * + *

Note: If performance is a concern, consider deferring the integrity validation + * to the point of actual data iteration to avoid incurring additional reference chasing for collections of complex objects. + * However, if performance considerations are low and it is acceptable to iterate over the data twice, + * this method can still be used for validation purposes. + * + * @param name the parameter name. + * @param values the values that should not contain null elements. + * @param the type of elements in the collection. + * @return the input collection if it passes the null element validation. + * @throws java.lang.IllegalArgumentException if the input collection is null or contains null elements. + */ + public static Iterable notNullElements(final String name, final Iterable values) { + if (values == null) { + throw new IllegalArgumentException(name + " can not be null"); + } + + for (T value : values) { + if (value == null){ + throw new IllegalArgumentException(name + " can not contain null"); + } + } + + return values; + } + + /** + * Throw IllegalArgumentException if the value is null. + * + * @param name the parameter name + * @param value the value that should not be null + * @param callback the callback that also is passed the exception if the value is null + * @param the value type + * @return the value + * @throws java.lang.IllegalArgumentException if value is null + */ + public static T notNull(final String name, final T value, final SingleResultCallback callback) { + if (value == null) { + IllegalArgumentException exception = new IllegalArgumentException(name + " can not be null"); + callback.onResult(null, exception); + throw exception; + } + return value; + } + + /** + * Throw IllegalStateException if the condition if false. + * + * @param name the name of the state that is being checked + * @param condition the condition about the parameter to check + * @throws java.lang.IllegalStateException if the condition is false + */ + public static void isTrue(final String name, final boolean condition) { + if (!condition) { + throw new IllegalStateException("state should be: " + name); + } + } + + /** + * Throw IllegalStateException if the condition if false. + * + * @param name the name of the state that is being checked + * @param condition the condition about the parameter to check + * @param callback the callback that also is passed the exception if the condition is not true + * @throws java.lang.IllegalStateException if the condition is false + */ + public static void isTrue(final String name, final boolean condition, final SingleResultCallback callback) { + if (!condition) { + IllegalStateException exception = new IllegalStateException("state should be: " + name); + callback.onResult(null, exception); + throw exception; + } + } + + /** + * Throw IllegalArgumentException if the condition if false. + * + * @param name the name of the state that is being checked + * @param condition the condition about the parameter to check + * @throws java.lang.IllegalArgumentException if the condition is false + */ + public static void isTrueArgument(final String name, final boolean condition) { + if (!condition) { + throw new IllegalArgumentException("state should be: " + name); + } + } + + /** + * Throw IllegalArgumentException if the collection contains a null value. + * + * @param name the name of the collection + * @param collection the collection + * @throws java.lang.IllegalArgumentException if the collection contains a null value + */ + public static void doesNotContainNull(final String name, final Collection collection) { + // Use a loop instead of the contains method, as some implementations of that method will throw an exception if passed null as a + // parameter (in particular, lists returned by List.of methods) + for (Object o : collection) { + if (o == null) { + throw new IllegalArgumentException(name + " can not contain a null value"); + } + } + } + + /** + * @param value A value to check. + * @param The type of {@code value}. + * @return {@code null}. + * @throws AssertionError If {@code value} is not {@code null}. + */ + @Nullable + public static T assertNull(@Nullable final T value) throws AssertionError { + if (value != null) { + throw new AssertionError(value.toString()); + } + return null; + } + + /** + * @param value A value to check. + * @param The type of {@code value}. + * @return {@code value} + * @throws AssertionError If {@code value} is {@code null}. + */ + public static T assertNotNull(@Nullable final T value) throws AssertionError { + if (value == null) { + throw new AssertionError(); + } + return value; + } + + /** + * @param value A value to check. + * @return {@code true}. + * @throws AssertionError If {@code value} is {@code false}. + */ + public static boolean assertTrue(final boolean value) throws AssertionError { + if (!value) { + throw new AssertionError(); + } + return true; + } + + /** + * @param value A value to check. + * @return {@code false}. + * @throws AssertionError If {@code value} is {@code true}. + */ + public static boolean assertFalse(final boolean value) throws AssertionError { + if (value) { + throw new AssertionError(); + } + return false; + } + + /** + * @throws AssertionError Always + * @return Never completes normally. The return type is {@link AssertionError} to allow writing {@code throw fail()}. + * This may be helpful in non-{@code void} methods. + */ + public static AssertionError fail() throws AssertionError { + throw new AssertionError(); + } + + /** + * @param msg The failure message. + * @throws AssertionError Always + * @return Never completes normally. The return type is {@link AssertionError} to allow writing {@code throw fail("failure message")}. + * This may be helpful in non-{@code void} methods. + */ + public static AssertionError fail(final String msg) throws AssertionError { + throw new AssertionError(assertNotNull(msg)); + } +} diff --git a/mars-springboot/src/main/java/com/whaleal/mars/config/MarsAutoConfiguration.java b/mars-springboot/src/main/java/com/whaleal/mars/config/MarsAutoConfiguration.java index d81a5e37..5f756b72 100644 --- a/mars-springboot/src/main/java/com/whaleal/mars/config/MarsAutoConfiguration.java +++ b/mars-springboot/src/main/java/com/whaleal/mars/config/MarsAutoConfiguration.java @@ -103,20 +103,7 @@ public Mars mars( MongoClient client, MongoProperties properties, ApplicationCon public MongoClient mongo(ObjectProvider builderCustomizers, MongoClientSettings settings) { return (MongoClient)(new MongoClientFactory((List)builderCustomizers.orderedStream().collect(Collectors.toList()))).createMongoClient(settings); } - -/* @Bean - @ConditionalOnMissingBean({MarsSessionImpl.class}) - @ConditionalOnBean({Mars.class}) - public MarsSessionImpl marsSessionImpl(Mars mars) { - return mars.startSession(); - }*/ - -/* @Bean - @ConditionalOnMissingBean({MongoTransactionManager.class}) - @ConditionalOnClass(Mars.class) - public MongoTransactionManager mongoTransactionManager(Mars mars) { - return new MongoTransactionManager(mars); - }*/ + @Configuration( diff --git a/mars-springboot/src/main/java/com/whaleal/mars/config/transaction/MongoResourceHolder.java b/mars-springboot/src/main/java/com/whaleal/mars/config/transaction/MongoResourceHolder.java index eb296cd2..8c04517f 100644 --- a/mars-springboot/src/main/java/com/whaleal/mars/config/transaction/MongoResourceHolder.java +++ b/mars-springboot/src/main/java/com/whaleal/mars/config/transaction/MongoResourceHolder.java @@ -1,3 +1,4 @@ +/* package com.whaleal.mars.config.transaction; import com.mongodb.client.ClientSession; @@ -5,11 +6,13 @@ import org.springframework.lang.Nullable; import org.springframework.transaction.support.ResourceHolderSupport; +*/ /** * @author lyz * @desc * @create: 2022-10-31 16:32 - **/ + **//* + public class MongoResourceHolder extends ResourceHolderSupport { @@ -70,3 +73,4 @@ boolean hasServerSession() { } } +*/ diff --git a/mars-springboot/src/main/java/com/whaleal/mars/config/transaction/MongoTransactionManager.java b/mars-springboot/src/main/java/com/whaleal/mars/config/transaction/MongoTransactionManager.java index 7a74e02d..6add8471 100644 --- a/mars-springboot/src/main/java/com/whaleal/mars/config/transaction/MongoTransactionManager.java +++ b/mars-springboot/src/main/java/com/whaleal/mars/config/transaction/MongoTransactionManager.java @@ -1,3 +1,4 @@ +/* package com.whaleal.mars.config.transaction; import com.mongodb.MongoException; @@ -15,11 +16,13 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +*/ /** * @author lyz * @desc * @create: 2022-10-31 14:24 - **/ + **//* + public class MongoTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean { @@ -141,22 +144,26 @@ protected void doCleanupAfterCompletion(Object transaction) { mongoTransactionObject.closeSession(); } +*/ /* public void setDbFactory(MongoMappingContext dbFactory) { Assert.notNull(dbFactory, "DbFactory must not be null!"); this.dbFactory = dbFactory; } -*/ +*//* + public void setOptions(@Nullable TransactionOptions options) { this.options = options; } - /* @Nullable + */ +/* @Nullable public MongoMappingContext getDbFactory() { return this.dbFactory; - }*/ + }*//* + public MongoMappingContext getResourceFactory() { return this.getRequiredDbFactory(); @@ -288,3 +295,4 @@ public void flush() { } } +*/