|
|
|
@ -34,6 +34,7 @@ import org.jspecify.annotations.Nullable; |
|
|
|
import org.springframework.data.mongodb.core.mapping.Field; |
|
|
|
import org.springframework.data.mongodb.core.mapping.Field; |
|
|
|
import org.springframework.data.mongodb.core.query.Collation; |
|
|
|
import org.springframework.data.mongodb.core.query.Collation; |
|
|
|
import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty; |
|
|
|
import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty; |
|
|
|
|
|
|
|
import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty; |
|
|
|
import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.QueryableJsonSchemaProperty; |
|
|
|
import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.QueryableJsonSchemaProperty; |
|
|
|
import org.springframework.data.mongodb.core.schema.JsonSchemaProperty; |
|
|
|
import org.springframework.data.mongodb.core.schema.JsonSchemaProperty; |
|
|
|
import org.springframework.data.mongodb.core.schema.MongoJsonSchema; |
|
|
|
import org.springframework.data.mongodb.core.schema.MongoJsonSchema; |
|
|
|
@ -681,17 +682,16 @@ public class CollectionOptions { |
|
|
|
private static final EncryptedFieldsOptions NONE = new EncryptedFieldsOptions(); |
|
|
|
private static final EncryptedFieldsOptions NONE = new EncryptedFieldsOptions(); |
|
|
|
|
|
|
|
|
|
|
|
private final @Nullable MongoJsonSchema schema; |
|
|
|
private final @Nullable MongoJsonSchema schema; |
|
|
|
private final List<QueryableJsonSchemaProperty> queryableProperties; |
|
|
|
private final List<JsonSchemaProperty> properties; |
|
|
|
|
|
|
|
|
|
|
|
EncryptedFieldsOptions() { |
|
|
|
EncryptedFieldsOptions() { |
|
|
|
this(null, List.of()); |
|
|
|
this(null, List.of()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private EncryptedFieldsOptions(@Nullable MongoJsonSchema schema, |
|
|
|
private EncryptedFieldsOptions(@Nullable MongoJsonSchema schema, List<JsonSchemaProperty> queryableProperties) { |
|
|
|
List<QueryableJsonSchemaProperty> queryableProperties) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.schema = schema; |
|
|
|
this.schema = schema; |
|
|
|
this.queryableProperties = queryableProperties; |
|
|
|
this.properties = queryableProperties; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -711,7 +711,7 @@ public class CollectionOptions { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* @return new instance of {@link EncryptedFieldsOptions}. |
|
|
|
* @return new instance of {@link EncryptedFieldsOptions}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static EncryptedFieldsOptions fromProperties(List<QueryableJsonSchemaProperty> properties) { |
|
|
|
public static EncryptedFieldsOptions fromProperties(List<JsonSchemaProperty> properties) { |
|
|
|
return new EncryptedFieldsOptions(null, List.copyOf(properties)); |
|
|
|
return new EncryptedFieldsOptions(null, List.copyOf(properties)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -731,13 +731,50 @@ public class CollectionOptions { |
|
|
|
@CheckReturnValue |
|
|
|
@CheckReturnValue |
|
|
|
public EncryptedFieldsOptions queryable(JsonSchemaProperty property, QueryCharacteristic... characteristics) { |
|
|
|
public EncryptedFieldsOptions queryable(JsonSchemaProperty property, QueryCharacteristic... characteristics) { |
|
|
|
|
|
|
|
|
|
|
|
List<QueryableJsonSchemaProperty> targetPropertyList = new ArrayList<>(queryableProperties.size() + 1); |
|
|
|
List<JsonSchemaProperty> targetPropertyList = new ArrayList<>(properties.size() + 1); |
|
|
|
targetPropertyList.addAll(queryableProperties); |
|
|
|
targetPropertyList.addAll(properties); |
|
|
|
targetPropertyList.add(JsonSchemaProperty.queryable(property, List.of(characteristics))); |
|
|
|
targetPropertyList.add(JsonSchemaProperty.queryable(property, List.of(characteristics))); |
|
|
|
|
|
|
|
|
|
|
|
return new EncryptedFieldsOptions(schema, targetPropertyList); |
|
|
|
return new EncryptedFieldsOptions(schema, targetPropertyList); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Add an {@link EncryptedJsonSchemaProperty encrypted property} that should not be queryable. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param property must not be {@literal null}. |
|
|
|
|
|
|
|
* @return new instance of {@link EncryptedFieldsOptions}. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Contract("_ -> new") |
|
|
|
|
|
|
|
@CheckReturnValue |
|
|
|
|
|
|
|
public EncryptedFieldsOptions with(EncryptedJsonSchemaProperty property) { |
|
|
|
|
|
|
|
return encrypted(property, null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Add a {@link JsonSchemaProperty property} that should not be encrypted but not queryable. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param property must not be {@literal null}. |
|
|
|
|
|
|
|
* @param key can be {@literal null}. |
|
|
|
|
|
|
|
* @return new instance of {@link EncryptedFieldsOptions}. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Contract("_, _ -> new") |
|
|
|
|
|
|
|
@CheckReturnValue |
|
|
|
|
|
|
|
public EncryptedFieldsOptions encrypted(JsonSchemaProperty property, @Nullable Object key) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<JsonSchemaProperty> targetPropertyList = new ArrayList<>(properties.size() + 1); |
|
|
|
|
|
|
|
targetPropertyList.addAll(properties); |
|
|
|
|
|
|
|
if (property instanceof IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty) { |
|
|
|
|
|
|
|
targetPropertyList.add(property); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
EncryptedJsonSchemaProperty encryptedJsonSchemaProperty = new EncryptedJsonSchemaProperty(property); |
|
|
|
|
|
|
|
if (key != null) { |
|
|
|
|
|
|
|
targetPropertyList.add(encryptedJsonSchemaProperty.keyId(key)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new EncryptedFieldsOptions(schema, targetPropertyList); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public Document toDocument() { |
|
|
|
public Document toDocument() { |
|
|
|
return new Document("fields", selectPaths()); |
|
|
|
return new Document("fields", selectPaths()); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -756,12 +793,12 @@ public class CollectionOptions { |
|
|
|
|
|
|
|
|
|
|
|
private List<Document> fromProperties() { |
|
|
|
private List<Document> fromProperties() { |
|
|
|
|
|
|
|
|
|
|
|
if (queryableProperties.isEmpty()) { |
|
|
|
if (properties.isEmpty()) { |
|
|
|
return List.of(); |
|
|
|
return List.of(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
List<Document> converted = new ArrayList<>(queryableProperties.size()); |
|
|
|
List<Document> converted = new ArrayList<>(properties.size()); |
|
|
|
for (QueryableJsonSchemaProperty property : queryableProperties) { |
|
|
|
for (JsonSchemaProperty property : properties) { |
|
|
|
|
|
|
|
|
|
|
|
Document field = new Document("path", property.getIdentifier()); |
|
|
|
Document field = new Document("path", property.getIdentifier()); |
|
|
|
|
|
|
|
|
|
|
|
@ -769,7 +806,7 @@ public class CollectionOptions { |
|
|
|
field.append("bsonType", property.getTypes().iterator().next().toBsonType().value()); |
|
|
|
field.append("bsonType", property.getTypes().iterator().next().toBsonType().value()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (property |
|
|
|
if (property instanceof QueryableJsonSchemaProperty qproperty && qproperty |
|
|
|
.getTargetProperty() instanceof IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty encrypted) { |
|
|
|
.getTargetProperty() instanceof IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty encrypted) { |
|
|
|
if (encrypted.getKeyId() != null) { |
|
|
|
if (encrypted.getKeyId() != null) { |
|
|
|
if (encrypted.getKeyId() instanceof String stringKey) { |
|
|
|
if (encrypted.getKeyId() instanceof String stringKey) { |
|
|
|
@ -779,11 +816,21 @@ public class CollectionOptions { |
|
|
|
field.append("keyId", encrypted.getKeyId()); |
|
|
|
field.append("keyId", encrypted.getKeyId()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else if (property instanceof IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty encrypted) { |
|
|
|
|
|
|
|
if (encrypted.getKeyId() != null) { |
|
|
|
|
|
|
|
if (encrypted.getKeyId() instanceof String stringKey) { |
|
|
|
|
|
|
|
field.append("keyId", |
|
|
|
|
|
|
|
new BsonBinary(BsonBinarySubType.UUID_STANDARD, stringKey.getBytes(StandardCharsets.UTF_8))); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
field.append("keyId", encrypted.getKeyId()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
field.append("queries", StreamSupport.stream(property.getCharacteristics().spliterator(), false) |
|
|
|
if (property instanceof QueryableJsonSchemaProperty qproperty) { |
|
|
|
.map(QueryCharacteristic::toDocument).toList()); |
|
|
|
field.append("queries", StreamSupport.stream(qproperty.getCharacteristics().spliterator(), false) |
|
|
|
|
|
|
|
.map(QueryCharacteristic::toDocument).toList()); |
|
|
|
|
|
|
|
} |
|
|
|
if (!field.containsKey("keyId")) { |
|
|
|
if (!field.containsKey("keyId")) { |
|
|
|
field.append("keyId", BsonNull.VALUE); |
|
|
|
field.append("keyId", BsonNull.VALUE); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -812,7 +859,9 @@ public class CollectionOptions { |
|
|
|
if (entry.getValue().containsKey("bsonType")) { |
|
|
|
if (entry.getValue().containsKey("bsonType")) { |
|
|
|
field.append("bsonType", entry.getValue().get("bsonType")); |
|
|
|
field.append("bsonType", entry.getValue().get("bsonType")); |
|
|
|
} |
|
|
|
} |
|
|
|
field.put("queries", entry.getValue().get("queries")); |
|
|
|
if (entry.getValue().containsKey("queries")) { |
|
|
|
|
|
|
|
field.put("queries", entry.getValue().get("queries")); |
|
|
|
|
|
|
|
} |
|
|
|
fields.add(field); |
|
|
|
fields.add(field); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|