Compare commits
193 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdc78592ee | ||
|
|
ab97e58793 | ||
|
|
a4eeb9f305 | ||
|
|
de6c649c83 | ||
|
|
e90c6b0790 | ||
|
|
d2e68cd925 | ||
|
|
7ed48f5e76 | ||
|
|
2359357977 | ||
|
|
a90f238574 | ||
|
|
1c9188f7e1 | ||
|
|
a2f7c3f482 | ||
|
|
3440bf6c4d | ||
|
|
deed19187f | ||
|
|
c5f2abe037 | ||
|
|
6cce16414e | ||
|
|
a85855a307 | ||
|
|
31390d41e0 | ||
|
|
117ab7c033 | ||
|
|
73fbaaf3bd | ||
|
|
17937b0475 | ||
|
|
46943716ee | ||
|
|
25af5b5f79 | ||
|
|
a5a4c6d8c4 | ||
|
|
5885d084be | ||
|
|
d8fdc18265 | ||
|
|
840bde65e8 | ||
|
|
f2ee7d90c4 | ||
|
|
898489fecf | ||
|
|
3575d5461e | ||
|
|
4fa09d80db | ||
|
|
bb84b92d1d | ||
|
|
af85b46e7d | ||
|
|
96fbe49cdb | ||
|
|
6b36c792b9 | ||
|
|
006c8cfae2 | ||
|
|
14aed4c348 | ||
|
|
37165dd76d | ||
|
|
b22fd056aa | ||
|
|
42672a6df9 | ||
|
|
0b169d5341 | ||
|
|
b9d301e525 | ||
|
|
e3238593ce | ||
|
|
5d8370fa90 | ||
|
|
e01c745884 | ||
|
|
9ae3a29103 | ||
|
|
6a446cbc7f | ||
|
|
d40084f78e | ||
|
|
7bfbff0602 | ||
|
|
fc377cf0f9 | ||
|
|
d594afb5bb | ||
|
|
3012e228c5 | ||
|
|
0a947da7e4 | ||
|
|
eb85fb3a14 | ||
|
|
ebc8c5df3a | ||
|
|
5b52af4efe | ||
|
|
74161162b4 | ||
|
|
bcba123e32 | ||
|
|
935db07511 | ||
|
|
314b95370f | ||
|
|
20929b34f1 | ||
|
|
782bcd4d5f | ||
|
|
33fb40c872 | ||
|
|
bf61c5782e | ||
|
|
431e71f4a0 | ||
|
|
3192d7dd78 | ||
|
|
d7a6594933 | ||
|
|
609d6d5a19 | ||
|
|
19c8788376 | ||
|
|
db9934c7d8 | ||
|
|
b5679744e7 | ||
|
|
b1acda4188 | ||
|
|
2ab466eb35 | ||
|
|
e9da449667 | ||
|
|
6bc72a654f | ||
|
|
4fd9edf585 | ||
|
|
955597bb54 | ||
|
|
f59bbd351d | ||
|
|
43ab3cad13 | ||
|
|
5ba46dadb8 | ||
|
|
a245c0f280 | ||
|
|
288f244c34 | ||
|
|
90bb6262f9 | ||
|
|
826d00afa7 | ||
|
|
ac3f7dbf99 | ||
|
|
f70e1fa291 | ||
|
|
a84c4b064d | ||
|
|
1a65828365 | ||
|
|
f4f5e02e66 | ||
|
|
4b8d35262f | ||
|
|
b486fec048 | ||
|
|
50fcbd18f2 | ||
|
|
c37dfd9688 | ||
|
|
98d655f4e2 | ||
|
|
98a9b66e6b | ||
|
|
827b6204a9 | ||
|
|
781717faa8 | ||
|
|
084a167e20 | ||
|
|
456ae2459f | ||
|
|
d079edb92c | ||
|
|
eb97944fd4 | ||
|
|
e2d6f187c2 | ||
|
|
8068e36679 | ||
|
|
c62d13154f | ||
|
|
7d53f21d58 | ||
|
|
0000a8fd11 | ||
|
|
fad9756a93 | ||
|
|
54acc4934c | ||
|
|
2e593bb9b2 | ||
|
|
2bf32a25be | ||
|
|
148c4f9e24 | ||
|
|
ae6171802e | ||
|
|
1b97d1d1d0 | ||
|
|
91495825a5 | ||
|
|
18e6b9cfa7 | ||
|
|
0e0b8d5f79 | ||
|
|
11882724fa | ||
|
|
eb2a58cdbe | ||
|
|
8c9bbf7f91 | ||
|
|
63fc047160 | ||
|
|
44e872c7df | ||
|
|
1135e90be0 | ||
|
|
65da90afd8 | ||
|
|
4856c9b4f5 | ||
|
|
644c1a2c89 | ||
|
|
8df9d30d2e | ||
|
|
90ae6d1805 | ||
|
|
1fe79f1194 | ||
|
|
2c6bd6ecea | ||
|
|
fc5bb3f1d3 | ||
|
|
d4d9c7673a | ||
|
|
20e2cfb273 | ||
|
|
634f618eb1 | ||
|
|
c6e2662151 | ||
|
|
51ae618585 | ||
|
|
b584f04a41 | ||
|
|
6e1e9967af | ||
|
|
af49230093 | ||
|
|
3355a436c8 | ||
|
|
9a0241992e | ||
|
|
779145645d | ||
|
|
c0f3255e26 | ||
|
|
b1de52f05a | ||
|
|
646b525d86 | ||
|
|
2c29f204c3 | ||
|
|
9cd44faeb7 | ||
|
|
362de45664 | ||
|
|
b7317892a2 | ||
|
|
35f43e9ab8 | ||
|
|
a77c5b6e1d | ||
|
|
5cf8ec3e55 | ||
|
|
450549150d | ||
|
|
b7a0b1d523 | ||
|
|
5c5c616be9 | ||
|
|
0bd98d67c8 | ||
|
|
8302727b23 | ||
|
|
86dbd95220 | ||
|
|
3d0750afc5 | ||
|
|
1bf8eb09ca | ||
|
|
ae4cfaa58c | ||
|
|
1dea009e32 | ||
|
|
4c07235107 | ||
|
|
5ebbf93cf9 | ||
|
|
794756d055 | ||
|
|
4fcc09c6c1 | ||
|
|
d297f5a253 | ||
|
|
696e53ff60 | ||
|
|
f512d8cb16 | ||
|
|
b98bc0e2bf | ||
|
|
f64d205522 | ||
|
|
853b2b2d5c | ||
|
|
c3f9af01e6 | ||
|
|
655a1e0351 | ||
|
|
26395f1b78 | ||
|
|
ecd8dae876 | ||
|
|
4b59736f82 | ||
|
|
31d4434562 | ||
|
|
f5a339bfe4 | ||
|
|
5e60867750 | ||
|
|
8a5da0e737 | ||
|
|
e01ebcf605 | ||
|
|
b01a34b2b1 | ||
|
|
5650e35eb6 | ||
|
|
e5a41ad7f9 | ||
|
|
dd7d25cdb3 | ||
|
|
0ddd7e3afd | ||
|
|
81c501dea3 | ||
|
|
b1cd7cfa53 | ||
|
|
2ffac0a74e | ||
|
|
ded99a74a3 | ||
|
|
f275aaad7f | ||
|
|
5d2faef072 | ||
|
|
2c3cbb3613 | ||
|
|
2b635fa151 |
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,9 +1,12 @@
|
||||
<!--
|
||||
|
||||
Thank you for proposing a pull request. This template will guide you through the essential steps necessary for a pull request.
|
||||
Make sure that:
|
||||
|
||||
-->
|
||||
|
||||
- [ ] You have read the [Spring Data contribution guidelines](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc).
|
||||
- [ ] There is a ticket in the bug tracker for the project in our [JIRA](https://jira.spring.io/browse/DATAMONGO).
|
||||
- [ ] You use the code formatters provided [here](https://github.com/spring-projects/spring-data-build/tree/master/etc/ide) and have them applied to your changes. Don’t submit any formatting related changes.
|
||||
- [ ] You submit test cases (unit or integration tests) that back your changes.
|
||||
- [ ] You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).
|
||||
- [ ] You provide your full name and an email address registered with your GitHub account. If you’re a first-time submitter, make sure you have completed the [Contributor’s License Agreement form](https://support.springsource.com/spring_committer_signup).
|
||||
12
.travis.yml
12
.travis.yml
@@ -9,22 +9,20 @@ before_script:
|
||||
env:
|
||||
matrix:
|
||||
- PROFILE=ci
|
||||
- PROFILE=mongo3
|
||||
- PROFILE=mongo3-next
|
||||
- PROFILE=mongo31
|
||||
- PROFILE=mongo32
|
||||
- PROFILE=mongo33
|
||||
- PROFILE=mongo34-next
|
||||
- PROFILE=mongo35-next
|
||||
|
||||
# Current MongoDB version is 2.4.2 as of 2016-04, see https://github.com/travis-ci/travis-ci/issues/3694
|
||||
# apt-get starts a MongoDB instance so it's not started using before_script
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- mongodb-3.2-precise
|
||||
- mongodb-upstart
|
||||
- sourceline: 'deb [arch=amd64] http://repo.mongodb.org/apt/ubuntu precise/mongodb-org/3.4 multiverse'
|
||||
key_url: 'https://www.mongodb.org/static/pgp/server-3.4.asc'
|
||||
packages:
|
||||
- mongodb-org-server
|
||||
- mongodb-org-shell
|
||||
- oracle-java8-installer
|
||||
|
||||
sudo: false
|
||||
|
||||
|
||||
@@ -143,8 +143,8 @@ public class MyService {
|
||||
Here are some ways for you to get involved in the community:
|
||||
|
||||
* Get involved with the Spring community on Stackoverflow and help out on the [spring-data-mongodb](http://stackoverflow.com/questions/tagged/spring-data-mongodb) tag by responding to questions and joining the debate.
|
||||
* Create [JIRA](https://jira.springframework.org/browse/DATADOC) tickets for bugs and new features and comment and vote on the ones that you are interested in.
|
||||
* Create [JIRA](https://jira.spring.io/browse/DATAMONGO) tickets for bugs and new features and comment and vote on the ones that you are interested in.
|
||||
* Github is for social coding: if you want to write code, we encourage contributions through pull requests from [forks of this repository](http://help.github.com/forking/). If you want to contribute code this way, please reference a JIRA ticket as well covering the specific issue you are addressing.
|
||||
* Watch for upcoming articles on Spring by [subscribing](http://spring.io/blog) to spring.io.
|
||||
|
||||
Before we accept a non-trivial patch or pull request we will need you to sign the [contributor's agreement](https://support.springsource.com/spring_committer_signup). Signing the contributor's agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors might be asked to join the core team, and given the ability to merge pull requests.
|
||||
Before we accept a non-trivial patch or pull request we will need you to [sign the Contributor License Agreement](https://cla.pivotal.io/sign/spring). Signing the contributor’s agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. If you forget to do so, you'll be reminded when you submit a pull request. Active contributors might be asked to join the core team, and given the ability to merge pull requests.
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="12">
|
||||
<profile kind="CodeFormatterProfile" name="Spring Data" version="12">
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.source" value="1.7"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.7"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.7"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||
</profile>
|
||||
</profiles>
|
||||
86
pom.xml
86
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.0.0.M1</version>
|
||||
<version>2.0.0.M4</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.0.0.M1</version>
|
||||
<version>2.0.0.M4</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
@@ -28,9 +28,9 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>2.0.0.M1</springdata.commons>
|
||||
<mongo>3.2.2</mongo>
|
||||
<mongo.reactivestreams>1.2.0</mongo.reactivestreams>
|
||||
<springdata.commons>2.0.0.M4</springdata.commons>
|
||||
<mongo>3.4.2</mongo>
|
||||
<mongo.reactivestreams>1.5.0</mongo.reactivestreams>
|
||||
</properties>
|
||||
|
||||
<developers>
|
||||
@@ -114,70 +114,28 @@
|
||||
</developers>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
|
||||
<id>mongo3</id>
|
||||
<properties>
|
||||
<mongo>3.0.4</mongo>
|
||||
</properties>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo3-next</id>
|
||||
<properties>
|
||||
<mongo>3.0.5-SNAPSHOT</mongo>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>mongo-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo31</id>
|
||||
<properties>
|
||||
<mongo>3.1.1</mongo>
|
||||
</properties>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo32</id>
|
||||
<properties>
|
||||
<mongo>3.2.2</mongo>
|
||||
</properties>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo33</id>
|
||||
<properties>
|
||||
<mongo>3.3.0</mongo>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>mongo-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo34-next</id>
|
||||
<properties>
|
||||
<mongo>3.4.0-SNAPSHOT</mongo>
|
||||
<mongo>3.4.3-SNAPSHOT</mongo>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>mongo-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
|
||||
<id>mongo35-next</id>
|
||||
<properties>
|
||||
<mongo>3.5.0-SNAPSHOT</mongo>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.0.0.M1</version>
|
||||
<version>2.0.0.M4</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>2.0.0.M1</version>
|
||||
<version>2.0.0.M4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- reactive -->
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
<mongo:mapping-converter/>
|
||||
|
||||
<!-- Mongo config -->
|
||||
<bean id="mongo" class="org.springframework.data.mongodb.core.MongoClientFactoryBean">
|
||||
<bean id="mongoClient" class="org.springframework.data.mongodb.core.MongoClientFactoryBean">
|
||||
<property name="host" value="localhost"/>
|
||||
<property name="port" value="27017"/>
|
||||
</bean>
|
||||
|
||||
<bean id="mongoDbFactory" class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
|
||||
<constructor-arg name="mongo" ref="mongo"/>
|
||||
<constructor-arg name="mongoClient" ref="mongoClient"/>
|
||||
<constructor-arg name="databaseName" value="database"/>
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.0.0.M1</version>
|
||||
<version>2.0.0.M4</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# MongoDB Log4J Appender
|
||||
|
||||
:warning: Deprecated. About to be removed for 2.0.0.RC1.
|
||||
|
||||
This module sets up a Log4J appender that puts logging events in MongoDB. It is fully configurable
|
||||
and connects directly to the MongoDB server using the driver. It has no dependency on any Spring package.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.0.0.M1</version>
|
||||
<version>2.0.0.M4</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.data.mongodb.log4j;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.AppenderSkeleton;
|
||||
@@ -31,15 +33,20 @@ import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
* Log4j appender writing log entries into a MongoDB instance.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @auhtor Christoph Strobl
|
||||
* @author Christoph Strobl
|
||||
* @author Ricardo Espirito Santo
|
||||
* @deprecated since 2.0.0.M4. About to be removed for 2.0.0.RC1.
|
||||
*/
|
||||
@Deprecated
|
||||
public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
|
||||
public static final String LEVEL = "level";
|
||||
@@ -56,6 +63,9 @@ public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
|
||||
protected String host = "localhost";
|
||||
protected int port = 27017;
|
||||
protected String username;
|
||||
protected String password;
|
||||
protected String authenticationDatabase;
|
||||
protected String database = "logs";
|
||||
protected String collectionPattern = "%c";
|
||||
protected PatternLayout collectionLayout = new PatternLayout(collectionPattern);
|
||||
@@ -65,8 +75,7 @@ public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
protected Mongo mongo;
|
||||
protected DB db;
|
||||
|
||||
public MongoLog4jAppender() {
|
||||
}
|
||||
public MongoLog4jAppender() {}
|
||||
|
||||
public MongoLog4jAppender(boolean isActive) {
|
||||
super(isActive);
|
||||
@@ -88,6 +97,53 @@ public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param username may be {@literal null} for unauthenticated access.
|
||||
* @since 1.10
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param password may be {@literal null} for unauthenticated access.
|
||||
* @since 1.10
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String getAuthenticationDatabase() {
|
||||
return authenticationDatabase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authenticationDatabase may be {@literal null} to use {@link #getDatabase()} as authentication database.
|
||||
* @since 1.10
|
||||
*/
|
||||
public void setAuthenticationDatabase(String authenticationDatabase) {
|
||||
this.authenticationDatabase = authenticationDatabase;
|
||||
}
|
||||
|
||||
public String getDatabase() {
|
||||
return database;
|
||||
}
|
||||
@@ -113,14 +169,14 @@ public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
this.applicationId = applicationId;
|
||||
}
|
||||
|
||||
public void setWarnOrHigherWriteConcern(String wc) {
|
||||
this.warnOrHigherWriteConcern = WriteConcern.valueOf(wc);
|
||||
}
|
||||
|
||||
public String getWarnOrHigherWriteConcern() {
|
||||
return warnOrHigherWriteConcern.toString();
|
||||
}
|
||||
|
||||
public void setWarnOrHigherWriteConcern(String wc) {
|
||||
this.warnOrHigherWriteConcern = WriteConcern.valueOf(wc);
|
||||
}
|
||||
|
||||
public String getInfoOrLowerWriteConcern() {
|
||||
return infoOrLowerWriteConcern.toString();
|
||||
}
|
||||
@@ -130,10 +186,26 @@ public class MongoLog4jAppender extends AppenderSkeleton {
|
||||
}
|
||||
|
||||
protected void connectToMongo() throws UnknownHostException {
|
||||
this.mongo = new MongoClient(host, port);
|
||||
|
||||
this.mongo = createMongoClient();
|
||||
this.db = mongo.getDB(database);
|
||||
}
|
||||
|
||||
private MongoClient createMongoClient() throws UnknownHostException {
|
||||
|
||||
ServerAddress serverAddress = new ServerAddress(host, port);
|
||||
|
||||
if (null == password || null == username) {
|
||||
return new MongoClient(serverAddress);
|
||||
}
|
||||
|
||||
String authenticationDatabaseToUse = authenticationDatabase == null ? this.database : authenticationDatabase;
|
||||
MongoCredential mongoCredential = MongoCredential.createCredential(username,
|
||||
authenticationDatabaseToUse, password.toCharArray());
|
||||
List<MongoCredential> credentials = Collections.singletonList(mongoCredential);
|
||||
return new MongoClient(serverAddress, credentials);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
* Infrastructure for to use MongoDB as a logging sink.
|
||||
*
|
||||
* @deprecated since 2.0.0.M4. About to be removed for 2.0.0.RC1.
|
||||
*/
|
||||
package org.springframework.data.mongodb.log4j;
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.log4j;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.MDC;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCursor;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MongoLog4jAppender} using authentication.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MongoLog4jAppenderAuthenticationIntegrationTests {
|
||||
|
||||
private final static String username = "admin";
|
||||
private final static String password = "test";
|
||||
private final static String authenticationDatabase = "logs";
|
||||
|
||||
MongoClient mongo;
|
||||
DB db;
|
||||
String collection;
|
||||
ServerAddress serverLocation;
|
||||
|
||||
Logger log;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
serverLocation = new ServerAddress("localhost", 27017);
|
||||
|
||||
mongo = new MongoClient(serverLocation);
|
||||
db = mongo.getDB("logs");
|
||||
|
||||
BasicDBList roles = new BasicDBList();
|
||||
roles.add("dbOwner");
|
||||
db.command(new BasicDBObjectBuilder().add("createUser", username).add("pwd", password).add("roles", roles).get());
|
||||
mongo.close();
|
||||
|
||||
mongo = new MongoClient(serverLocation, Collections
|
||||
.singletonList(MongoCredential.createCredential(username, authenticationDatabase, password.toCharArray())));
|
||||
db = mongo.getDB("logs");
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
collection = String.valueOf(now.get(Calendar.YEAR)) + String.format("%1$02d", now.get(Calendar.MONTH) + 1);
|
||||
|
||||
LogManager.resetConfiguration();
|
||||
PropertyConfigurator.configure(getClass().getResource("/log4j-with-authentication.properties"));
|
||||
|
||||
log = Logger.getLogger(MongoLog4jAppenderIntegrationTests.class.getName());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
|
||||
if (db != null) {
|
||||
db.getCollection(collection).remove(new BasicDBObject());
|
||||
db.command(new BasicDBObject("dropUser", username));
|
||||
}
|
||||
|
||||
LogManager.resetConfiguration();
|
||||
PropertyConfigurator.configure(getClass().getResource("/log4j.properties"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogging() {
|
||||
|
||||
log.debug("DEBUG message");
|
||||
log.info("INFO message");
|
||||
log.warn("WARN message");
|
||||
log.error("ERROR message");
|
||||
|
||||
DBCursor msgs = db.getCollection(collection).find();
|
||||
assertThat(msgs.count(), is(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProperties() {
|
||||
MDC.put("property", "one");
|
||||
log.debug("DEBUG message");
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,10 @@ import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.MDC;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -30,31 +32,34 @@ import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCursor;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.ServerAddress;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MongoLog4jAppender}.
|
||||
*
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoLog4jAppenderIntegrationTests {
|
||||
|
||||
static final String NAME = MongoLog4jAppenderIntegrationTests.class.getName();
|
||||
|
||||
private static final Logger log = Logger.getLogger(NAME);
|
||||
MongoClient mongo;
|
||||
DB db;
|
||||
String collection;
|
||||
ServerAddress serverLocation;
|
||||
Logger log;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
serverLocation = new ServerAddress("localhost", 27017);
|
||||
|
||||
mongo = new MongoClient("localhost", 27017);
|
||||
mongo = new MongoClient(serverLocation);
|
||||
db = mongo.getDB("logs");
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
collection = String.valueOf(now.get(Calendar.YEAR)) + String.format("%1$02d", now.get(Calendar.MONTH) + 1);
|
||||
|
||||
log = Logger.getLogger(MongoLog4jAppenderIntegrationTests.class.getName());
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -76,7 +81,6 @@ public class MongoLog4jAppenderIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void testProperties() {
|
||||
|
||||
MDC.put("property", "one");
|
||||
log.debug("DEBUG message");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,10 +24,7 @@ import org.junit.Test;
|
||||
*/
|
||||
public class MongoLog4jAppenderUnitTests {
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-641
|
||||
*/
|
||||
@Test
|
||||
@Test // DATAMONGO-641
|
||||
public void closesWithoutMongoInstancePresent() {
|
||||
new MongoLog4jAppender().close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
log4j.rootCategory=INFO, mongo
|
||||
|
||||
log4j.appender.mongo=org.springframework.data.mongodb.log4j.MongoLog4jAppender
|
||||
log4j.appender.mongo.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.mongo.layout.ConversionPattern=%d %p [%c] - <%m>%n
|
||||
log4j.appender.mongo.host = localhost
|
||||
log4j.appender.mongo.port = 27017
|
||||
log4j.appender.mongo.database = logs
|
||||
log4j.appender.mongo.username = admin
|
||||
log4j.appender.mongo.password = test
|
||||
log4j.appender.mongo.authenticationDatabase = logs
|
||||
log4j.appender.mongo.collectionPattern = %X{year}%X{month}
|
||||
log4j.appender.mongo.applicationId = my.application
|
||||
log4j.appender.mongo.warnOrHigherWriteConcern = FSYNC_SAFE
|
||||
|
||||
log4j.category.org.springframework.data.mongodb=DEBUG
|
||||
@@ -1,13 +1,13 @@
|
||||
log4j.rootCategory=INFO, stdout
|
||||
log4j.rootCategory=INFO, mongo
|
||||
|
||||
log4j.appender.stdout=org.springframework.data.mongodb.log4j.MongoLog4jAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
|
||||
log4j.appender.stdout.host = localhost
|
||||
log4j.appender.stdout.port = 27017
|
||||
log4j.appender.stdout.database = logs
|
||||
log4j.appender.stdout.collectionPattern = %X{year}%X{month}
|
||||
log4j.appender.stdout.applicationId = my.application
|
||||
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE
|
||||
log4j.appender.mongo=org.springframework.data.mongodb.log4j.MongoLog4jAppender
|
||||
log4j.appender.mongo.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.mongo.layout.ConversionPattern=%d %p [%c] - <%m>%n
|
||||
log4j.appender.mongo.host = localhost
|
||||
log4j.appender.mongo.port = 27017
|
||||
log4j.appender.mongo.database = logs
|
||||
log4j.appender.mongo.collectionPattern = %X{year}%X{month}
|
||||
log4j.appender.mongo.applicationId = my.application
|
||||
log4j.appender.mongo.warnOrHigherWriteConcern = FSYNC_SAFE
|
||||
|
||||
log4j.category.org.springframework.data.mongodb=DEBUG
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.0.0.M1</version>
|
||||
<version>2.0.0.M4</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<objenesis>1.3</objenesis>
|
||||
<equalsverifier>1.5</equalsverifier>
|
||||
<mongo>3.3.0</mongo>
|
||||
<kotlin>1.1.2-5</kotlin>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -111,6 +111,13 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<version>${reactor}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.reactivex</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
@@ -125,6 +132,13 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.reactivex.rxjava2</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
<version>${rxjava2}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- CDI -->
|
||||
<dependency>
|
||||
<groupId>javax.enterprise</groupId>
|
||||
@@ -218,11 +232,117 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Kotlin extension -->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${kotlin}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<version>${kotlin}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test</artifactId>
|
||||
<version>${kotlin}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nhaarman</groupId>
|
||||
<artifactId>mockito-kotlin</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<version>${kotlin}</version>
|
||||
<configuration>
|
||||
<jvmTarget>${source.level}</jvmTarget>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
|
||||
<sourceDir>${project.basedir}/src/main/java</sourceDir>
|
||||
</sourceDirs>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
|
||||
<sourceDir>${project.basedir}/src/test/java</sourceDir>
|
||||
</sourceDirs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-compile</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>default-testCompile</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>java-compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>java-test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.mysema.maven</groupId>
|
||||
<artifactId>apt-maven-plugin</artifactId>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.mongodb.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||
@@ -26,12 +25,11 @@ import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* Base class for Spring Data MongoDB configuration using JavaConfig.
|
||||
*
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
@@ -41,35 +39,21 @@ import com.mongodb.MongoClient;
|
||||
* @see MongoConfigurationSupport
|
||||
*/
|
||||
@Configuration
|
||||
public abstract class AbstractMongoConfiguration extends MongoConfigurationSupport {
|
||||
public abstract class
|
||||
AbstractMongoConfiguration extends MongoConfigurationSupport {
|
||||
|
||||
/**
|
||||
* Return the name of the authentication database to use. Defaults to {@literal null} and will turn into the value
|
||||
* returned by {@link #getDatabaseName()} later on effectively.
|
||||
*
|
||||
* Return the {@link MongoClient} instance to connect to. Annotate with {@link Bean} in case you want to expose a
|
||||
* {@link MongoClient} instance to the {@link org.springframework.context.ApplicationContext}.
|
||||
*
|
||||
* @return
|
||||
* @deprecated since 1.7. {@link MongoClient} should hold authentication data within
|
||||
* {@link MongoClient#getCredentialsList()}
|
||||
*/
|
||||
@Deprecated
|
||||
protected String getAuthenticationDatabaseName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Mongo} instance to connect to. Annotate with {@link Bean} in case you want to expose a
|
||||
* {@link Mongo} instance to the {@link org.springframework.context.ApplicationContext}.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public abstract Mongo mongo() throws Exception;
|
||||
public abstract MongoClient mongoClient();
|
||||
|
||||
/**
|
||||
* Creates a {@link MongoTemplate}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public MongoTemplate mongoTemplate() throws Exception {
|
||||
@@ -77,17 +61,16 @@ public abstract class AbstractMongoConfiguration extends MongoConfigurationSuppo
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SimpleMongoDbFactory} to be used by the {@link MongoTemplate}. Will use the {@link Mongo} instance
|
||||
* configured in {@link #mongo()}.
|
||||
*
|
||||
* @see #mongo()
|
||||
* Creates a {@link SimpleMongoDbFactory} to be used by the {@link MongoTemplate}. Will use the {@link MongoClient}
|
||||
* instance configured in {@link #mongo()}.
|
||||
*
|
||||
* @see #mongoClient()
|
||||
* @see #mongoTemplate()
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public MongoDbFactory mongoDbFactory() throws Exception {
|
||||
return new SimpleMongoDbFactory(mongo(), getDatabaseName(), getUserCredentials(), getAuthenticationDatabaseName());
|
||||
public MongoDbFactory mongoDbFactory() {
|
||||
return new SimpleMongoDbFactory(mongoClient(), getDatabaseName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,23 +90,10 @@ public abstract class AbstractMongoConfiguration extends MongoConfigurationSuppo
|
||||
return mappingBasePackage == null ? null : mappingBasePackage.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link UserCredentials} to be used when connecting to the MongoDB instance or {@literal null} if none shall
|
||||
* be used.
|
||||
*
|
||||
* @return
|
||||
* @deprecated since 1.7. {@link MongoClient} should hold authentication data within
|
||||
* {@link MongoClient#getCredentialsList()}
|
||||
*/
|
||||
@Deprecated
|
||||
protected UserCredentials getUserCredentials() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link MappingMongoConverter} using the configured {@link #mongoDbFactory()} and
|
||||
* {@link #mongoMappingContext()}. Will get {@link #customConversions()} applied.
|
||||
*
|
||||
*
|
||||
* @see #customConversions()
|
||||
* @see #mongoMappingContext()
|
||||
* @see #mongoDbFactory()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2014 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,13 +21,14 @@ package org.springframework.data.mongodb.config;
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @author Martin Baumgartner
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public abstract class BeanNames {
|
||||
|
||||
public static final String MAPPING_CONTEXT_BEAN_NAME = "mongoMappingContext";
|
||||
|
||||
static final String INDEX_HELPER_BEAN_NAME = "indexCreationHelper";
|
||||
static final String MONGO_BEAN_NAME = "mongo";
|
||||
static final String MONGO_BEAN_NAME = "mongoClient";
|
||||
static final String DB_FACTORY_BEAN_NAME = "mongoDbFactory";
|
||||
static final String VALIDATING_EVENT_LISTENER_BEAN_NAME = "validatingMongoEventListener";
|
||||
static final String IS_NEW_STRATEGY_FACTORY_BEAN_NAME = "isNewStrategyFactory";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -53,8 +53,9 @@ import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
||||
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
|
||||
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
@@ -121,11 +122,15 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||
converterBuilder.addPropertyValue("customConversions", conversionsDefinition);
|
||||
}
|
||||
|
||||
if(!registry.containsBeanDefinition("indexOperationsProvider")){
|
||||
if (!registry.containsBeanDefinition("indexOperationsProvider")) {
|
||||
|
||||
BeanDefinitionBuilder indexOperationsProviderBuilder = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.data.mongodb.core.DefaultIndexOperationsProvider");
|
||||
BeanDefinitionBuilder indexOperationsProviderBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition("org.springframework.data.mongodb.core.DefaultIndexOperationsProvider");
|
||||
indexOperationsProviderBuilder.addConstructorArgReference(dbFactoryRef);
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(indexOperationsProviderBuilder.getBeanDefinition(), "indexOperationsProvider"));
|
||||
indexOperationsProviderBuilder.addConstructorArgValue(BeanDefinitionBuilder
|
||||
.genericBeanDefinition(QueryMapper.class).addConstructorArgReference(id).getBeanDefinition());
|
||||
parserContext.registerBeanComponent(
|
||||
new BeanComponentDefinition(indexOperationsProviderBuilder.getBeanDefinition(), "indexOperationsProvider"));
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -138,15 +143,15 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||
indexHelperBuilder.addConstructorArgReference("indexOperationsProvider");
|
||||
indexHelperBuilder.addDependsOn(ctxRef);
|
||||
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(),
|
||||
INDEX_HELPER_BEAN_NAME));
|
||||
parserContext.registerBeanComponent(
|
||||
new BeanComponentDefinition(indexHelperBuilder.getBeanDefinition(), INDEX_HELPER_BEAN_NAME));
|
||||
}
|
||||
|
||||
BeanDefinition validatingMongoEventListener = potentiallyCreateValidatingMongoEventListener(element, parserContext);
|
||||
|
||||
if (validatingMongoEventListener != null) {
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(validatingMongoEventListener,
|
||||
VALIDATING_EVENT_LISTENER_BEAN_NAME));
|
||||
parserContext.registerBeanComponent(
|
||||
new BeanComponentDefinition(validatingMongoEventListener, VALIDATING_EVENT_LISTENER_BEAN_NAME));
|
||||
}
|
||||
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(converterBuilder.getBeanDefinition(), id));
|
||||
@@ -285,7 +290,7 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder conversionsBuilder = BeanDefinitionBuilder.rootBeanDefinition(CustomConversions.class);
|
||||
BeanDefinitionBuilder conversionsBuilder = BeanDefinitionBuilder.rootBeanDefinition(MongoCustomConversions.class);
|
||||
conversionsBuilder.addConstructorArgValue(converterBeans);
|
||||
|
||||
AbstractBeanDefinition conversionsBean = conversionsBuilder.getBeanDefinition();
|
||||
@@ -333,8 +338,8 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||
return beanDef;
|
||||
}
|
||||
|
||||
parserContext.getReaderContext().error(
|
||||
"Element <converter> must specify 'ref' or contain a bean definition for the converter", element);
|
||||
parserContext.getReaderContext()
|
||||
.error("Element <converter> must specify 'ref' or contain a bean definition for the converter", element);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -346,8 +351,8 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||
mappingContextStrategyFactoryBuilder.addConstructorArgReference(mappingContextRef);
|
||||
|
||||
BeanComponentDefinitionBuilder builder = new BeanComponentDefinitionBuilder(element, context);
|
||||
context.registerBeanComponent(builder.getComponent(mappingContextStrategyFactoryBuilder,
|
||||
IS_NEW_STRATEGY_FACTORY_BEAN_NAME));
|
||||
context.registerBeanComponent(
|
||||
builder.getComponent(mappingContextStrategyFactoryBuilder, IS_NEW_STRATEGY_FACTORY_BEAN_NAME));
|
||||
|
||||
return IS_NEW_STRATEGY_FACTORY_BEAN_NAME;
|
||||
}
|
||||
@@ -367,7 +372,9 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||
* @param filters
|
||||
*/
|
||||
public NegatingFilter(TypeFilter... filters) {
|
||||
Assert.notNull(filters);
|
||||
|
||||
Assert.notNull(filters, "TypeFilters must not be null");
|
||||
|
||||
this.delegates = new HashSet<TypeFilter>(Arrays.asList(filters));
|
||||
}
|
||||
|
||||
@@ -375,7 +382,8 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.type.filter.TypeFilter#match(org.springframework.core.type.classreading.MetadataReader, org.springframework.core.type.classreading.MetadataReaderFactory)
|
||||
*/
|
||||
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
|
||||
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
|
||||
throws IOException {
|
||||
|
||||
for (TypeFilter delegate : delegates) {
|
||||
if (delegate.match(metadataReader, metadataReaderFactory)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mongodb.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -28,20 +27,14 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.convert.CustomConversions;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.convert.CustomConversions;
|
||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.support.CachingIsNewStrategyFactory;
|
||||
@@ -49,9 +42,6 @@ import org.springframework.data.support.IsNewStrategyFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* Base class for Spring Data MongoDB to be extended for JavaConfiguration usage.
|
||||
*
|
||||
@@ -62,7 +52,7 @@ public abstract class MongoConfigurationSupport {
|
||||
|
||||
/**
|
||||
* Return the name of the database to connect to.
|
||||
*
|
||||
*
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
protected abstract String getDatabaseName();
|
||||
@@ -72,7 +62,7 @@ public abstract class MongoConfigurationSupport {
|
||||
* configuration class' (the concrete class, not this one here) by default. So if you have a
|
||||
* {@code com.acme.AppConfig} extending {@link MongoConfigurationSupport} the base package will be considered
|
||||
* {@code com.acme} unless the method is overridden to implement alternate behavior.
|
||||
*
|
||||
*
|
||||
* @return the base packages to scan for mapped {@link Document} classes or an empty collection to not enable scanning
|
||||
* for entities.
|
||||
* @since 1.10
|
||||
@@ -85,8 +75,8 @@ public abstract class MongoConfigurationSupport {
|
||||
|
||||
/**
|
||||
* Creates a {@link MongoMappingContext} equipped with entity classes scanned from the mapping base package.
|
||||
*
|
||||
* @see #getMappingBasePackage()
|
||||
*
|
||||
* @see #getMappingBasePackages()
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
@@ -117,13 +107,13 @@ public abstract class MongoConfigurationSupport {
|
||||
/**
|
||||
* Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
|
||||
* {@link CustomConversions} will be registered with the {@link #mappingMongoConverter()} and
|
||||
* {@link #mongoMappingContext()}. Returns an empty {@link CustomConversions} instance by default.
|
||||
* {@link #mongoMappingContext()}. Returns an empty {@link MongoCustomConversions} instance by default.
|
||||
*
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
@Bean
|
||||
public CustomConversions customConversions() {
|
||||
return new CustomConversions(Collections.emptyList());
|
||||
return new MongoCustomConversions(Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 by the original author(s).
|
||||
* Copyright 2011-2017 by the original author(s).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,7 +30,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
||||
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||
@@ -99,8 +98,6 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
||||
String mongoRef = element.getAttribute("mongo-ref");
|
||||
String dbname = element.getAttribute("dbname");
|
||||
|
||||
BeanDefinition userCredentials = getUserCredentialsBeanDefinition(element, parserContext);
|
||||
|
||||
// Defaulting
|
||||
if (StringUtils.hasText(mongoRef)) {
|
||||
dbFactoryBuilder.addConstructorArgReference(mongoRef);
|
||||
@@ -109,8 +106,6 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
||||
}
|
||||
|
||||
dbFactoryBuilder.addConstructorArgValue(StringUtils.hasText(dbname) ? dbname : "db");
|
||||
dbFactoryBuilder.addConstructorArgValue(userCredentials);
|
||||
dbFactoryBuilder.addConstructorArgValue(element.getAttribute("authentication-dbname"));
|
||||
|
||||
BeanDefinitionBuilder writeConcernPropertyEditorBuilder = getWriteConcernPropertyEditorBuilder();
|
||||
|
||||
@@ -138,28 +133,6 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
||||
return getSourceBeanDefinition(mongoBuilder, parserContext, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link BeanDefinition} for a {@link UserCredentials} object.
|
||||
*
|
||||
* @param element
|
||||
* @return the {@link BeanDefinition} or {@literal null} if neither username nor password given.
|
||||
*/
|
||||
private BeanDefinition getUserCredentialsBeanDefinition(Element element, ParserContext context) {
|
||||
|
||||
String username = element.getAttribute("username");
|
||||
String password = element.getAttribute("password");
|
||||
|
||||
if (!StringUtils.hasText(username) && !StringUtils.hasText(password)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder userCredentialsBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserCredentials.class);
|
||||
userCredentialsBuilder.addConstructorArgValue(StringUtils.hasText(username) ? username : null);
|
||||
userCredentialsBuilder.addConstructorArgValue(StringUtils.hasText(password) ? password : null);
|
||||
|
||||
return getSourceBeanDefinition(userCredentialsBuilder, context, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link BeanDefinition} for a {@link MongoURI} or {@link MongoClientURI} depending on configured
|
||||
* attributes. <br />
|
||||
@@ -193,7 +166,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
||||
parserContext.extractSource(element));
|
||||
}
|
||||
|
||||
Class<?> type = hasClientUri ? MongoClientURI.class : MongoURI.class;
|
||||
Class<?> type = MongoClientURI.class;
|
||||
String uri = hasClientUri ? element.getAttribute("client-uri") : element.getAttribute("uri");
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(type);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,12 +26,19 @@ import org.springframework.data.mongodb.monitor.*;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Mark Pollack
|
||||
* @author Thomas Risberg
|
||||
* @author John Brisbin
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoJmxParser implements BeanDefinitionParser {
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String name = element.getAttribute("mongo-ref");
|
||||
if (!StringUtils.hasText(name)) {
|
||||
name = "mongo";
|
||||
name = BeanNames.MONGO_BEAN_NAME;
|
||||
}
|
||||
registerJmxComponents(name, element, parserContext);
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,7 +33,6 @@ public class MongoNamespaceHandler extends NamespaceHandlerSupport {
|
||||
public void init() {
|
||||
|
||||
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
|
||||
registerBeanDefinitionParser("mongo", new MongoParser());
|
||||
registerBeanDefinitionParser("mongo-client", new MongoClientParser());
|
||||
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
|
||||
registerBeanDefinitionParser("jmx", new MongoJmxParser());
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.mongodb.core.MongoFactoryBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for <mongo;gt; definitions.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MongoParser implements BeanDefinitionParser {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
|
||||
Object source = parserContext.extractSource(element);
|
||||
String id = element.getAttribute("id");
|
||||
|
||||
BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class);
|
||||
ParsingUtils.setPropertyValue(builder, element, "port", "port");
|
||||
ParsingUtils.setPropertyValue(builder, element, "host", "host");
|
||||
ParsingUtils.setPropertyValue(builder, element, "write-concern", "writeConcern");
|
||||
|
||||
MongoParsingUtils.parseMongoOptions(element, builder);
|
||||
MongoParsingUtils.parseReplicaSet(element, builder);
|
||||
|
||||
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO_BEAN_NAME;
|
||||
|
||||
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mongo", source));
|
||||
|
||||
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
|
||||
parserContext.registerBeanComponent(mongoComponent);
|
||||
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(MongoParsingUtils
|
||||
.getServerAddressPropertyEditorBuilder());
|
||||
parserContext.registerBeanComponent(serverAddressPropertyEditor);
|
||||
BeanComponentDefinition writeConcernPropertyEditor = helper.getComponent(MongoParsingUtils
|
||||
.getWriteConcernPropertyEditorBuilder());
|
||||
parserContext.registerBeanComponent(writeConcernPropertyEditor);
|
||||
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
|
||||
return mongoComponent.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,7 +25,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.data.mongodb.core.MongoClientOptionsFactoryBean;
|
||||
import org.springframework.data.mongodb.core.MongoOptionsFactoryBean;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
@@ -54,42 +53,6 @@ abstract class MongoParsingUtils {
|
||||
setPropertyValue(mongoBuilder, element, "replica-set", "replicaSetSeeds");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the {@code mongo:options} sub-element. Populates the given attribute factory with the proper attributes.
|
||||
*
|
||||
* @return true if parsing actually occured, {@literal false} otherwise
|
||||
*/
|
||||
static boolean parseMongoOptions(Element element, BeanDefinitionBuilder mongoBuilder) {
|
||||
|
||||
Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
|
||||
|
||||
if (optionsElement == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(MongoOptionsFactoryBean.class);
|
||||
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "connections-per-host", "connectionsPerHost");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "threads-allowed-to-block-for-connection-multiplier",
|
||||
"threadsAllowedToBlockForConnectionMultiplier");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "max-wait-time", "maxWaitTime");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "connect-timeout", "connectTimeout");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "socket-timeout", "socketTimeout");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "socket-keep-alive", "socketKeepAlive");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "auto-connect-retry", "autoConnectRetry");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "max-auto-connect-retry-time", "maxAutoConnectRetryTime");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "write-number", "writeNumber");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "write-timeout", "writeTimeout");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "write-fsync", "writeFsync");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "slave-ok", "slaveOk");
|
||||
setPropertyValue(optionsDefBuilder, optionsElement, "ssl", "ssl");
|
||||
setPropertyReference(optionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
|
||||
|
||||
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the {@code mongo:client-options} sub-element. Populates the given attribute factory with the proper
|
||||
* attributes.
|
||||
@@ -129,6 +92,7 @@ abstract class MongoParsingUtils {
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-socket-timeout", "heartbeatSocketTimeout");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "ssl", "ssl");
|
||||
setPropertyReference(clientOptionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
|
||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "server-selection-timeout", "serverSelectionTimeout");
|
||||
|
||||
mongoClientBuilder.addPropertyValue("mongoClientOptions", clientOptionsDefBuilder.getBeanDefinition());
|
||||
|
||||
|
||||
@@ -0,0 +1,835 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.client.model.Collation.Builder;
|
||||
import com.mongodb.client.model.CollationAlternate;
|
||||
import com.mongodb.client.model.CollationCaseFirst;
|
||||
import com.mongodb.client.model.CollationMaxVariable;
|
||||
import com.mongodb.client.model.CollationStrength;
|
||||
|
||||
/**
|
||||
* Central abstraction for MongoDB collation support. <br />
|
||||
* Allows fluent creation of a collation {@link Document} that can be used for creating collections & indexes as well as
|
||||
* querying data.
|
||||
* <p />
|
||||
* <strong>NOTE:</strong> Please keep in mind that queries will only make use of an index with collation settings if the
|
||||
* query itself specifies the same collation.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
* @see <a href="https://docs.mongodb.com/manual/reference/collation/">MongoDB Reference - Collation</a>
|
||||
*/
|
||||
public class Collation {
|
||||
|
||||
private static final Collation SIMPLE = of("simple");
|
||||
|
||||
private final CollationLocale locale;
|
||||
|
||||
private Optional<ComparisonLevel> strength = Optional.empty();
|
||||
private Optional<Boolean> numericOrdering = Optional.empty();
|
||||
private Optional<Alternate> alternate = Optional.empty();
|
||||
private Optional<Boolean> backwards = Optional.empty();
|
||||
private Optional<Boolean> normalization = Optional.empty();
|
||||
private Optional<String> version = Optional.empty();
|
||||
|
||||
private Collation(CollationLocale locale) {
|
||||
|
||||
Assert.notNull(locale, "ICULocale must not be null!");
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Collation} using {@literal simple} binary comparison.
|
||||
*
|
||||
* @return a {@link Collation} for {@literal simple} binary comparison.
|
||||
*/
|
||||
public static Collation simple() {
|
||||
return SIMPLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link Collation} with locale set to {{@link java.util.Locale#getLanguage()}} and
|
||||
* {@link java.util.Locale#getVariant()}.
|
||||
*
|
||||
* @param locale must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Collation of(Locale locale) {
|
||||
|
||||
Assert.notNull(locale, "Locale must not be null!");
|
||||
|
||||
String format;
|
||||
|
||||
if (StringUtils.hasText(locale.getCountry())) {
|
||||
format = String.format("%s_%s", locale.getLanguage(), locale.getCountry());
|
||||
} else {
|
||||
format = locale.getLanguage();
|
||||
}
|
||||
|
||||
return of(CollationLocale.of(format).variant(locale.getVariant()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link Collation} with locale set to the given ICU language.
|
||||
*
|
||||
* @param language must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Collation of(String language) {
|
||||
return of(CollationLocale.of(language));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link Collation} with locale set to the given {@link CollationLocale}.
|
||||
*
|
||||
* @param locale must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Collation of(CollationLocale locale) {
|
||||
return new Collation(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link Collation} from values in {@link Document}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
* @see <a href="https://docs.mongodb.com/manual/reference/collation/#collation-document">MongoDB Reference -
|
||||
* Collation Document</a>
|
||||
*/
|
||||
public static Collation from(Document source) {
|
||||
|
||||
Assert.notNull(source, "Source must not be null!");
|
||||
|
||||
Collation collation = Collation.of(source.getString("locale"));
|
||||
if (source.containsKey("strength")) {
|
||||
collation = collation.strength(source.getInteger("strength"));
|
||||
}
|
||||
if (source.containsKey("caseLevel")) {
|
||||
collation = collation.caseLevel(source.getBoolean("caseLevel"));
|
||||
}
|
||||
if (source.containsKey("caseFirst")) {
|
||||
collation = collation.caseFirst(source.getString("caseFirst"));
|
||||
}
|
||||
if (source.containsKey("numericOrdering")) {
|
||||
collation = collation.numericOrdering(source.getBoolean("numericOrdering"));
|
||||
}
|
||||
if (source.containsKey("alternate")) {
|
||||
collation = collation.alternate(source.getString("alternate"));
|
||||
}
|
||||
if (source.containsKey("maxVariable")) {
|
||||
collation = collation.maxVariable(source.getString("maxVariable"));
|
||||
}
|
||||
if (source.containsKey("backwards")) {
|
||||
collation = collation.backwards(source.getBoolean("backwards"));
|
||||
}
|
||||
if (source.containsKey("normalization")) {
|
||||
collation = collation.normalization(source.getBoolean("normalization"));
|
||||
}
|
||||
if (source.containsKey("version")) {
|
||||
collation.version = Optional.of(source.get("version").toString());
|
||||
}
|
||||
return collation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the level of comparison to perform.
|
||||
*
|
||||
* @param strength
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation strength(int strength) {
|
||||
|
||||
ComparisonLevel current = this.strength.orElseGet(() -> new ICUComparisonLevel(strength));
|
||||
return strength(new ICUComparisonLevel(strength, current.getCaseFirst(), current.getCaseLevel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the level of comparison to perform.
|
||||
*
|
||||
* @param comparisonLevel must not be {@literal null}.
|
||||
* @return new {@link Collation}
|
||||
*/
|
||||
public Collation strength(ComparisonLevel comparisonLevel) {
|
||||
|
||||
Collation newInstance = copy();
|
||||
newInstance.strength = Optional.of(comparisonLevel);
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to include {@code caseLevel} comparison. <br />
|
||||
*
|
||||
* @param caseLevel
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation caseLevel(boolean caseLevel) {
|
||||
|
||||
ComparisonLevel strengthValue = strength.orElseGet(ComparisonLevel::primary);
|
||||
return strength(
|
||||
new ICUComparisonLevel(strengthValue.getLevel(), strengthValue.getCaseFirst(), Optional.of(caseLevel)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag that determines sort order of case differences during tertiary level comparisons.
|
||||
*
|
||||
* @param caseFirst must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Collation caseFirst(String caseFirst) {
|
||||
return caseFirst(new CaseFirst(caseFirst));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag that determines sort order of case differences during tertiary level comparisons.
|
||||
*
|
||||
* @param caseFirst must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Collation caseFirst(CaseFirst sort) {
|
||||
|
||||
ComparisonLevel strengthValue = strength.orElseGet(ComparisonLevel::tertiary);
|
||||
return strength(new ICUComparisonLevel(strengthValue.getLevel(), Optional.of(sort), strengthValue.getCaseLevel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Treat numeric strings as numbers for comparison.
|
||||
*
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation numericOrderingEnabled() {
|
||||
return numericOrdering(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Treat numeric strings as string for comparison.
|
||||
*
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation numericOrderingDisabled() {
|
||||
return numericOrdering(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag that determines whether to compare numeric strings as numbers or as strings.
|
||||
*
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation numericOrdering(boolean flag) {
|
||||
|
||||
Collation newInstance = copy();
|
||||
newInstance.numericOrdering = Optional.of(flag);
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Field that determines whether collation should consider whitespace and punctuation as base characters for
|
||||
* purposes of comparison.
|
||||
*
|
||||
* @param alternate must not be {@literal null}.
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation alternate(String alternate) {
|
||||
|
||||
Alternate instance = this.alternate.orElseGet(() -> new Alternate(alternate, Optional.empty()));
|
||||
return alternate(new Alternate(alternate, instance.maxVariable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Field that determines whether collation should consider whitespace and punctuation as base characters for
|
||||
* purposes of comparison.
|
||||
*
|
||||
* @param alternate must not be {@literal null}.
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation alternate(Alternate alternate) {
|
||||
|
||||
Collation newInstance = copy();
|
||||
newInstance.alternate = Optional.ofNullable(alternate);
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort string with diacritics sort from back of the string.
|
||||
*
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation backwardDiacriticSort() {
|
||||
return backwards(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not sort string with diacritics sort from back of the string.
|
||||
*
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation forwardDiacriticSort() {
|
||||
return backwards(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag that determines whether strings with diacritics sort from back of the string.
|
||||
*
|
||||
* @param backwards must not be {@literal null}.
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation backwards(Boolean backwards) {
|
||||
|
||||
Collation newInstance = copy();
|
||||
newInstance.backwards = Optional.ofNullable(backwards);
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable text normalization.
|
||||
*
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation normalizationEnabled() {
|
||||
return normalization(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable text normalization.
|
||||
*
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation normalizationDisabled() {
|
||||
return normalization(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag that determines whether to check if text require normalization and to perform normalization.
|
||||
*
|
||||
* @param normalization must not be {@literal null}.
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation normalization(Boolean normalization) {
|
||||
|
||||
Collation newInstance = copy();
|
||||
newInstance.normalization = Optional.ofNullable(normalization);
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field that determines up to which characters are considered ignorable when alternate is {@code shifted}.
|
||||
*
|
||||
* @param maxVariable must not be {@literal null}.
|
||||
* @return new {@link Collation}.
|
||||
*/
|
||||
public Collation maxVariable(String maxVariable) {
|
||||
|
||||
Alternate alternateValue = alternate.orElseGet(Alternate::shifted);
|
||||
return alternate(new AlternateWithMaxVariable(alternateValue.alternate, maxVariable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Document} representation of the {@link Collation}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Document toDocument() {
|
||||
return map(toMongoDocumentConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link com.mongodb.client.model.Collation} representation of the {@link Collation}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public com.mongodb.client.model.Collation toMongoCollation() {
|
||||
return map(toMongoCollationConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform {@code this} {@link Collation} by applying a {@link Converter}.
|
||||
*
|
||||
* @param mapper
|
||||
* @param <R>
|
||||
* @return
|
||||
*/
|
||||
public <R> R map(Converter<? super Collation, ? extends R> mapper) {
|
||||
return mapper.convert(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toDocument().toJson();
|
||||
}
|
||||
|
||||
private Collation copy() {
|
||||
|
||||
Collation collation = new Collation(locale);
|
||||
collation.strength = this.strength;
|
||||
collation.normalization = this.normalization;
|
||||
collation.numericOrdering = this.numericOrdering;
|
||||
collation.alternate = this.alternate;
|
||||
collation.backwards = this.backwards;
|
||||
return collation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstraction for the ICU Comparison Levels.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ComparisonLevel {
|
||||
|
||||
/**
|
||||
* Primary level of comparison. Collation performs comparisons of the base characters only, ignoring other
|
||||
* differences such as diacritics and case. <br />
|
||||
* The {@code caseLevel} can be set via {@link PrimaryICUComparisonLevel#includeCase()} and
|
||||
* {@link PrimaryICUComparisonLevel#excludeCase()}.
|
||||
*
|
||||
* @return new {@link SecondaryICUComparisonLevel}.
|
||||
*/
|
||||
static PrimaryICUComparisonLevel primary() {
|
||||
return PrimaryICUComparisonLevel.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Secondary level of comparison. Collation performs comparisons up to secondary differences, such as
|
||||
* diacritics.<br />
|
||||
* The {@code caseLevel} can be set via {@link SecondaryICUComparisonLevel#includeCase()} and
|
||||
* {@link SecondaryICUComparisonLevel#excludeCase()}.
|
||||
*
|
||||
* @return new {@link SecondaryICUComparisonLevel}.
|
||||
*/
|
||||
static SecondaryICUComparisonLevel secondary() {
|
||||
return SecondaryICUComparisonLevel.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tertiary level of comparison. Collation performs comparisons up to tertiary differences, such as case and letter
|
||||
* variants. <br />
|
||||
* The {@code caseLevel} cannot be set for {@link ICUComparisonLevel} above {@code secondary}.
|
||||
*
|
||||
* @return new {@link ICUComparisonLevel}.
|
||||
*/
|
||||
static TertiaryICUComparisonLevel tertiary() {
|
||||
return TertiaryICUComparisonLevel.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quaternary Level. Limited for specific use case to consider punctuation. <br />
|
||||
* The {@code caseLevel} cannot be set for {@link ICUComparisonLevel} above {@code secondary}.
|
||||
*
|
||||
* @return new {@link ComparisonLevel}.
|
||||
*/
|
||||
static ComparisonLevel quaternary() {
|
||||
return ComparisonLevels.QUATERNARY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identical Level. Limited for specific use case of tie breaker. <br />
|
||||
* The {@code caseLevel} cannot be set for {@link ICUComparisonLevel} above {@code secondary}.
|
||||
*
|
||||
* @return new {@link ComparisonLevel}.
|
||||
*/
|
||||
static ComparisonLevel identical() {
|
||||
return ComparisonLevels.IDENTICAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return collation strength, {@literal 1} for primary, {@literal 2} for secondary and so on.
|
||||
*/
|
||||
int getLevel();
|
||||
|
||||
default Optional<CaseFirst> getCaseFirst() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
default Optional<Boolean> getCaseLevel() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstraction for the ICU Comparison Levels.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@Getter
|
||||
static class ICUComparisonLevel implements ComparisonLevel {
|
||||
|
||||
private final int level;
|
||||
private final Optional<CaseFirst> caseFirst;
|
||||
private final Optional<Boolean> caseLevel;
|
||||
|
||||
ICUComparisonLevel(int level) {
|
||||
this(level, Optional.empty(), Optional.empty());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple comparison levels.
|
||||
*/
|
||||
enum ComparisonLevels implements ComparisonLevel {
|
||||
|
||||
QUATERNARY(4), IDENTICAL(5);
|
||||
|
||||
private final int level;
|
||||
|
||||
ComparisonLevels(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary-strength {@link ICUComparisonLevel}.
|
||||
*/
|
||||
public static class PrimaryICUComparisonLevel extends ICUComparisonLevel {
|
||||
|
||||
static final PrimaryICUComparisonLevel DEFAULT = new PrimaryICUComparisonLevel();
|
||||
static final PrimaryICUComparisonLevel WITH_CASE_LEVEL = new PrimaryICUComparisonLevel(true);
|
||||
static final PrimaryICUComparisonLevel WITHOUT_CASE_LEVEL = new PrimaryICUComparisonLevel(false);
|
||||
|
||||
private PrimaryICUComparisonLevel() {
|
||||
super(1);
|
||||
}
|
||||
|
||||
private PrimaryICUComparisonLevel(boolean caseLevel) {
|
||||
super(1, Optional.empty(), Optional.of(caseLevel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Include case comparison.
|
||||
*
|
||||
* @return new {@link ICUComparisonLevel}
|
||||
*/
|
||||
public ComparisonLevel includeCase() {
|
||||
return WITH_CASE_LEVEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude case comparison.
|
||||
*
|
||||
* @return new {@link ICUComparisonLevel}
|
||||
*/
|
||||
public ComparisonLevel excludeCase() {
|
||||
return WITHOUT_CASE_LEVEL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Secondary-strength {@link ICUComparisonLevel}.
|
||||
*/
|
||||
public static class SecondaryICUComparisonLevel extends ICUComparisonLevel {
|
||||
|
||||
static final SecondaryICUComparisonLevel DEFAULT = new SecondaryICUComparisonLevel();
|
||||
static final SecondaryICUComparisonLevel WITH_CASE_LEVEL = new SecondaryICUComparisonLevel(true);
|
||||
static final SecondaryICUComparisonLevel WITHOUT_CASE_LEVEL = new SecondaryICUComparisonLevel(false);
|
||||
|
||||
private SecondaryICUComparisonLevel() {
|
||||
super(2);
|
||||
}
|
||||
|
||||
private SecondaryICUComparisonLevel(boolean caseLevel) {
|
||||
super(2, Optional.empty(), Optional.of(caseLevel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Include case comparison.
|
||||
*
|
||||
* @return new {@link SecondaryICUComparisonLevel}
|
||||
*/
|
||||
public ComparisonLevel includeCase() {
|
||||
return WITH_CASE_LEVEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude case comparison.
|
||||
*
|
||||
* @return new {@link SecondaryICUComparisonLevel}
|
||||
*/
|
||||
public ComparisonLevel excludeCase() {
|
||||
return WITHOUT_CASE_LEVEL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tertiary-strength {@link ICUComparisonLevel}.
|
||||
*/
|
||||
public static class TertiaryICUComparisonLevel extends ICUComparisonLevel {
|
||||
|
||||
static final TertiaryICUComparisonLevel DEFAULT = new TertiaryICUComparisonLevel();
|
||||
|
||||
private TertiaryICUComparisonLevel() {
|
||||
super(3);
|
||||
}
|
||||
|
||||
private TertiaryICUComparisonLevel(CaseFirst caseFirst) {
|
||||
super(3, Optional.of(caseFirst), Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag that determines sort order of case differences.
|
||||
*
|
||||
* @param caseFirst must not be {@literal null}.
|
||||
* @return new {@link ICUComparisonLevel}
|
||||
*/
|
||||
public ComparisonLevel caseFirst(CaseFirst caseFirst) {
|
||||
|
||||
Assert.notNull(caseFirst, "CaseFirst must not be null!");
|
||||
return new TertiaryICUComparisonLevel(caseFirst);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public static class CaseFirst {
|
||||
|
||||
private static final CaseFirst UPPER = new CaseFirst("upper");
|
||||
private static final CaseFirst LOWER = new CaseFirst("lower");
|
||||
private static final CaseFirst OFF = new CaseFirst("off");
|
||||
|
||||
private final String state;
|
||||
|
||||
/**
|
||||
* Sort uppercase before lowercase.
|
||||
*
|
||||
* @return new {@link CaseFirst}.
|
||||
*/
|
||||
public static CaseFirst upper() {
|
||||
return UPPER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort lowercase before uppercase.
|
||||
*
|
||||
* @return new {@link CaseFirst}.
|
||||
*/
|
||||
public static CaseFirst lower() {
|
||||
return LOWER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the default.
|
||||
*
|
||||
* @return new {@link CaseFirst}.
|
||||
*/
|
||||
public static CaseFirst off() {
|
||||
return OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public static class Alternate {
|
||||
|
||||
private static final Alternate NON_IGNORABLE = new Alternate("non-ignorable", Optional.empty());
|
||||
|
||||
final String alternate;
|
||||
final Optional<String> maxVariable;
|
||||
|
||||
/**
|
||||
* Consider Whitespace and punctuation as base characters.
|
||||
*
|
||||
* @return new {@link Alternate}.
|
||||
*/
|
||||
public static Alternate nonIgnorable() {
|
||||
return NON_IGNORABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whitespace and punctuation are <strong>not</strong> considered base characters and are only distinguished at
|
||||
* strength. <br />
|
||||
* <strong>NOTE:</strong> Only works for {@link ICUComparisonLevel} above {@link ComparisonLevel#tertiary()}.
|
||||
*
|
||||
* @return new {@link AlternateWithMaxVariable}.
|
||||
*/
|
||||
public static AlternateWithMaxVariable shifted() {
|
||||
return AlternateWithMaxVariable.DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
public static class AlternateWithMaxVariable extends Alternate {
|
||||
|
||||
static final AlternateWithMaxVariable DEFAULT = new AlternateWithMaxVariable("shifted");
|
||||
static final Alternate SHIFTED_PUNCT = new AlternateWithMaxVariable("shifted", "punct");
|
||||
static final Alternate SHIFTED_SPACE = new AlternateWithMaxVariable("shifted", "space");
|
||||
|
||||
private AlternateWithMaxVariable(String alternate) {
|
||||
super(alternate, Optional.empty());
|
||||
}
|
||||
|
||||
private AlternateWithMaxVariable(String alternate, String maxVariable) {
|
||||
super(alternate, Optional.of(maxVariable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Consider both whitespaces and punctuation as ignorable.
|
||||
*
|
||||
* @return new {@link AlternateWithMaxVariable}.
|
||||
*/
|
||||
public Alternate punct() {
|
||||
return SHIFTED_PUNCT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only consider whitespaces as ignorable.
|
||||
*
|
||||
* @return new {@link AlternateWithMaxVariable}.
|
||||
*/
|
||||
public Alternate space() {
|
||||
return SHIFTED_SPACE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ICU locale abstraction for usage with MongoDB {@link Collation}.
|
||||
*
|
||||
* @since 2.0
|
||||
* @see <a href="http://site.icu-project.org">ICU - International Components for Unicode</a>
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public static class CollationLocale {
|
||||
|
||||
private final String language;
|
||||
private final Optional<String> variant;
|
||||
|
||||
/**
|
||||
* Create new {@link CollationLocale} for given language.
|
||||
*
|
||||
* @param language must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static CollationLocale of(String language) {
|
||||
|
||||
Assert.notNull(language, "Code must not be null!");
|
||||
return new CollationLocale(language, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Define language variant.
|
||||
*
|
||||
* @param variant must not be {@literal null}.
|
||||
* @return new {@link CollationLocale}.
|
||||
*/
|
||||
public CollationLocale variant(String variant) {
|
||||
|
||||
Assert.notNull(variant, "Variant must not be null!");
|
||||
return new CollationLocale(language, Optional.of(variant));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String asString() {
|
||||
|
||||
StringBuilder sb = new StringBuilder(language);
|
||||
|
||||
variant.filter(it -> !it.isEmpty()).ifPresent(val -> {
|
||||
|
||||
// Mongo requires variant rendered as ICU keyword (@key=value;key=value…)
|
||||
sb.append("@collation=").append(val);
|
||||
});
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static Converter<Collation, Document> toMongoDocumentConverter() {
|
||||
|
||||
return source -> {
|
||||
|
||||
Document document = new Document();
|
||||
document.append("locale", source.locale.asString());
|
||||
|
||||
source.strength.ifPresent(strength -> {
|
||||
|
||||
document.append("strength", strength.getLevel());
|
||||
|
||||
strength.getCaseLevel().ifPresent(it -> document.append("caseLevel", it));
|
||||
strength.getCaseFirst().ifPresent(it -> document.append("caseFirst", it.state));
|
||||
});
|
||||
|
||||
source.numericOrdering.ifPresent(val -> document.append("numericOrdering", val));
|
||||
source.alternate.ifPresent(it -> {
|
||||
|
||||
document.append("alternate", it.alternate);
|
||||
it.maxVariable.ifPresent(maxVariable -> document.append("maxVariable", maxVariable));
|
||||
});
|
||||
|
||||
source.backwards.ifPresent(it -> document.append("backwards", it));
|
||||
source.normalization.ifPresent(it -> document.append("normalization", it));
|
||||
source.version.ifPresent(it -> document.append("version", it));
|
||||
|
||||
return document;
|
||||
};
|
||||
}
|
||||
|
||||
private static Converter<Collation, com.mongodb.client.model.Collation> toMongoCollationConverter() {
|
||||
|
||||
return source -> {
|
||||
|
||||
Builder builder = com.mongodb.client.model.Collation.builder();
|
||||
|
||||
builder.locale(source.locale.asString());
|
||||
|
||||
source.strength.ifPresent(strength -> {
|
||||
|
||||
builder.collationStrength(CollationStrength.fromInt(strength.getLevel()));
|
||||
|
||||
strength.getCaseLevel().ifPresent(builder::caseLevel);
|
||||
strength.getCaseFirst().ifPresent(it -> builder.collationCaseFirst(CollationCaseFirst.fromString(it.state)));
|
||||
});
|
||||
|
||||
source.numericOrdering.ifPresent(builder::numericOrdering);
|
||||
source.alternate.ifPresent(it -> {
|
||||
|
||||
builder.collationAlternate(CollationAlternate.fromString(it.alternate));
|
||||
it.maxVariable
|
||||
.ifPresent(maxVariable -> builder.collationMaxVariable(CollationMaxVariable.fromString(maxVariable)));
|
||||
});
|
||||
|
||||
source.backwards.ifPresent(builder::backwards);
|
||||
source.normalization.ifPresent(builder::normalization);
|
||||
|
||||
return builder.build();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2010-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,56 +15,149 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Provides a simple wrapper to encapsulate the variety of settings you can use when creating a collection.
|
||||
*
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class CollectionOptions {
|
||||
|
||||
private Integer maxDocuments;
|
||||
|
||||
private Integer size;
|
||||
|
||||
private Long maxDocuments;
|
||||
private Long size;
|
||||
private Boolean capped;
|
||||
private Collation collation;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>CollectionOptions</code> instance.
|
||||
*
|
||||
* @param size the collection size in bytes, this data space is preallocated
|
||||
*
|
||||
* @param size the collection size in bytes, this data space is preallocated.
|
||||
* @param maxDocuments the maximum number of documents in the collection.
|
||||
* @param capped true to created a "capped" collection (fixed size with auto-FIFO behavior based on insertion order),
|
||||
* false otherwise.
|
||||
* @deprecated since 2.0 please use {@link CollectionOptions#empty()} as entry point.
|
||||
*/
|
||||
public CollectionOptions(Integer size, Integer maxDocuments, Boolean capped) {
|
||||
super();
|
||||
@Deprecated
|
||||
public CollectionOptions(Long size, Long maxDocuments, Boolean capped) {
|
||||
this(size, maxDocuments, capped, null);
|
||||
}
|
||||
|
||||
private CollectionOptions(Long size, Long maxDocuments, Boolean capped, Collation collation) {
|
||||
|
||||
this.maxDocuments = maxDocuments;
|
||||
this.size = size;
|
||||
this.capped = capped;
|
||||
this.collation = collation;
|
||||
}
|
||||
|
||||
public Integer getMaxDocuments() {
|
||||
return maxDocuments;
|
||||
/**
|
||||
* Create new {@link CollectionOptions} by just providing the {@link Collation} to use.
|
||||
*
|
||||
* @param collation must not be {@literal null}.
|
||||
* @return new {@link CollectionOptions}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static CollectionOptions just(Collation collation) {
|
||||
|
||||
Assert.notNull(collation, "Collation must not be null!");
|
||||
|
||||
return new CollectionOptions(null, null, null, collation);
|
||||
}
|
||||
|
||||
public void setMaxDocuments(Integer maxDocuments) {
|
||||
this.maxDocuments = maxDocuments;
|
||||
/**
|
||||
* Create new empty {@link CollectionOptions}.
|
||||
*
|
||||
* @return new {@link CollectionOptions}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static CollectionOptions empty() {
|
||||
return new CollectionOptions(null, null, null, null);
|
||||
}
|
||||
|
||||
public Integer getSize() {
|
||||
return size;
|
||||
/**
|
||||
* Create new {@link CollectionOptions} with already given settings and capped set to {@literal true}. <br />
|
||||
* <strong>NOTE</strong> Using capped collections requires defining {@link #size(int)}.
|
||||
*
|
||||
* @return new {@link CollectionOptions}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public CollectionOptions capped() {
|
||||
return new CollectionOptions(size, maxDocuments, true, collation);
|
||||
}
|
||||
|
||||
public void setSize(Integer size) {
|
||||
this.size = size;
|
||||
/**
|
||||
* Create new {@link CollectionOptions} with already given settings and {@code maxDocuments} set to given value.
|
||||
*
|
||||
* @param maxDocuments can be {@literal null}.
|
||||
* @return new {@link CollectionOptions}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public CollectionOptions maxDocuments(long maxDocuments) {
|
||||
return new CollectionOptions(size, maxDocuments, capped, collation);
|
||||
}
|
||||
|
||||
public Boolean getCapped() {
|
||||
return capped;
|
||||
/**
|
||||
* Create new {@link CollectionOptions} with already given settings and {@code size} set to given value.
|
||||
*
|
||||
* @param size can be {@literal null}.
|
||||
* @return new {@link CollectionOptions}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public CollectionOptions size(long size) {
|
||||
return new CollectionOptions(size, maxDocuments, capped, collation);
|
||||
}
|
||||
|
||||
public void setCapped(Boolean capped) {
|
||||
this.capped = capped;
|
||||
/**
|
||||
* Create new {@link CollectionOptions} with already given settings and {@code collation} set to given value.
|
||||
*
|
||||
* @param collation can be {@literal null}.
|
||||
* @return new {@link CollectionOptions}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public CollectionOptions collation(Collation collation) {
|
||||
return new CollectionOptions(size, maxDocuments, capped, collation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the max number of documents the collection should be limited to.
|
||||
*
|
||||
* @return {@link Optional#empty()} if not set.
|
||||
*/
|
||||
public Optional<Long> getMaxDocuments() {
|
||||
return Optional.ofNullable(maxDocuments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@literal size} in bytes the collection should be limited to.
|
||||
*
|
||||
* @return {@link Optional#empty()} if not set.
|
||||
*/
|
||||
public Optional<Long> getSize() {
|
||||
return Optional.ofNullable(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the collection should be capped.
|
||||
*
|
||||
* @return {@link Optional#empty()} if not set.
|
||||
* @since 2.0
|
||||
*/
|
||||
public Optional<Boolean> getCapped() {
|
||||
return Optional.ofNullable(capped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Collation} settings.
|
||||
*
|
||||
* @return {@link Optional#empty()} if not set.
|
||||
* @since 2.0
|
||||
*/
|
||||
public Optional<Collation> getCollation() {
|
||||
return Optional.ofNullable(collation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2015-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.mongodb.client.model.DeleteOptions;
|
||||
import org.bson.Document;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
@@ -58,12 +59,12 @@ class DefaultBulkOperations implements BulkOperations {
|
||||
|
||||
private BulkWriteOptions bulkOptions;
|
||||
|
||||
List<WriteModel<Document>> models = new ArrayList<WriteModel<Document>>();
|
||||
List<WriteModel<Document>> models = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultBulkOperations} for the given {@link MongoOperations}, {@link BulkMode}, collection
|
||||
* name and {@link WriteConcern}.
|
||||
*
|
||||
*
|
||||
* @param mongoOperations The underlying {@link MongoOperations}, must not be {@literal null}.
|
||||
* @param bulkMode must not be {@literal null}.
|
||||
* @param collectionName Name of the collection to work on, must not be {@literal null} or empty.
|
||||
@@ -88,7 +89,7 @@ class DefaultBulkOperations implements BulkOperations {
|
||||
|
||||
/**
|
||||
* Configures the {@link PersistenceExceptionTranslator} to be used. Defaults to {@link MongoExceptionTranslator}.
|
||||
*
|
||||
*
|
||||
* @param exceptionTranslator can be {@literal null}.
|
||||
*/
|
||||
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
|
||||
@@ -97,7 +98,7 @@ class DefaultBulkOperations implements BulkOperations {
|
||||
|
||||
/**
|
||||
* Configures the {@link WriteConcernResolver} to be used. Defaults to {@link DefaultWriteConcernResolver}.
|
||||
*
|
||||
*
|
||||
* @param writeConcernResolver can be {@literal null}.
|
||||
*/
|
||||
public void setWriteConcernResolver(WriteConcernResolver writeConcernResolver) {
|
||||
@@ -107,7 +108,7 @@ class DefaultBulkOperations implements BulkOperations {
|
||||
|
||||
/**
|
||||
* Configures the default {@link WriteConcern} to be used. Defaults to {@literal null}.
|
||||
*
|
||||
*
|
||||
* @param defaultWriteConcern can be {@literal null}.
|
||||
*/
|
||||
public void setDefaultWriteConcern(WriteConcern defaultWriteConcern) {
|
||||
@@ -123,7 +124,16 @@ class DefaultBulkOperations implements BulkOperations {
|
||||
|
||||
Assert.notNull(document, "Document must not be null!");
|
||||
|
||||
models.add(new InsertOneModel<Document>((Document) mongoOperations.getConverter().convertToMongoType(document)));
|
||||
if (document instanceof Document) {
|
||||
|
||||
models.add(new InsertOneModel<>((Document) document));
|
||||
return this;
|
||||
}
|
||||
|
||||
Document sink = new Document();
|
||||
mongoOperations.getConverter().write(document, sink);
|
||||
|
||||
models.add(new InsertOneModel<>(sink));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -235,7 +245,10 @@ class DefaultBulkOperations implements BulkOperations {
|
||||
|
||||
Assert.notNull(query, "Query must not be null!");
|
||||
|
||||
models.add(new DeleteManyModel<Document>(query.getQueryObject()));
|
||||
DeleteOptions deleteOptions = new DeleteOptions();
|
||||
query.getCollation().map(Collation::toMongoCollation).ifPresent(deleteOptions::collation);
|
||||
|
||||
models.add(new DeleteManyModel(query.getQueryObject(), deleteOptions));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -297,11 +310,12 @@ class DefaultBulkOperations implements BulkOperations {
|
||||
|
||||
UpdateOptions options = new UpdateOptions();
|
||||
options.upsert(upsert);
|
||||
query.getCollation().map(Collation::toMongoCollation).ifPresent(options::collation);
|
||||
|
||||
if (multi) {
|
||||
models.add(new UpdateManyModel<Document>(query.getQueryObject(), update.getUpdateObject(), options));
|
||||
models.add(new UpdateManyModel<>(query.getQueryObject(), update.getUpdateObject(), options));
|
||||
} else {
|
||||
models.add(new UpdateOneModel<Document>(query.getQueryObject(), update.getUpdateObject(), options));
|
||||
models.add(new UpdateOneModel<>(query.getQueryObject(), update.getUpdateObject(), options));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,13 +18,16 @@ package org.springframework.data.mongodb.core;
|
||||
import static org.springframework.data.mongodb.core.MongoTemplate.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
@@ -43,22 +46,45 @@ import com.mongodb.client.model.IndexOptions;
|
||||
*/
|
||||
public class DefaultIndexOperations implements IndexOperations {
|
||||
|
||||
private static final String PARTIAL_FILTER_EXPRESSION_KEY = "partialFilterExpression";
|
||||
|
||||
private final MongoDbFactory mongoDbFactory;
|
||||
private final String collectionName;
|
||||
private final QueryMapper mapper;
|
||||
private final Class<?> type;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultIndexOperations}.
|
||||
*
|
||||
* @param mongoDbFactory must not be {@literal null}.
|
||||
* @param collectionName must not be {@literal null}.
|
||||
* @param queryMapper must not be {@literal null}.
|
||||
*/
|
||||
public DefaultIndexOperations(MongoDbFactory mongoDbFactory, String collectionName) {
|
||||
public DefaultIndexOperations(MongoDbFactory mongoDbFactory, String collectionName, QueryMapper queryMapper) {
|
||||
|
||||
this(mongoDbFactory, collectionName, queryMapper, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultIndexOperations}.
|
||||
*
|
||||
* @param mongoDbFactory must not be {@literal null}.
|
||||
* @param collectionName must not be {@literal null}.
|
||||
* @param queryMapper must not be {@literal null}.
|
||||
* @param type Type used for mapping potential partial index filter expression. Can be {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public DefaultIndexOperations(MongoDbFactory mongoDbFactory, String collectionName, QueryMapper queryMapper,
|
||||
Class<?> type) {
|
||||
|
||||
Assert.notNull(mongoDbFactory, "MongoDbFactory must not be null!");
|
||||
Assert.notNull(collectionName, "Collection name can not be null!");
|
||||
Assert.notNull(queryMapper, "QueryMapper must not be null!");
|
||||
|
||||
this.mongoDbFactory = mongoDbFactory;
|
||||
this.collectionName = collectionName;
|
||||
this.mapper = queryMapper;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -74,10 +100,38 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
if (indexOptions != null) {
|
||||
|
||||
IndexOptions ops = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
|
||||
|
||||
if (indexOptions.containsKey(PARTIAL_FILTER_EXPRESSION_KEY)) {
|
||||
|
||||
Assert.isInstanceOf(Document.class, indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY));
|
||||
|
||||
ops.partialFilterExpression( mapper.getMappedObject(
|
||||
(Document) indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY), lookupPersistentEntity(type, collectionName)));
|
||||
}
|
||||
|
||||
return collection.createIndex(indexDefinition.getIndexKeys(), ops);
|
||||
}
|
||||
return collection.createIndex(indexDefinition.getIndexKeys());
|
||||
});
|
||||
}
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
private MongoPersistentEntity<?> lookupPersistentEntity(Class<?> entityType, String collection) {
|
||||
|
||||
if (entityType != null) {
|
||||
return mapper.getMappingContext().getRequiredPersistentEntity(entityType);
|
||||
}
|
||||
|
||||
Collection<? extends MongoPersistentEntity<?>> entities = mapper.getMappingContext().getPersistentEntities();
|
||||
|
||||
for (MongoPersistentEntity<?> entity : entities) {
|
||||
if (entity.getCollection().equals(collection)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -134,7 +188,7 @@ public class DefaultIndexOperations implements IndexOperations {
|
||||
|
||||
public <T> T execute(CollectionCallback<T> callback) {
|
||||
|
||||
Assert.notNull(callback);
|
||||
Assert.notNull(callback, "CollectionCallback must not be null!");
|
||||
|
||||
try {
|
||||
MongoCollection<Document> collection = mongoDbFactory.getDb().getCollection(collectionName);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||
|
||||
/**
|
||||
* {@link IndexOperationsProvider} to obtain {@link IndexOperations} from a given {@link MongoDbFactory}. TODO: Review
|
||||
@@ -27,12 +28,13 @@ import org.springframework.data.mongodb.MongoDbFactory;
|
||||
class DefaultIndexOperationsProvider implements IndexOperationsProvider {
|
||||
|
||||
private final MongoDbFactory mongoDbFactory;
|
||||
private final QueryMapper mapper;
|
||||
|
||||
/**
|
||||
* @param mongoDbFactory must not be {@literal null}.
|
||||
*/
|
||||
DefaultIndexOperationsProvider(MongoDbFactory mongoDbFactory) {
|
||||
this.mongoDbFactory = mongoDbFactory;
|
||||
DefaultIndexOperationsProvider(MongoDbFactory mongoDbFactory, QueryMapper mapper) {
|
||||
this.mongoDbFactory = mongoDbFactory; this.mapper = mapper;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -40,6 +42,6 @@ class DefaultIndexOperationsProvider implements IndexOperationsProvider {
|
||||
*/
|
||||
@Override
|
||||
public IndexOperations indexOps(String collectionName) {
|
||||
return new DefaultIndexOperations(mongoDbFactory, collectionName);
|
||||
return new DefaultIndexOperations(mongoDbFactory, collectionName, mapper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
|
||||
/**
|
||||
* {@link ExecutableAggregationOperation} allows creation and execution of MongoDB aggregation operations in a fluent
|
||||
* API style. <br />
|
||||
* The starting {@literal domainType} is used for mapping the {@link Aggregation} provided via {@code by} into the
|
||||
* MongoDB specific representation, as well as mapping back the resulting {@link org.bson.Document}. An alternative
|
||||
* input type for mapping the {@link Aggregation} can be provided by using
|
||||
* {@link org.springframework.data.mongodb.core.aggregation.TypedAggregation}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* aggregateAndReturn(Jedi.class)
|
||||
* .by(newAggregation(Human.class, project("These are not the droids you are looking for")))
|
||||
* .get();
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ExecutableAggregationOperation {
|
||||
|
||||
/**
|
||||
* Start creating an aggregation operation that returns results mapped to the given domain type. <br />
|
||||
* Use {@link org.springframework.data.mongodb.core.aggregation.TypedAggregation} to specify a potentially different
|
||||
* input type for he aggregation.
|
||||
*
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @return new instance of {@link AggregationOperation}.
|
||||
* @throws IllegalArgumentException if domainType is {@literal null}.
|
||||
*/
|
||||
<T> AggregationOperation<T> aggregateAndReturn(Class<T> domainType);
|
||||
|
||||
/**
|
||||
* Collection override (Optional).
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface AggregationOperationWithCollection<T> {
|
||||
|
||||
/**
|
||||
* Explicitly set the name of the collection to perform the query on. <br />
|
||||
* Skip this step to use the default collection derived from the domain type.
|
||||
*
|
||||
* @param collection must not be {@literal null} nor {@literal empty}.
|
||||
* @return new instance of {@link AggregationOperationWithAggregation}.
|
||||
* @throws IllegalArgumentException if collection is {@literal null}.
|
||||
*/
|
||||
AggregationOperationWithAggregation<T> inCollection(String collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger execution by calling one of the terminating methods.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface TerminatingAggregationOperation<T> {
|
||||
|
||||
/**
|
||||
* Apply pipeline operations as specified and get all matching elements.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
AggregationResults<T> all();
|
||||
|
||||
/**
|
||||
* Apply pipeline operations as specified and stream all matching elements. <br />
|
||||
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.Cursor}
|
||||
*
|
||||
* @return a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.Cursor} that needs to be closed.
|
||||
* Never {@literal null}.
|
||||
*/
|
||||
CloseableIterator<T> stream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the aggregation with pipeline stages.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface AggregationOperationWithAggregation<T> {
|
||||
|
||||
/**
|
||||
* Set the aggregation to be used.
|
||||
*
|
||||
* @param aggregation must not be {@literal null}.
|
||||
* @return new instance of {@link TerminatingAggregationOperation}.
|
||||
* @throws IllegalArgumentException if aggregation is {@literal null}.
|
||||
*/
|
||||
TerminatingAggregationOperation<T> by(Aggregation aggregation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface AggregationOperation<T>
|
||||
extends AggregationOperationWithCollection<T>, AggregationOperationWithAggregation<T> {}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
||||
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExecutableAggregationOperation} operating directly on {@link MongoTemplate}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
class ExecutableAggregationOperationSupport implements ExecutableAggregationOperation {
|
||||
|
||||
private final MongoTemplate template;
|
||||
|
||||
/**
|
||||
* Create new instance of {@link ExecutableAggregationOperationSupport}.
|
||||
*
|
||||
* @param template must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if template is {@literal null}.
|
||||
*/
|
||||
ExecutableAggregationOperationSupport(MongoTemplate template) {
|
||||
|
||||
Assert.notNull(template, "Template must not be null!");
|
||||
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> AggregationOperation<T> aggregateAndReturn(Class<T> domainType) {
|
||||
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
|
||||
return new AggregationOperationSupport<>(template, null, domainType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class AggregationOperationSupport<T>
|
||||
implements AggregationOperationWithAggregation<T>, AggregationOperation<T>, TerminatingAggregationOperation<T> {
|
||||
|
||||
private final MongoTemplate template;
|
||||
private final Aggregation aggregation;
|
||||
private final Class<T> domainType;
|
||||
private final String collection;
|
||||
|
||||
@Override
|
||||
public AggregationOperationWithAggregation<T> inCollection(String collection) {
|
||||
|
||||
Assert.hasText(collection, "Collection must not be null nor empty!");
|
||||
|
||||
return new AggregationOperationSupport<>(template, aggregation, domainType, collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminatingAggregationOperation<T> by(Aggregation aggregation) {
|
||||
|
||||
Assert.notNull(aggregation, "Aggregation must not be null!");
|
||||
|
||||
return new AggregationOperationSupport<>(template, aggregation, domainType, collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AggregationResults<T> all() {
|
||||
return template.aggregate(aggregation, getCollectionName(aggregation), domainType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloseableIterator<T> stream() {
|
||||
return template.aggregateStream(aggregation, getCollectionName(aggregation), domainType);
|
||||
}
|
||||
|
||||
private String getCollectionName(Aggregation aggregation) {
|
||||
|
||||
if (StringUtils.hasText(collection)) {
|
||||
return collection;
|
||||
}
|
||||
|
||||
if (aggregation instanceof TypedAggregation) {
|
||||
|
||||
TypedAggregation<?> typedAggregation = (TypedAggregation<?>) aggregation;
|
||||
|
||||
if (typedAggregation.getInputType() != null) {
|
||||
return template.determineCollectionName(typedAggregation.getInputType());
|
||||
}
|
||||
}
|
||||
|
||||
return template.determineCollectionName(domainType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
|
||||
/**
|
||||
* {@link ExecutableFindOperation} allows creation and execution of MongoDB find operations in a fluent API style.
|
||||
* <br />
|
||||
* The starting {@literal domainType} is used for mapping the {@link Query} provided via {@code matching} into the
|
||||
* MongoDB specific representation. By default, the originating {@literal domainType} is also used for mapping back the
|
||||
* result from the {@link org.bson.Document}. However, it is possible to define an different {@literal returnType} via
|
||||
* {@code as} to mapping the result.<br />
|
||||
* The collection to operate on is by default derived from the initial {@literal domainType} and can be defined there
|
||||
* via {@link org.springframework.data.mongodb.core.mapping.Document}. Using {@code inCollection} allows to override the
|
||||
* collection name for the execution.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* query(Human.class)
|
||||
* .inCollection("star-wars")
|
||||
* .as(Jedi.class)
|
||||
* .matching(query(where("firstname").is("luke")))
|
||||
* .all();
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ExecutableFindOperation {
|
||||
|
||||
/**
|
||||
* Start creating a find operation for the given {@literal domainType}.
|
||||
*
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @return new instance of {@link FindOperation}.
|
||||
* @throws IllegalArgumentException if domainType is {@literal null}.
|
||||
*/
|
||||
<T> FindOperation<T> query(Class<T> domainType);
|
||||
|
||||
/**
|
||||
* Trigger find execution by calling one of the terminating methods.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface TerminatingFindOperation<T> {
|
||||
|
||||
/**
|
||||
* Get exactly zero or one result.
|
||||
*
|
||||
* @return {@link Optional#empty()} if no match found.
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one match found.
|
||||
*/
|
||||
Optional<T> one();
|
||||
|
||||
/**
|
||||
* Get the first or no result.
|
||||
*
|
||||
* @return {@link Optional#empty()} if no match found.
|
||||
*/
|
||||
Optional<T> first();
|
||||
|
||||
/**
|
||||
* Get all matching elements.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
List<T> all();
|
||||
|
||||
/**
|
||||
* Stream all matching elements.
|
||||
*
|
||||
* @return a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.Cursor} that needs to be closed.
|
||||
* Never {@literal null}.
|
||||
*/
|
||||
CloseableIterator<T> stream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger geonear execution by calling one of the terminating methods.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface TerminatingFindNearOperation<T> {
|
||||
|
||||
/**
|
||||
* Find all matching elements and return them as {@link org.springframework.data.geo.GeoResult}.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
GeoResults<T> all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminating operations invoking the actual query execution.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface FindOperationWithQuery<T> extends TerminatingFindOperation<T> {
|
||||
|
||||
/**
|
||||
* Set the filter query to be used.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @return new instance of {@link TerminatingFindOperation}.
|
||||
* @throws IllegalArgumentException if query is {@literal null}.
|
||||
*/
|
||||
TerminatingFindOperation<T> matching(Query query);
|
||||
|
||||
/**
|
||||
* Set the filter query for the geoNear execution.
|
||||
*
|
||||
* @param nearQuery must not be {@literal null}.
|
||||
* @return new instance of {@link TerminatingFindNearOperation}.
|
||||
* @throws IllegalArgumentException if nearQuery is {@literal null}.
|
||||
*/
|
||||
TerminatingFindNearOperation<T> near(NearQuery nearQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection override (Optional).
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface FindOperationWithCollection<T> extends FindOperationWithQuery<T> {
|
||||
|
||||
/**
|
||||
* Explicitly set the name of the collection to perform the query on. <br />
|
||||
* Skip this step to use the default collection derived from the domain type.
|
||||
*
|
||||
* @param collection must not be {@literal null} nor {@literal empty}.
|
||||
* @return new instance of {@link FindOperationWithProjection}.
|
||||
* @throws IllegalArgumentException if collection is {@literal null}.
|
||||
*/
|
||||
FindOperationWithProjection<T> inCollection(String collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Result type override (Optional).
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface FindOperationWithProjection<T> extends FindOperationWithQuery<T> {
|
||||
|
||||
/**
|
||||
* Define the target type fields should be mapped to. <br />
|
||||
* Skip this step if you are anyway only interested in the original domain type.
|
||||
*
|
||||
* @param resultType must not be {@literal null}.
|
||||
* @param <R> result type.
|
||||
* @return new instance of {@link FindOperationWithProjection}.
|
||||
* @throws IllegalArgumentException if resultType is {@literal null}.
|
||||
*/
|
||||
<R> FindOperationWithQuery<R> as(Class<R> resultType);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FindOperation} provides methods for constructing lookup operations in a fluent way.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface FindOperation<T> extends FindOperationWithCollection<T>, FindOperationWithProjection<T> {}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.SerializationUtils;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.client.FindIterable;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExecutableFindOperation}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
class ExecutableFindOperationSupport implements ExecutableFindOperation {
|
||||
|
||||
private final MongoTemplate template;
|
||||
|
||||
/**
|
||||
* Create new {@link ExecutableFindOperationSupport}.
|
||||
*
|
||||
* @param template must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if template is {@literal null}.
|
||||
*/
|
||||
ExecutableFindOperationSupport(MongoTemplate template) {
|
||||
|
||||
Assert.notNull(template, "Template must not be null!");
|
||||
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> FindOperation<T> query(Class<T> domainType) {
|
||||
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
|
||||
return new FindOperationSupport<>(template, domainType, domainType, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class FindOperationSupport<T> implements FindOperation<T>, FindOperationWithCollection<T>,
|
||||
FindOperationWithProjection<T>, FindOperationWithQuery<T> {
|
||||
|
||||
private final MongoTemplate template;
|
||||
private final Class<?> domainType;
|
||||
private final Class<T> returnType;
|
||||
private final String collection;
|
||||
private final Query query;
|
||||
|
||||
@Override
|
||||
public FindOperationWithProjection<T> inCollection(String collection) {
|
||||
|
||||
Assert.hasText(collection, "Collection name must not be null nor empty!");
|
||||
|
||||
return new FindOperationSupport<>(template, domainType, returnType, collection, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T1> FindOperationWithQuery<T1> as(Class<T1> returnType) {
|
||||
|
||||
Assert.notNull(returnType, "ReturnType must not be null!");
|
||||
|
||||
return new FindOperationSupport<>(template, domainType, returnType, collection, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminatingFindOperation<T> matching(Query query) {
|
||||
|
||||
Assert.notNull(query, "Query must not be null!");
|
||||
|
||||
return new FindOperationSupport<>(template, domainType, returnType, collection, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> one() {
|
||||
|
||||
List<T> result = doFind(new DelegatingQueryCursorPreparer(getCursorPreparer(query, null)).limit(2));
|
||||
|
||||
if (ObjectUtils.isEmpty(result)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (result.size() > 1) {
|
||||
throw new IncorrectResultSizeDataAccessException("Query " + asString() + " returned non unique result.", 1);
|
||||
}
|
||||
|
||||
return Optional.of(result.iterator().next());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> first() {
|
||||
|
||||
List<T> result = doFind(new DelegatingQueryCursorPreparer(getCursorPreparer(query, null)).limit(1));
|
||||
|
||||
return ObjectUtils.isEmpty(result) ? Optional.empty() : Optional.of(result.iterator().next());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> all() {
|
||||
return doFind(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloseableIterator<T> stream() {
|
||||
return doStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminatingFindNearOperation<T> near(NearQuery nearQuery) {
|
||||
return () -> template.geoNear(nearQuery, domainType, getCollectionName(), returnType);
|
||||
}
|
||||
|
||||
private List<T> doFind(CursorPreparer preparer) {
|
||||
|
||||
Document queryObject = query != null ? query.getQueryObject() : new Document();
|
||||
Document fieldsObject = query != null ? query.getFieldsObject() : new Document();
|
||||
|
||||
return template.doFind(getCollectionName(), queryObject, fieldsObject, domainType, returnType,
|
||||
getCursorPreparer(query, preparer));
|
||||
}
|
||||
|
||||
private CloseableIterator<T> doStream() {
|
||||
|
||||
return template.doStream(query != null ? query : new BasicQuery(new Document()), domainType, getCollectionName(),
|
||||
returnType);
|
||||
}
|
||||
|
||||
private CursorPreparer getCursorPreparer(Query query, CursorPreparer preparer) {
|
||||
return query == null || preparer != null ? preparer : template.new QueryCursorPreparer(query, domainType);
|
||||
}
|
||||
|
||||
private String getCollectionName() {
|
||||
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType);
|
||||
}
|
||||
|
||||
private String asString() {
|
||||
return SerializationUtils.serializeToJsonSafely(query);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
static class DelegatingQueryCursorPreparer implements CursorPreparer {
|
||||
|
||||
private final CursorPreparer delegate;
|
||||
private Optional<Integer> limit = Optional.empty();
|
||||
|
||||
DelegatingQueryCursorPreparer(CursorPreparer delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FindIterable<Document> prepare(FindIterable<Document> cursor) {
|
||||
|
||||
FindIterable<Document> target = delegate.prepare(cursor);
|
||||
|
||||
return limit.map(target::limit).orElse(target);
|
||||
}
|
||||
|
||||
CursorPreparer limit(int limit) {
|
||||
|
||||
this.limit = Optional.of(limit);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
|
||||
|
||||
import com.mongodb.bulk.BulkWriteResult;
|
||||
|
||||
/**
|
||||
* {@link ExecutableInsertOperation} allows creation and execution of MongoDB insert and bulk insert operations in a
|
||||
* fluent API style. <br />
|
||||
* The collection to operate on is by default derived from the initial {@literal domainType} and can be defined there
|
||||
* via {@link org.springframework.data.mongodb.core.mapping.Document}. Using {@code inCollection} allows to override the
|
||||
* collection name for the execution.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* insert(Jedi.class)
|
||||
* .inCollection("star-wars")
|
||||
* .one(luke);
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ExecutableInsertOperation {
|
||||
|
||||
/**
|
||||
* Start creating an insert operation for given {@literal domainType}.
|
||||
*
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @return new instance of {@link InsertOperation}.
|
||||
* @throws IllegalArgumentException if domainType is {@literal null}.
|
||||
*/
|
||||
<T> InsertOperation<T> insert(Class<T> domainType);
|
||||
|
||||
/**
|
||||
* Trigger insert execution by calling one of the terminating methods.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface TerminatingInsertOperation<T> extends TerminatingBulkInsertOperation<T> {
|
||||
|
||||
/**
|
||||
* Insert exactly one object.
|
||||
*
|
||||
* @param object must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if object is {@literal null}.
|
||||
*/
|
||||
void one(T object);
|
||||
|
||||
/**
|
||||
* Insert a collection of objects.
|
||||
*
|
||||
* @param objects must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if objects is {@literal null}.
|
||||
*/
|
||||
void all(Collection<? extends T> objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger bulk insert execution by calling one of the terminating methods.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface TerminatingBulkInsertOperation<T> {
|
||||
|
||||
/**
|
||||
* Bulk write collection of objects.
|
||||
*
|
||||
* @param objects must not be {@literal null}.
|
||||
* @return resulting {@link BulkWriteResult}.
|
||||
* @throws IllegalArgumentException if objects is {@literal null}.
|
||||
*/
|
||||
BulkWriteResult bulk(Collection<? extends T> objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface InsertOperation<T>
|
||||
extends TerminatingInsertOperation<T>, InsertOperationWithCollection<T>, InsertOperationWithBulkMode<T> {}
|
||||
|
||||
/**
|
||||
* Collection override (Optional).
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface InsertOperationWithCollection<T> {
|
||||
|
||||
/**
|
||||
* Explicitly set the name of the collection. <br />
|
||||
* Skip this step to use the default collection derived from the domain type.
|
||||
*
|
||||
* @param collection must not be {@literal null} nor {@literal empty}.
|
||||
* @return new instance of {@link InsertOperationWithBulkMode}.
|
||||
* @throws IllegalArgumentException if collection is {@literal null}.
|
||||
*/
|
||||
InsertOperationWithBulkMode<T> inCollection(String collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface InsertOperationWithBulkMode<T> extends TerminatingInsertOperation<T> {
|
||||
|
||||
/**
|
||||
* Define the {@link BulkMode} to use for bulk insert operation.
|
||||
*
|
||||
* @param bulkMode must not be {@literal null}.
|
||||
* @return new instance of {@link TerminatingBulkInsertOperation}.
|
||||
* @throws IllegalArgumentException if bulkMode is {@literal null}.
|
||||
*/
|
||||
TerminatingBulkInsertOperation<T> withBulkMode(BulkMode bulkMode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.bulk.BulkWriteResult;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExecutableInsertOperation}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
|
||||
|
||||
private final MongoTemplate template;
|
||||
|
||||
/**
|
||||
* Create new {@link ExecutableInsertOperationSupport}.
|
||||
*
|
||||
* @param template must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if template is {@literal null}.
|
||||
*/
|
||||
ExecutableInsertOperationSupport(MongoTemplate template) {
|
||||
|
||||
Assert.notNull(template, "Template must not be null!");
|
||||
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> InsertOperation<T> insert(Class<T> domainType) {
|
||||
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
|
||||
return new InsertOperationSupport<>(template, domainType, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class InsertOperationSupport<T> implements InsertOperation<T> {
|
||||
|
||||
private final MongoTemplate template;
|
||||
private final Class<T> domainType;
|
||||
private final String collection;
|
||||
private final BulkMode bulkMode;
|
||||
|
||||
@Override
|
||||
public void one(T object) {
|
||||
|
||||
Assert.notNull(object, "Object must not be null!");
|
||||
|
||||
template.insert(object, getCollectionName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void all(Collection<? extends T> objects) {
|
||||
|
||||
Assert.notNull(objects, "Objects must not be null!");
|
||||
|
||||
template.insert(objects, getCollectionName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BulkWriteResult bulk(Collection<? extends T> objects) {
|
||||
|
||||
Assert.notNull(objects, "Objects must not be null!");
|
||||
|
||||
return template.bulkOps(bulkMode != null ? bulkMode : BulkMode.ORDERED, domainType, getCollectionName())
|
||||
.insert(new ArrayList<>(objects)).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertOperationWithBulkMode<T> inCollection(String collection) {
|
||||
|
||||
Assert.hasText(collection, "Collection must not be null nor empty.");
|
||||
|
||||
return new InsertOperationSupport<>(template, domainType, collection, bulkMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminatingBulkInsertOperation<T> withBulkMode(BulkMode bulkMode) {
|
||||
|
||||
Assert.notNull(bulkMode, "BulkMode must not be null!");
|
||||
|
||||
return new InsertOperationSupport<>(template, domainType, collection, bulkMode);
|
||||
}
|
||||
|
||||
private String getCollectionName() {
|
||||
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
|
||||
import com.mongodb.client.result.DeleteResult;
|
||||
|
||||
/**
|
||||
* {@link ExecutableRemoveOperation} allows creation and execution of MongoDB remove / findAndRemove operations in a
|
||||
* fluent API style. <br />
|
||||
* The starting {@literal domainType} is used for mapping the {@link Query} provided via {@code matching} into the
|
||||
* MongoDB specific representation. The collection to operate on is by default derived from the initial
|
||||
* {@literal domainType} and can be defined there via {@link org.springframework.data.mongodb.core.mapping.Document}.
|
||||
* Using {@code inCollection} allows to override the collection name for the execution.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* remove(Jedi.class)
|
||||
* .inCollection("star-wars")
|
||||
* .matching(query(where("firstname").is("luke")))
|
||||
* .all();
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ExecutableRemoveOperation {
|
||||
|
||||
/**
|
||||
* Start creating a remove operation for the given {@literal domainType}.
|
||||
*
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @return new instance of {@link RemoveOperation}.
|
||||
* @throws IllegalArgumentException if domainType is {@literal null}.
|
||||
*/
|
||||
<T> RemoveOperation<T> remove(Class<T> domainType);
|
||||
|
||||
/**
|
||||
* Collection override (Optional).
|
||||
*
|
||||
* @param <T>
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface RemoveOperationWithCollection<T> extends RemoveOperationWithQuery<T> {
|
||||
|
||||
/**
|
||||
* Explicitly set the name of the collection to perform the query on. <br />
|
||||
* Skip this step to use the default collection derived from the domain type.
|
||||
*
|
||||
* @param collection must not be {@literal null} nor {@literal empty}.
|
||||
* @return new instance of {@link RemoveOperationWithCollection}.
|
||||
* @throws IllegalArgumentException if collection is {@literal null}.
|
||||
*/
|
||||
RemoveOperationWithQuery<T> inCollection(String collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface TerminatingRemoveOperation<T> {
|
||||
|
||||
/**
|
||||
* Remove all documents matching.
|
||||
*
|
||||
* @return the {@link DeleteResult}. Never {@literal null}.
|
||||
*/
|
||||
DeleteResult all();
|
||||
|
||||
/**
|
||||
* Remove and return all matching documents. <br/>
|
||||
* <strong>NOTE</strong> The entire list of documents will be fetched before sending the actual delete commands.
|
||||
* Also, {@link org.springframework.context.ApplicationEvent}s will be published for each and every delete
|
||||
* operation.
|
||||
*
|
||||
* @return empty {@link List} if no match found. Never {@literal null}.
|
||||
*/
|
||||
List<T> findAndRemove();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface RemoveOperationWithQuery<T> extends TerminatingRemoveOperation<T> {
|
||||
|
||||
/**
|
||||
* Define the query filtering elements.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @return new instance of {@link TerminatingRemoveOperation}.
|
||||
* @throws IllegalArgumentException if query is {@literal null}.
|
||||
*/
|
||||
TerminatingRemoveOperation<T> matching(Query query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface RemoveOperation<T> extends RemoveOperationWithCollection<T> {}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.client.result.DeleteResult;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExecutableRemoveOperation}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
class ExecutableRemoveOperationSupport implements ExecutableRemoveOperation {
|
||||
|
||||
private final MongoTemplate tempate;
|
||||
|
||||
/**
|
||||
* Create new {@link ExecutableRemoveOperationSupport}.
|
||||
*
|
||||
* @param template must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if template is {@literal null}.
|
||||
*/
|
||||
ExecutableRemoveOperationSupport(MongoTemplate template) {
|
||||
|
||||
Assert.notNull(template, "Template must not be null!");
|
||||
|
||||
this.tempate = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> RemoveOperation<T> remove(Class<T> domainType) {
|
||||
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
|
||||
return new RemoveOperationSupport<>(tempate, null, domainType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class RemoveOperationSupport<T> implements RemoveOperation<T>, RemoveOperationWithCollection<T> {
|
||||
|
||||
private final MongoTemplate template;
|
||||
private final Query query;
|
||||
private final Class<T> domainType;
|
||||
private final String collection;
|
||||
|
||||
@Override
|
||||
public RemoveOperationWithQuery<T> inCollection(String collection) {
|
||||
|
||||
Assert.hasText(collection, "Collection must not be null nor empty!");
|
||||
|
||||
return new RemoveOperationSupport<>(template, query, domainType, collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminatingRemoveOperation<T> matching(Query query) {
|
||||
|
||||
Assert.notNull(query, "Query must not be null!");
|
||||
|
||||
return new RemoveOperationSupport<>(template, query, domainType, collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteResult all() {
|
||||
|
||||
String collectionName = getCollectionName();
|
||||
|
||||
return template.doRemove(collectionName, getQuery(), domainType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> findAndRemove() {
|
||||
|
||||
String collectionName = getCollectionName();
|
||||
|
||||
return template.doFindAndDelete(collectionName, getQuery(), domainType);
|
||||
}
|
||||
|
||||
private String getCollectionName() {
|
||||
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType);
|
||||
}
|
||||
|
||||
private Query getQuery() {
|
||||
return query != null ? query : new BasicQuery(new Document());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
|
||||
/**
|
||||
* {@link ExecutableUpdateOperation} allows creation and execution of MongoDB update / findAndModify operations in a
|
||||
* fluent API style. <br />
|
||||
* The starting {@literal domainType} is used for mapping the {@link Query} provided via {@code matching}, as well as
|
||||
* the {@link Update} via {@code apply} into the MongoDB specific representations. The collection to operate on is by
|
||||
* default derived from the initial {@literal domainType} and can be defined there via
|
||||
* {@link org.springframework.data.mongodb.core.mapping.Document}. Using {@code inCollection} allows to override the
|
||||
* collection name for the execution.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* update(Jedi.class)
|
||||
* .inCollection("star-wars")
|
||||
* .matching(query(where("firstname").is("luke")))
|
||||
* .apply(new Update().set("lastname", "skywalker"))
|
||||
* .upsert();
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ExecutableUpdateOperation {
|
||||
|
||||
/**
|
||||
* Start creating an update operation for the given {@literal domainType}.
|
||||
*
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @return new instance of {@link UpdateOperation}.
|
||||
* @throws IllegalArgumentException if domainType is {@literal null}.
|
||||
*/
|
||||
<T> UpdateOperation<T> update(Class<T> domainType);
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface UpdateOperation<T>
|
||||
extends UpdateOperationWithCollection<T>, UpdateOperationWithQuery<T>, UpdateOperationWithUpdate<T> {}
|
||||
|
||||
/**
|
||||
* Declare the {@link Update} to apply.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface UpdateOperationWithUpdate<T> {
|
||||
|
||||
/**
|
||||
* Set the {@link Update} to be applied.
|
||||
*
|
||||
* @param update must not be {@literal null}.
|
||||
* @return new instance of {@link TerminatingUpdateOperation}.
|
||||
* @throws IllegalArgumentException if update is {@literal null}.
|
||||
*/
|
||||
TerminatingUpdateOperation<T> apply(Update update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly define the name of the collection to perform operation in.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface UpdateOperationWithCollection<T> {
|
||||
|
||||
/**
|
||||
* Explicitly set the name of the collection to perform the query on. <br />
|
||||
* Skip this step to use the default collection derived from the domain type.
|
||||
*
|
||||
* @param collection must not be {@literal null} nor {@literal empty}.
|
||||
* @return new instance of {@link UpdateOperationWithCollection}.
|
||||
* @throws IllegalArgumentException if collection is {@literal null}.
|
||||
*/
|
||||
UpdateOperationWithQuery<T> inCollection(String collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a filter query for the {@link Update}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface UpdateOperationWithQuery<T> extends UpdateOperationWithUpdate<T> {
|
||||
|
||||
/**
|
||||
* Filter documents by given {@literal query}.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @return new instance of {@link UpdateOperationWithQuery}.
|
||||
* @throws IllegalArgumentException if query is {@literal null}.
|
||||
*/
|
||||
UpdateOperationWithUpdate<T> matching(Query query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define {@link FindAndModifyOptions}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface FindAndModifyWithOptions<T> {
|
||||
|
||||
/**
|
||||
* Explicitly define {@link FindAndModifyOptions} for the {@link Update}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return new instance of {@link FindAndModifyWithOptions}.
|
||||
* @throws IllegalArgumentException if options is {@literal null}.
|
||||
*/
|
||||
TerminatingFindAndModifyOperation<T> withOptions(FindAndModifyOptions options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger findAndModify execution by calling one of the terminating methods.
|
||||
*/
|
||||
interface TerminatingFindAndModifyOperation<T> {
|
||||
|
||||
/**
|
||||
* Find, modify and return the first matching document.
|
||||
*
|
||||
* @return {@link Optional#empty()} if nothing found.
|
||||
*/
|
||||
Optional<T> findAndModify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger update execution by calling one of the terminating methods.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
interface TerminatingUpdateOperation<T> extends TerminatingFindAndModifyOperation<T>, FindAndModifyWithOptions<T> {
|
||||
|
||||
/**
|
||||
* Update all matching documents in the collection.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
UpdateResult all();
|
||||
|
||||
/**
|
||||
* Update the first document in the collection.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
UpdateResult first();
|
||||
|
||||
/**
|
||||
* Creates a new document if no documents match the filter query or updates the matching ones.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
UpdateResult upsert();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExecutableUpdateOperation}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
|
||||
|
||||
private final MongoTemplate template;
|
||||
|
||||
/**
|
||||
* Creates new {@link ExecutableUpdateOperationSupport}.
|
||||
*
|
||||
* @param template must not be {@literal null}.
|
||||
*/
|
||||
ExecutableUpdateOperationSupport(MongoTemplate template) {
|
||||
|
||||
Assert.notNull(template, "Template must not be null!");
|
||||
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> UpdateOperation<T> update(Class<T> domainType) {
|
||||
|
||||
Assert.notNull(domainType, "DomainType must not be null!");
|
||||
|
||||
return new UpdateOperationSupport<>(template, null, domainType, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class UpdateOperationSupport<T> implements UpdateOperation<T>, UpdateOperationWithCollection<T>,
|
||||
UpdateOperationWithQuery<T>, TerminatingUpdateOperation<T> {
|
||||
|
||||
private final MongoTemplate template;
|
||||
private final Query query;
|
||||
private final Class<T> domainType;
|
||||
private final Update update;
|
||||
private final String collection;
|
||||
private final FindAndModifyOptions options;
|
||||
|
||||
@Override
|
||||
public TerminatingUpdateOperation<T> apply(Update update) {
|
||||
|
||||
Assert.notNull(update, "Update must not be null!");
|
||||
|
||||
return new UpdateOperationSupport<>(template, query, domainType, update, collection, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateOperationWithQuery<T> inCollection(String collection) {
|
||||
|
||||
Assert.hasText(collection, "Collection must not be null nor empty!");
|
||||
|
||||
return new UpdateOperationSupport<>(template, query, domainType, update, collection, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateResult first() {
|
||||
return doUpdate(false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateResult upsert() {
|
||||
return doUpdate(true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> findAndModify() {
|
||||
|
||||
String collectionName = getCollectionName();
|
||||
|
||||
return Optional.ofNullable(template.findAndModify(query != null ? query : new BasicQuery(new Document()), update,
|
||||
options, domainType, collectionName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateOperationWithUpdate<T> matching(Query query) {
|
||||
|
||||
Assert.notNull(query, "Query must not be null!");
|
||||
|
||||
return new UpdateOperationSupport<>(template, query, domainType, update, collection, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateResult all() {
|
||||
return doUpdate(true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminatingFindAndModifyOperation<T> withOptions(FindAndModifyOptions options) {
|
||||
|
||||
Assert.notNull(options, "Options must not be null!");
|
||||
|
||||
return new UpdateOperationSupport<>(template, query, domainType, update, collection, options);
|
||||
}
|
||||
|
||||
private UpdateResult doUpdate(boolean multi, boolean upsert) {
|
||||
|
||||
String collectionName = getCollectionName();
|
||||
|
||||
Query query = this.query != null ? this.query : new BasicQuery(new Document());
|
||||
|
||||
return template.doUpdate(collectionName, query, update, domainType, upsert, multi);
|
||||
}
|
||||
|
||||
private String getCollectionName() {
|
||||
return StringUtils.hasText(collection) ? collection : template.determineCollectionName(domainType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2011 the original author or authors.
|
||||
* Copyright 2010-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,23 +15,50 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Mark Pollak
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class FindAndModifyOptions {
|
||||
|
||||
boolean returnNew;
|
||||
private boolean returnNew;
|
||||
private boolean upsert;
|
||||
private boolean remove;
|
||||
|
||||
boolean upsert;
|
||||
|
||||
boolean remove;
|
||||
private Collation collation;
|
||||
|
||||
/**
|
||||
* Static factory method to create a FindAndModifyOptions instance
|
||||
*
|
||||
*
|
||||
* @return a new instance
|
||||
*/
|
||||
public static FindAndModifyOptions options() {
|
||||
return new FindAndModifyOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param options
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
public static FindAndModifyOptions of(FindAndModifyOptions source) {
|
||||
|
||||
FindAndModifyOptions options = new FindAndModifyOptions();
|
||||
if (source == null) {
|
||||
return options;
|
||||
}
|
||||
|
||||
options.returnNew = source.returnNew;
|
||||
options.upsert = source.upsert;
|
||||
options.remove = source.remove;
|
||||
options.collation = source.collation;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
public FindAndModifyOptions returnNew(boolean returnNew) {
|
||||
this.returnNew = returnNew;
|
||||
return this;
|
||||
@@ -47,6 +74,19 @@ public class FindAndModifyOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the {@link Collation} specifying language-specific rules for string comparison.
|
||||
*
|
||||
* @param collation
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
public FindAndModifyOptions collation(Collation collation) {
|
||||
|
||||
this.collation = collation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isReturnNew() {
|
||||
return returnNew;
|
||||
}
|
||||
@@ -59,4 +99,14 @@ public class FindAndModifyOptions {
|
||||
return remove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Collation} specifying language-specific rules for string comparison.
|
||||
*
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
public Optional<Collation> getCollation() {
|
||||
return Optional.ofNullable(collation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
/**
|
||||
* Stripped down interface providing access to a fluent API that specifies a basic set of MongoDB operations.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface FluentMongoOperations extends ExecutableFindOperation, ExecutableInsertOperation,
|
||||
ExecutableUpdateOperation, ExecutableRemoveOperation, ExecutableAggregationOperation {}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -62,7 +62,7 @@ class GeoCommandStatistics {
|
||||
* didn't return any result introduced in MongoDB 3.2 RC1.
|
||||
*
|
||||
* @return
|
||||
* @see https://jira.mongodb.org/browse/SERVER-21024
|
||||
* @see <a href="https://jira.mongodb.org/browse/SERVER-21024">MongoDB Jira SERVER-21024</a>
|
||||
*/
|
||||
public double getAverageDistance() {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,15 +17,14 @@ package org.springframework.data.mongodb.core;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.mongodb.core.geo.GeoJsonModule;
|
||||
import org.springframework.data.web.config.SpringDataWebConfigurationMixin;
|
||||
import org.springframework.data.web.config.SpringDataJacksonModules;
|
||||
|
||||
/**
|
||||
* Configuration class to expose {@link GeoJsonModule} as a Spring bean.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@SpringDataWebConfigurationMixin
|
||||
public class GeoJsonConfiguration {
|
||||
public class GeoJsonConfiguration implements SpringDataJacksonModules {
|
||||
|
||||
@Bean
|
||||
public GeoJsonModule geoJsonModule() {
|
||||
|
||||
@@ -16,21 +16,15 @@
|
||||
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.domain.Sort.Direction.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mongodb.core.index.IndexDefinition;
|
||||
import org.springframework.data.mongodb.core.index.IndexField;
|
||||
import org.springframework.data.mongodb.core.index.IndexInfo;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.mongodb.client.model.Collation;
|
||||
import com.mongodb.client.model.IndexOptions;
|
||||
|
||||
/**
|
||||
@@ -45,10 +39,6 @@ abstract class IndexConverters {
|
||||
private static final Converter<IndexDefinition, IndexOptions> DEFINITION_TO_MONGO_INDEX_OPTIONS;
|
||||
private static final Converter<Document, IndexInfo> DOCUMENT_INDEX_INFO;
|
||||
|
||||
private static final Double ONE = Double.valueOf(1);
|
||||
private static final Double MINUS_ONE = Double.valueOf(-1);
|
||||
private static final Collection<String> TWO_D_IDENTIFIERS = Arrays.asList("2d", "2dsphere");
|
||||
|
||||
static {
|
||||
|
||||
DEFINITION_TO_MONGO_INDEX_OPTIONS = getIndexDefinitionIndexOptionsConverter();
|
||||
@@ -117,50 +107,29 @@ abstract class IndexConverters {
|
||||
}
|
||||
}
|
||||
|
||||
if (indexOptions.containsKey("partialFilterExpression")) {
|
||||
ops = ops.partialFilterExpression((org.bson.Document) indexOptions.get("partialFilterExpression"));
|
||||
}
|
||||
|
||||
if (indexOptions.containsKey("collation")) {
|
||||
ops = ops.collation(fromDocument(indexOptions.get("collation", Document.class)));
|
||||
}
|
||||
|
||||
return ops;
|
||||
};
|
||||
}
|
||||
|
||||
private static Converter<Document, IndexInfo> getDocumentIndexInfoConverter() {
|
||||
public static Collation fromDocument(Document source) {
|
||||
|
||||
return ix -> {
|
||||
Document keyDocument = (Document) ix.get("key");
|
||||
int numberOfElements = keyDocument.keySet().size();
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<IndexField> indexFields = new ArrayList<IndexField>(numberOfElements);
|
||||
|
||||
for (String key : keyDocument.keySet()) {
|
||||
|
||||
Object value = keyDocument.get(key);
|
||||
|
||||
if (TWO_D_IDENTIFIERS.contains(value)) {
|
||||
indexFields.add(IndexField.geo(key));
|
||||
} else if ("text".equals(value)) {
|
||||
|
||||
Document weights = (Document) ix.get("weights");
|
||||
for (String fieldName : weights.keySet()) {
|
||||
indexFields.add(IndexField.text(fieldName, Float.valueOf(weights.get(fieldName).toString())));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Double keyValue = new Double(value.toString());
|
||||
|
||||
if (ONE.equals(keyValue)) {
|
||||
indexFields.add(IndexField.create(key, ASC));
|
||||
} else if (MINUS_ONE.equals(keyValue)) {
|
||||
indexFields.add(IndexField.create(key, DESC));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String name = ix.get("name").toString();
|
||||
|
||||
boolean unique = ix.containsKey("unique") ? (Boolean) ix.get("unique") : false;
|
||||
boolean sparse = ix.containsKey("sparse") ? (Boolean) ix.get("sparse") : false;
|
||||
|
||||
String language = ix.containsKey("default_language") ? (String) ix.get("default_language") : "";
|
||||
return new IndexInfo(indexFields, name, unique, sparse, language);
|
||||
};
|
||||
return org.springframework.data.mongodb.core.Collation.from(source).toMongoCollation();
|
||||
}
|
||||
|
||||
private static Converter<Document, IndexInfo> getDocumentIndexInfoConverter() {
|
||||
return IndexInfo::indexInfoOf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||
|
||||
/**
|
||||
* TODO: Revisit for a better pattern.
|
||||
* @author Mark Paluch
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2013 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,31 +15,30 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core;
|
||||
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import org.bson.Document;
|
||||
import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
/**
|
||||
* Mongo server administration exposed via JMX annotations
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Thomas Darimont
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@ManagedResource(description = "Mongo Admin Operations")
|
||||
public class MongoAdmin implements MongoAdminOperations {
|
||||
|
||||
private final Mongo mongo;
|
||||
private String username;
|
||||
private String password;
|
||||
private String authenticationDatabaseName;
|
||||
private final MongoClient mongoClient;
|
||||
|
||||
public MongoAdmin(Mongo mongo) {
|
||||
Assert.notNull(mongo);
|
||||
this.mongo = mongo;
|
||||
public MongoAdmin(MongoClient mongoClient) {
|
||||
|
||||
Assert.notNull(mongoClient, "MongoClient must not be null!");
|
||||
this.mongoClient = mongoClient;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -47,7 +46,7 @@ public class MongoAdmin implements MongoAdminOperations {
|
||||
*/
|
||||
@ManagedOperation
|
||||
public void dropDatabase(String databaseName) {
|
||||
getDB(databaseName).dropDatabase();
|
||||
getDB(databaseName).drop();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -63,37 +62,16 @@ public class MongoAdmin implements MongoAdminOperations {
|
||||
*/
|
||||
@ManagedOperation
|
||||
public String getDatabaseStats(String databaseName) {
|
||||
return getDB(databaseName).getStats().toString();
|
||||
return getDB(databaseName).runCommand(new Document("dbStats", 1).append("scale" , 1024)).toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username to use to connect to the Mongo database
|
||||
*
|
||||
* @param username The username to use
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
@ManagedOperation
|
||||
public String getServerStatus() {
|
||||
return getDB("admin").runCommand(new Document("serverStatus", 1).append("rangeDeleter", 1).append("repl", 1)).toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password to use to authenticate with the Mongo database.
|
||||
*
|
||||
* @param password The password to use
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authenticationDatabaseName to use to authenticate with the Mongo database.
|
||||
*
|
||||
* @param authenticationDatabaseName The authenticationDatabaseName to use.
|
||||
*/
|
||||
public void setAuthenticationDatabaseName(String authenticationDatabaseName) {
|
||||
this.authenticationDatabaseName = authenticationDatabaseName;
|
||||
}
|
||||
|
||||
DB getDB(String databaseName) {
|
||||
return MongoDbUtils.getDB(mongo, databaseName, new UserCredentials(username, password), authenticationDatabaseName);
|
||||
MongoDatabase getDB(String databaseName) {
|
||||
return mongoClient.getDatabase(databaseName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,7 +26,6 @@ import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientOptions;
|
||||
import com.mongodb.MongoCredential;
|
||||
@@ -38,7 +37,7 @@ import com.mongodb.ServerAddress;
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
public class MongoClientFactoryBean extends AbstractFactoryBean<Mongo> implements PersistenceExceptionTranslator {
|
||||
public class MongoClientFactoryBean extends AbstractFactoryBean<MongoClient> implements PersistenceExceptionTranslator {
|
||||
|
||||
private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();
|
||||
|
||||
@@ -108,8 +107,8 @@ public class MongoClientFactoryBean extends AbstractFactoryBean<Mongo> implement
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
public Class<? extends Mongo> getObjectType() {
|
||||
return Mongo.class;
|
||||
public Class<? extends MongoClient> getObjectType() {
|
||||
return MongoClient.class;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -125,7 +124,7 @@ public class MongoClientFactoryBean extends AbstractFactoryBean<Mongo> implement
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||
*/
|
||||
@Override
|
||||
protected Mongo createInstance() throws Exception {
|
||||
protected MongoClient createInstance() throws Exception {
|
||||
|
||||
if (mongoClientOptions == null) {
|
||||
mongoClientOptions = MongoClientOptions.builder().build();
|
||||
@@ -143,7 +142,7 @@ public class MongoClientFactoryBean extends AbstractFactoryBean<Mongo> implement
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#destroyInstance(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected void destroyInstance(Mongo instance) throws Exception {
|
||||
protected void destroyInstance(MongoClient instance) throws Exception {
|
||||
instance.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,9 +30,10 @@ import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
* A factory bean for construction of a {@link MongoClientOptions} instance.
|
||||
*
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @since 1.7
|
||||
*/
|
||||
public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClientOptions> {
|
||||
@@ -62,13 +63,14 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
private int heartbeatConnectTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatConnectTimeout();
|
||||
private int heartbeatSocketTimeout = DEFAULT_MONGO_OPTIONS.getHeartbeatSocketTimeout();
|
||||
private String requiredReplicaSetName = DEFAULT_MONGO_OPTIONS.getRequiredReplicaSetName();
|
||||
private int serverSelectionTimeout = DEFAULT_MONGO_OPTIONS.getServerSelectionTimeout();
|
||||
|
||||
private boolean ssl;
|
||||
private SSLSocketFactory sslSocketFactory;
|
||||
|
||||
/**
|
||||
* Set the {@link MongoClient} description.
|
||||
*
|
||||
*
|
||||
* @param description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
@@ -77,7 +79,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the minimum number of connections per host.
|
||||
*
|
||||
*
|
||||
* @param minConnectionsPerHost
|
||||
*/
|
||||
public void setMinConnectionsPerHost(int minConnectionsPerHost) {
|
||||
@@ -87,7 +89,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
/**
|
||||
* Set the number of connections allowed per host. Will block if run out. Default is 10. System property
|
||||
* {@code MONGO.POOLSIZE} can override
|
||||
*
|
||||
*
|
||||
* @param connectionsPerHost
|
||||
*/
|
||||
public void setConnectionsPerHost(int connectionsPerHost) {
|
||||
@@ -98,7 +100,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
* Set the multiplier for connectionsPerHost for # of threads that can block. Default is 5. If connectionsPerHost is
|
||||
* 10, and threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block more than that and an
|
||||
* exception will be thrown.
|
||||
*
|
||||
*
|
||||
* @param threadsAllowedToBlockForConnectionMultiplier
|
||||
*/
|
||||
public void setThreadsAllowedToBlockForConnectionMultiplier(int threadsAllowedToBlockForConnectionMultiplier) {
|
||||
@@ -107,7 +109,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the max wait time of a blocking thread for a connection. Default is 12000 ms (2 minutes)
|
||||
*
|
||||
*
|
||||
* @param maxWaitTime
|
||||
*/
|
||||
public void setMaxWaitTime(int maxWaitTime) {
|
||||
@@ -116,7 +118,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* The maximum idle time for a pooled connection.
|
||||
*
|
||||
*
|
||||
* @param maxConnectionIdleTime
|
||||
*/
|
||||
public void setMaxConnectionIdleTime(int maxConnectionIdleTime) {
|
||||
@@ -125,7 +127,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the maximum life time for a pooled connection.
|
||||
*
|
||||
*
|
||||
* @param maxConnectionLifeTime
|
||||
*/
|
||||
public void setMaxConnectionLifeTime(int maxConnectionLifeTime) {
|
||||
@@ -134,7 +136,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the connect timeout in milliseconds. 0 is default and infinite.
|
||||
*
|
||||
*
|
||||
* @param connectTimeout
|
||||
*/
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
@@ -143,7 +145,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the socket timeout. 0 is default and infinite.
|
||||
*
|
||||
*
|
||||
* @param socketTimeout
|
||||
*/
|
||||
public void setSocketTimeout(int socketTimeout) {
|
||||
@@ -152,7 +154,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the keep alive flag, controls whether or not to have socket keep alive timeout. Defaults to false.
|
||||
*
|
||||
*
|
||||
* @param socketKeepAlive
|
||||
*/
|
||||
public void setSocketKeepAlive(boolean socketKeepAlive) {
|
||||
@@ -161,7 +163,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the {@link ReadPreference}.
|
||||
*
|
||||
*
|
||||
* @param readPreference
|
||||
*/
|
||||
public void setReadPreference(ReadPreference readPreference) {
|
||||
@@ -171,7 +173,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
/**
|
||||
* Set the {@link WriteConcern} that will be the default value used when asking the {@link MongoDbFactory} for a DB
|
||||
* object.
|
||||
*
|
||||
*
|
||||
* @param writeConcern
|
||||
*/
|
||||
public void setWriteConcern(WriteConcern writeConcern) {
|
||||
@@ -187,7 +189,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the frequency that the driver will attempt to determine the current state of each server in the cluster.
|
||||
*
|
||||
*
|
||||
* @param heartbeatFrequency
|
||||
*/
|
||||
public void setHeartbeatFrequency(int heartbeatFrequency) {
|
||||
@@ -197,7 +199,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
/**
|
||||
* In the event that the driver has to frequently re-check a server's availability, it will wait at least this long
|
||||
* since the previous check to avoid wasted effort.
|
||||
*
|
||||
*
|
||||
* @param minHeartbeatFrequency
|
||||
*/
|
||||
public void setMinHeartbeatFrequency(int minHeartbeatFrequency) {
|
||||
@@ -206,7 +208,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the connect timeout for connections used for the cluster heartbeat.
|
||||
*
|
||||
*
|
||||
* @param heartbeatConnectTimeout
|
||||
*/
|
||||
public void setHeartbeatConnectTimeout(int heartbeatConnectTimeout) {
|
||||
@@ -215,7 +217,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Set the socket timeout for connections used for the cluster heartbeat.
|
||||
*
|
||||
*
|
||||
* @param heartbeatSocketTimeout
|
||||
*/
|
||||
public void setHeartbeatSocketTimeout(int heartbeatSocketTimeout) {
|
||||
@@ -224,7 +226,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* Configures the name of the replica set.
|
||||
*
|
||||
*
|
||||
* @param requiredReplicaSetName
|
||||
*/
|
||||
public void setRequiredReplicaSetName(String requiredReplicaSetName) {
|
||||
@@ -233,7 +235,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
|
||||
/**
|
||||
* This controls if the driver should us an SSL connection. Defaults to |@literal false}.
|
||||
*
|
||||
*
|
||||
* @param ssl
|
||||
*/
|
||||
public void setSsl(boolean ssl) {
|
||||
@@ -243,22 +245,35 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
/**
|
||||
* Set the {@link SSLSocketFactory} to use for the {@literal SSL} connection. If none is configured here,
|
||||
* {@link SSLSocketFactory#getDefault()} will be used.
|
||||
*
|
||||
*
|
||||
* @param sslSocketFactory
|
||||
*/
|
||||
public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
|
||||
|
||||
this.sslSocketFactory = sslSocketFactory;
|
||||
this.ssl = sslSocketFactory != null;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Set the {@literal server selection timeout} in msec for a 3.x MongoDB Java driver. If not set the default value of
|
||||
* 30 sec will be used. A value of 0 means that it will timeout immediately if no server is available. A negative
|
||||
* value means to wait indefinitely.
|
||||
*
|
||||
* @param serverSelectionTimeout in msec.
|
||||
*/
|
||||
public void setServerSelectionTimeout(int serverSelectionTimeout) {
|
||||
this.serverSelectionTimeout = serverSelectionTimeout;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||
*/
|
||||
@Override
|
||||
protected MongoClientOptions createInstance() throws Exception {
|
||||
|
||||
SocketFactory socketFactoryToUse = ssl ? (sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory
|
||||
.getDefault()) : this.socketFactory;
|
||||
SocketFactory socketFactoryToUse = ssl
|
||||
? (sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory.getDefault()) : this.socketFactory;
|
||||
|
||||
return MongoClientOptions.builder() //
|
||||
.alwaysUseMBeans(this.alwaysUseMBeans) //
|
||||
@@ -278,6 +293,7 @@ public class MongoClientOptionsFactoryBean extends AbstractFactoryBean<MongoClie
|
||||
.minHeartbeatFrequency(minHeartbeatFrequency) //
|
||||
.readPreference(readPreference) //
|
||||
.requiredReplicaSetName(requiredReplicaSetName) //
|
||||
.serverSelectionTimeout(serverSelectionTimeout) //
|
||||
.socketFactory(socketFactoryToUse) //
|
||||
.socketKeepAlive(socketKeepAlive) //
|
||||
.socketTimeout(socketTimeout) //
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* Helper class featuring helper methods for internal MongoDb classes. Mainly intended for internal use within the
|
||||
* framework.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Graeme Rocher
|
||||
* @author Oliver Gierke
|
||||
* @author Randy Watler
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @since 1.0
|
||||
*/
|
||||
public abstract class MongoDbUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MongoDbUtils.class);
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation.
|
||||
*/
|
||||
private MongoDbUtils() {}
|
||||
|
||||
/**
|
||||
* Obtains a {@link DB} connection for the given {@link Mongo} instance and database name
|
||||
*
|
||||
* @param mongo the {@link Mongo} instance, must not be {@literal null}.
|
||||
* @param databaseName the database name, must not be {@literal null} or empty.
|
||||
* @return the {@link DB} connection
|
||||
*/
|
||||
public static DB getDB(Mongo mongo, String databaseName) {
|
||||
return doGetDB(mongo, databaseName, UserCredentials.NO_CREDENTIALS, true, databaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@link DB} connection for the given {@link Mongo} instance and database name
|
||||
*
|
||||
* @param mongo the {@link Mongo} instance, must not be {@literal null}.
|
||||
* @param databaseName the database name, must not be {@literal null} or empty.
|
||||
* @param credentials the credentials to use, must not be {@literal null}.
|
||||
* @return the {@link DB} connection
|
||||
* @deprecated since 1.7. The {@link MongoClient} itself should hold credentials within
|
||||
* {@link MongoClient#getCredentialsList()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials) {
|
||||
return getDB(mongo, databaseName, credentials, databaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mongo
|
||||
* @param databaseName
|
||||
* @param credentials
|
||||
* @param authenticationDatabaseName
|
||||
* @return
|
||||
* @deprecated since 1.7. The {@link MongoClient} itself should hold credentials within
|
||||
* {@link MongoClient#getCredentialsList()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||
String authenticationDatabaseName) {
|
||||
|
||||
Assert.notNull(mongo, "No Mongo instance specified!");
|
||||
Assert.hasText(databaseName, "Database name must be given!");
|
||||
Assert.notNull(credentials, "Credentials must not be null, use UserCredentials.NO_CREDENTIALS!");
|
||||
Assert.hasText(authenticationDatabaseName, "Authentication database name must not be null or empty!");
|
||||
|
||||
return doGetDB(mongo, databaseName, credentials, true, authenticationDatabaseName);
|
||||
}
|
||||
|
||||
private static DB doGetDB(Mongo mongo, String databaseName, UserCredentials credentials, boolean allowCreate,
|
||||
String authenticationDatabaseName) {
|
||||
|
||||
DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
|
||||
|
||||
// Do we have a populated holder and TX sync active?
|
||||
if (dbHolder != null && !dbHolder.isEmpty() && TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
|
||||
DB db = dbHolder.getDB(databaseName);
|
||||
|
||||
// DB found but not yet synchronized
|
||||
if (db != null && !dbHolder.isSynchronizedWithTransaction()) {
|
||||
|
||||
LOGGER.debug("Registering Spring transaction synchronization for existing MongoDB {}.", databaseName);
|
||||
|
||||
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(dbHolder, mongo));
|
||||
dbHolder.setSynchronizedWithTransaction(true);
|
||||
}
|
||||
|
||||
if (db != null) {
|
||||
return db;
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup fresh database instance
|
||||
LOGGER.debug("Getting Mongo Database name=[{}]", databaseName);
|
||||
|
||||
DB db = mongo.getDB(databaseName);
|
||||
|
||||
if (!(mongo instanceof MongoClient) && requiresAuthDbAuthentication(credentials)) {
|
||||
ReflectiveDbInvoker.authenticate(mongo, db, credentials, authenticationDatabaseName);
|
||||
}
|
||||
|
||||
// TX sync active, bind new database to thread
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
|
||||
LOGGER.debug("Registering Spring transaction synchronization for MongoDB instance {}.", databaseName);
|
||||
|
||||
DbHolder holderToUse = dbHolder;
|
||||
|
||||
if (holderToUse == null) {
|
||||
holderToUse = new DbHolder(databaseName, db);
|
||||
} else {
|
||||
holderToUse.addDB(databaseName, db);
|
||||
}
|
||||
|
||||
// synchronize holder only if not yet synchronized
|
||||
if (!holderToUse.isSynchronizedWithTransaction()) {
|
||||
TransactionSynchronizationManager.registerSynchronization(new MongoSynchronization(holderToUse, mongo));
|
||||
holderToUse.setSynchronizedWithTransaction(true);
|
||||
}
|
||||
|
||||
if (holderToUse != dbHolder) {
|
||||
TransactionSynchronizationManager.bindResource(mongo, holderToUse);
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether we are allowed to return the DB.
|
||||
if (!allowCreate && !isDBTransactional(db, mongo)) {
|
||||
throw new IllegalStateException("No Mongo DB bound to thread, "
|
||||
+ "and configuration does not allow creation of non-transactional one here");
|
||||
}
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given DB instance is transactional, that is, bound to the current thread by Spring's transaction
|
||||
* facilities.
|
||||
*
|
||||
* @param db the DB to check
|
||||
* @param mongo the Mongo instance that the DB was created with (may be <code>null</code>)
|
||||
* @return whether the DB is transactional
|
||||
*/
|
||||
public static boolean isDBTransactional(DB db, Mongo mongo) {
|
||||
|
||||
if (mongo == null) {
|
||||
return false;
|
||||
}
|
||||
DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
|
||||
return dbHolder != null && dbHolder.containsDB(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform actual closing of the Mongo DB object, catching and logging any cleanup exceptions thrown.
|
||||
*
|
||||
* @param db the DB to close (may be <code>null</code>)
|
||||
* @deprecated since 1.7. The main use case for this method is to ensure that applications can read their own
|
||||
* unacknowledged writes, but this is no longer so prevalent since the MongoDB Java driver version 3
|
||||
* started defaulting to acknowledged writes.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void closeDB(DB db) {
|
||||
|
||||
if (db != null) {
|
||||
LOGGER.debug("Closing Mongo DB object");
|
||||
try {
|
||||
ReflectiveDbInvoker.requestDone(db);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.debug("Unexpected exception on closing Mongo DB object", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if credentials present. In case we're using a mongo-java-driver version 3 or above we do not have the need
|
||||
* for authentication as the auth data has to be provided within the MongoClient
|
||||
*
|
||||
* @param credentials
|
||||
* @return
|
||||
*/
|
||||
private static boolean requiresAuthDbAuthentication(UserCredentials credentials) {
|
||||
|
||||
if (credentials == null || !credentials.hasUsername()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !MongoClientVersion.isMongo3Driver();
|
||||
}
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoOptions;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
* Convenient factory for configuring MongoDB.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Graeme Rocher
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @since 1.0
|
||||
* @deprecated since 1.7. Please use {@link MongoClientFactoryBean} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class MongoFactoryBean extends AbstractFactoryBean<Mongo> implements PersistenceExceptionTranslator {
|
||||
|
||||
private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();
|
||||
|
||||
private MongoOptions mongoOptions;
|
||||
private String host;
|
||||
private Integer port;
|
||||
private WriteConcern writeConcern;
|
||||
private List<ServerAddress> replicaSetSeeds;
|
||||
private List<ServerAddress> replicaPair;
|
||||
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_EXCEPTION_TRANSLATOR;
|
||||
|
||||
/**
|
||||
* @param mongoOptions
|
||||
*/
|
||||
public void setMongoOptions(MongoOptions mongoOptions) {
|
||||
this.mongoOptions = mongoOptions;
|
||||
}
|
||||
|
||||
public void setReplicaSetSeeds(ServerAddress[] replicaSetSeeds) {
|
||||
this.replicaSetSeeds = filterNonNullElementsAsList(replicaSetSeeds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #setReplicaSetSeeds(ServerAddress[])} instead
|
||||
* @param replicaPair
|
||||
*/
|
||||
@Deprecated
|
||||
public void setReplicaPair(ServerAddress[] replicaPair) {
|
||||
this.replicaPair = filterNonNullElementsAsList(replicaPair);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the host to connect to.
|
||||
*
|
||||
* @param host
|
||||
*/
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the port to connect to.
|
||||
*
|
||||
* @param port
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link WriteConcern} to be configured for the {@link Mongo} instance to be created.
|
||||
*
|
||||
* @param writeConcern
|
||||
*/
|
||||
public void setWriteConcern(WriteConcern writeConcern) {
|
||||
this.writeConcern = writeConcern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link PersistenceExceptionTranslator} to use.
|
||||
*
|
||||
* @param exceptionTranslator can be {@literal null}.
|
||||
*/
|
||||
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
|
||||
this.exceptionTranslator = exceptionTranslator == null ? DEFAULT_EXCEPTION_TRANSLATOR : exceptionTranslator;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
public Class<? extends Mongo> getObjectType() {
|
||||
return Mongo.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
*/
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
return exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||
*/
|
||||
@Override
|
||||
protected Mongo createInstance() throws Exception {
|
||||
|
||||
Mongo mongo;
|
||||
ServerAddress defaultOptions = new ServerAddress();
|
||||
|
||||
if (mongoOptions == null) {
|
||||
mongoOptions = new MongoOptions();
|
||||
}
|
||||
|
||||
if (!isNullOrEmpty(replicaPair)) {
|
||||
if (replicaPair.size() < 2) {
|
||||
throw new CannotGetMongoDbConnectionException("A replica pair must have two server entries");
|
||||
}
|
||||
mongo = new Mongo(replicaPair.get(0), replicaPair.get(1), mongoOptions);
|
||||
} else if (!isNullOrEmpty(replicaSetSeeds)) {
|
||||
mongo = new Mongo(replicaSetSeeds, mongoOptions);
|
||||
} else {
|
||||
String mongoHost = StringUtils.hasText(host) ? host : defaultOptions.getHost();
|
||||
mongo = port != null ? new Mongo(new ServerAddress(mongoHost, port), mongoOptions) : new Mongo(mongoHost,
|
||||
mongoOptions);
|
||||
}
|
||||
|
||||
if (writeConcern != null) {
|
||||
mongo.setWriteConcern(writeConcern);
|
||||
}
|
||||
|
||||
return mongo;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#destroyInstance(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected void destroyInstance(Mongo mongo) throws Exception {
|
||||
mongo.close();
|
||||
}
|
||||
|
||||
private static boolean isNullOrEmpty(Collection<?> elements) {
|
||||
return elements == null || elements.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given array as {@link List} with all {@literal null} elements removed.
|
||||
*
|
||||
* @param elements the elements to filter <T>
|
||||
* @return a new unmodifiable {@link List#} from the given elements without nulls
|
||||
*/
|
||||
private static <T> List<T> filterNonNullElementsAsList(T[] elements) {
|
||||
|
||||
if (elements == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<T> candidateElements = new ArrayList<T>();
|
||||
|
||||
for (T element : elements) {
|
||||
if (element != null) {
|
||||
candidateElements.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(candidateElements);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
*
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
@@ -23,6 +23,7 @@ import org.bson.Document;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
|
||||
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
@@ -38,7 +39,6 @@ import org.springframework.data.mongodb.core.query.Update;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
|
||||
import com.mongodb.Cursor;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.ReadPreference;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.result.DeleteResult;
|
||||
@@ -48,7 +48,7 @@ import com.mongodb.client.result.UpdateResult;
|
||||
* Interface that specifies a basic set of MongoDB operations. Implemented by {@link MongoTemplate}. Not often used but
|
||||
* a useful option for extensibility and testability (as it can be easily mocked, stubbed, or be the target of a JDK
|
||||
* proxy).
|
||||
*
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
@@ -56,12 +56,13 @@ import com.mongodb.client.result.UpdateResult;
|
||||
* @author Chuong Ngo
|
||||
* @author Christoph Strobl
|
||||
* @author Thomas Darimont
|
||||
* @author Maninder Singh
|
||||
*/
|
||||
public interface MongoOperations {
|
||||
public interface MongoOperations extends FluentMongoOperations {
|
||||
|
||||
/**
|
||||
* The collection name used for the specified class by this template.
|
||||
*
|
||||
*
|
||||
* @param entityClass must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -71,7 +72,7 @@ public interface MongoOperations {
|
||||
* Execute the a MongoDB command expressed as a JSON string. This will call the method JSON.parse that is part of the
|
||||
* MongoDB driver to convert the JSON string to a Document. Any errors that result from executing this command will be
|
||||
* converted into Spring's DAO exception hierarchy.
|
||||
*
|
||||
*
|
||||
* @param jsonCommand a MongoDB command expressed as a JSON string.
|
||||
*/
|
||||
Document executeCommand(String jsonCommand);
|
||||
@@ -79,7 +80,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's DAO
|
||||
* exception hierarchy.
|
||||
*
|
||||
*
|
||||
* @param command a MongoDB command
|
||||
*/
|
||||
Document executeCommand(Document command);
|
||||
@@ -87,7 +88,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Execute a MongoDB command. Any errors that result from executing this command will be converted into Spring's data
|
||||
* access exception hierarchy.
|
||||
*
|
||||
*
|
||||
* @param command a MongoDB command, must not be {@literal null}.
|
||||
* @param readPreference read preferences to use, can be {@literal null}.
|
||||
* @return
|
||||
@@ -97,7 +98,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Execute a MongoDB query and iterate over the query results on a per-document basis with a DocumentCallbackHandler.
|
||||
*
|
||||
*
|
||||
* @param query the query class that specifies the criteria used to find a record and also an optional fields
|
||||
* specification
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
@@ -109,7 +110,7 @@ public interface MongoOperations {
|
||||
* Executes a {@link DbCallback} translating any exceptions as necessary.
|
||||
* <p/>
|
||||
* Allows for returning a result object, that is a domain object or a collection of domain objects.
|
||||
*
|
||||
*
|
||||
* @param <T> return type
|
||||
* @param action callback object that specifies the MongoDB actions to perform on the passed in DB instance.
|
||||
* @return a result object returned by the action or <tt>null</tt>
|
||||
@@ -120,7 +121,7 @@ public interface MongoOperations {
|
||||
* Executes the given {@link CollectionCallback} on the entity collection of the specified class.
|
||||
* <p/>
|
||||
* Allows for returning a result object, that is a domain object or a collection of domain objects.
|
||||
*
|
||||
*
|
||||
* @param entityClass class that determines the collection to use
|
||||
* @param <T> return type
|
||||
* @param action callback object that specifies the MongoDB action
|
||||
@@ -132,7 +133,7 @@ public interface MongoOperations {
|
||||
* Executes the given {@link CollectionCallback} on the collection of the given name.
|
||||
* <p/>
|
||||
* Allows for returning a result object, that is a domain object or a collection of domain objects.
|
||||
*
|
||||
*
|
||||
* @param <T> return type
|
||||
* @param collectionName the name of the collection that specifies which DBCollection instance will be passed into
|
||||
* @param action callback object that specifies the MongoDB action the callback action.
|
||||
@@ -145,7 +146,7 @@ public interface MongoOperations {
|
||||
* {@link Cursor}.
|
||||
* <p>
|
||||
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed.
|
||||
*
|
||||
*
|
||||
* @param <T> element return type
|
||||
* @param query must not be {@literal null}.
|
||||
* @param entityType must not be {@literal null}.
|
||||
@@ -159,7 +160,7 @@ public interface MongoOperations {
|
||||
* by a Mongo DB {@link Cursor}.
|
||||
* <p>
|
||||
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed.
|
||||
*
|
||||
*
|
||||
* @param <T> element return type
|
||||
* @param query must not be {@literal null}.
|
||||
* @param entityType must not be {@literal null}.
|
||||
@@ -171,7 +172,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Create an uncapped collection with a name based on the provided entity class.
|
||||
*
|
||||
*
|
||||
* @param entityClass class that determines the collection to create
|
||||
* @return the created collection
|
||||
*/
|
||||
@@ -179,7 +180,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Create a collection with a name based on the provided entity class using the options.
|
||||
*
|
||||
*
|
||||
* @param entityClass class that determines the collection to create
|
||||
* @param collectionOptions options to use when creating the collection.
|
||||
* @return the created collection
|
||||
@@ -188,7 +189,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Create an uncapped collection with the provided name.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection
|
||||
* @return the created collection
|
||||
*/
|
||||
@@ -196,7 +197,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Create a collection with the provided name and options.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection
|
||||
* @param collectionOptions options to use when creating the collection.
|
||||
* @return the created collection
|
||||
@@ -205,7 +206,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* A set of collection names.
|
||||
*
|
||||
*
|
||||
* @return list of collection names
|
||||
*/
|
||||
Set<String> getCollectionNames();
|
||||
@@ -214,7 +215,7 @@ public interface MongoOperations {
|
||||
* Get a collection by name, creating it if it doesn't exist.
|
||||
* <p/>
|
||||
* Translate any exceptions as necessary.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection
|
||||
* @return an existing collection or a newly created one.
|
||||
*/
|
||||
@@ -224,7 +225,7 @@ public interface MongoOperations {
|
||||
* Check to see if a collection with a name indicated by the entity class exists.
|
||||
* <p/>
|
||||
* Translate any exceptions as necessary.
|
||||
*
|
||||
*
|
||||
* @param entityClass class that determines the name of the collection
|
||||
* @return true if a collection with the given name is found, false otherwise.
|
||||
*/
|
||||
@@ -234,7 +235,7 @@ public interface MongoOperations {
|
||||
* Check to see if a collection with a given name exists.
|
||||
* <p/>
|
||||
* Translate any exceptions as necessary.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection
|
||||
* @return true if a collection with the given name is found, false otherwise.
|
||||
*/
|
||||
@@ -244,7 +245,7 @@ public interface MongoOperations {
|
||||
* Drop the collection with the name indicated by the entity class.
|
||||
* <p/>
|
||||
* Translate any exceptions as necessary.
|
||||
*
|
||||
*
|
||||
* @param entityClass class that determines the collection to drop/delete.
|
||||
*/
|
||||
<T> void dropCollection(Class<T> entityClass);
|
||||
@@ -253,28 +254,28 @@ public interface MongoOperations {
|
||||
* Drop the collection with the given name.
|
||||
* <p/>
|
||||
* Translate any exceptions as necessary.
|
||||
*
|
||||
*
|
||||
* @param collectionName name of the collection to drop/delete.
|
||||
*/
|
||||
void dropCollection(String collectionName);
|
||||
|
||||
/**
|
||||
* Returns the operations that can be performed on indexes
|
||||
*
|
||||
*
|
||||
* @return index operations on the named collection
|
||||
*/
|
||||
IndexOperations indexOps(String collectionName);
|
||||
|
||||
/**
|
||||
* Returns the operations that can be performed on indexes
|
||||
*
|
||||
*
|
||||
* @return index operations on the named collection associated with the given entity class
|
||||
*/
|
||||
IndexOperations indexOps(Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Returns the {@link ScriptOperations} that can be performed on {@link com.mongodb.DB} level.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
@@ -282,7 +283,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Returns a new {@link BulkOperations} for the given collection.
|
||||
*
|
||||
*
|
||||
* @param mode the {@link BulkMode} to use for bulk operations, must not be {@literal null}.
|
||||
* @param collectionName the name of the collection to work on, must not be {@literal null} or empty.
|
||||
* @return {@link BulkOperations} on the named collection
|
||||
@@ -291,7 +292,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Returns a new {@link BulkOperations} for the given entity type.
|
||||
*
|
||||
*
|
||||
* @param mode the {@link BulkMode} to use for bulk operations, must not be {@literal null}.
|
||||
* @param entityType the name of the entity class, must not be {@literal null}.
|
||||
* @return {@link BulkOperations} on the named collection associated of the given entity class.
|
||||
@@ -300,7 +301,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Returns a new {@link BulkOperations} for the given entity type and collection name.
|
||||
*
|
||||
*
|
||||
* @param mode the {@link BulkMode} to use for bulk operations, must not be {@literal null}.
|
||||
* @param entityClass the name of the entity class, must not be {@literal null}.
|
||||
* @param collectionName the name of the collection to work on, must not be {@literal null} or empty.
|
||||
@@ -316,7 +317,7 @@ public interface MongoOperations {
|
||||
* <p/>
|
||||
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way
|
||||
* to map objects since the test for class type is done in the client and not on the server.
|
||||
*
|
||||
*
|
||||
* @param entityClass the parameterized type of the returned list
|
||||
* @return the converted collection
|
||||
*/
|
||||
@@ -330,7 +331,7 @@ public interface MongoOperations {
|
||||
* <p/>
|
||||
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way
|
||||
* to map objects since the test for class type is done in the client and not on the server.
|
||||
*
|
||||
*
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
* @return the converted collection
|
||||
@@ -340,7 +341,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Execute a group operation over the entire collection. The group operation entity class should match the 'shape' of
|
||||
* the returned object that takes int account the initial document structure as well as any finalize functions.
|
||||
*
|
||||
*
|
||||
* @param criteria The criteria that restricts the row that are considered for grouping. If not specified all rows are
|
||||
* considered.
|
||||
* @param inputCollectionName the collection where the group operation will read from
|
||||
@@ -355,7 +356,7 @@ public interface MongoOperations {
|
||||
* Execute a group operation restricting the rows to those which match the provided Criteria. The group operation
|
||||
* entity class should match the 'shape' of the returned object that takes int account the initial document structure
|
||||
* as well as any finalize functions.
|
||||
*
|
||||
*
|
||||
* @param criteria The criteria that restricts the row that are considered for grouping. If not specified all rows are
|
||||
* considered.
|
||||
* @param inputCollectionName the collection where the group operation will read from
|
||||
@@ -369,7 +370,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Execute an aggregation operation. The raw results will be mapped to the given entity class. The name of the
|
||||
* inputCollection is derived from the inputType of the aggregation.
|
||||
*
|
||||
*
|
||||
* @param aggregation The {@link TypedAggregation} specification holding the aggregation operations, must not be
|
||||
* {@literal null}.
|
||||
* @param collectionName The name of the input collection to use for the aggreation.
|
||||
@@ -382,7 +383,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Execute an aggregation operation. The raw results will be mapped to the given entity class. The name of the
|
||||
* inputCollection is derived from the inputType of the aggregation.
|
||||
*
|
||||
*
|
||||
* @param aggregation The {@link TypedAggregation} specification holding the aggregation operations, must not be
|
||||
* {@literal null}.
|
||||
* @param outputType The parameterized type of the returned list, must not be {@literal null}.
|
||||
@@ -393,7 +394,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Execute an aggregation operation. The raw results will be mapped to the given entity class.
|
||||
*
|
||||
*
|
||||
* @param aggregation The {@link Aggregation} specification holding the aggregation operations, must not be
|
||||
* {@literal null}.
|
||||
* @param inputType the inputType where the aggregation operation will read from, must not be {@literal null} or
|
||||
@@ -406,7 +407,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Execute an aggregation operation. The raw results will be mapped to the given entity class.
|
||||
*
|
||||
*
|
||||
* @param aggregation The {@link Aggregation} specification holding the aggregation operations, must not be
|
||||
* {@literal null}.
|
||||
* @param collectionName the collection where the aggregation operation will read from, must not be {@literal null} or
|
||||
@@ -417,9 +418,84 @@ public interface MongoOperations {
|
||||
*/
|
||||
<O> AggregationResults<O> aggregate(Aggregation aggregation, String collectionName, Class<O> outputType);
|
||||
|
||||
/**
|
||||
* Execute an aggregation operation backed by a Mongo DB {@link Cursor}.
|
||||
* <p>
|
||||
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed. The raw
|
||||
* results will be mapped to the given entity class. The name of the inputCollection is derived from the inputType of
|
||||
* the aggregation.
|
||||
* <p>
|
||||
* Aggregation streaming can't be used with {@link AggregationOptions#isExplain() aggregation explain}. Enabling
|
||||
* explanation mode will throw an {@link IllegalArgumentException}.
|
||||
*
|
||||
* @param aggregation The {@link TypedAggregation} specification holding the aggregation operations, must not be
|
||||
* {@literal null}.
|
||||
* @param collectionName The name of the input collection to use for the aggreation.
|
||||
* @param outputType The parameterized type of the returned list, must not be {@literal null}.
|
||||
* @return The results of the aggregation operation.
|
||||
* @since 2.0
|
||||
*/
|
||||
<O> CloseableIterator<O> aggregateStream(TypedAggregation<?> aggregation, String collectionName, Class<O> outputType);
|
||||
|
||||
/**
|
||||
* Execute an aggregation operation backed by a Mongo DB {@link Cursor}.
|
||||
* <p/>
|
||||
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed. The raw
|
||||
* results will be mapped to the given entity class and are returned as stream. The name of the inputCollection is
|
||||
* derived from the inputType of the aggregation.
|
||||
* <p/>
|
||||
* Aggregation streaming can't be used with {@link AggregationOptions#isExplain() aggregation explain}. Enabling
|
||||
* explanation mode will throw an {@link IllegalArgumentException}.
|
||||
*
|
||||
* @param aggregation The {@link TypedAggregation} specification holding the aggregation operations, must not be
|
||||
* {@literal null}.
|
||||
* @param outputType The parameterized type of the returned list, must not be {@literal null}.
|
||||
* @return The results of the aggregation operation.
|
||||
* @since 2.0
|
||||
*/
|
||||
<O> CloseableIterator<O> aggregateStream(TypedAggregation<?> aggregation, Class<O> outputType);
|
||||
|
||||
/**
|
||||
* Execute an aggregation operation backed by a Mongo DB {@link Cursor}.
|
||||
* <p/>
|
||||
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed. The raw
|
||||
* results will be mapped to the given entity class.
|
||||
* <p/>
|
||||
* Aggregation streaming can't be used with {@link AggregationOptions#isExplain() aggregation explain}. Enabling
|
||||
* explanation mode will throw an {@link IllegalArgumentException}.
|
||||
*
|
||||
* @param aggregation The {@link Aggregation} specification holding the aggregation operations, must not be
|
||||
* {@literal null}.
|
||||
* @param inputType the inputType where the aggregation operation will read from, must not be {@literal null} or
|
||||
* empty.
|
||||
* @param outputType The parameterized type of the returned list, must not be {@literal null}.
|
||||
* @return The results of the aggregation operation.
|
||||
* @since 2.0
|
||||
*/
|
||||
<O> CloseableIterator<O> aggregateStream(Aggregation aggregation, Class<?> inputType, Class<O> outputType);
|
||||
|
||||
/**
|
||||
* Execute an aggregation operation backed by a Mongo DB {@link Cursor}.
|
||||
* <p/>
|
||||
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link Cursor} that needs to be closed. The raw
|
||||
* results will be mapped to the given entity class.
|
||||
* <p/>
|
||||
* Aggregation streaming can't be used with {@link AggregationOptions#isExplain() aggregation explain}. Enabling
|
||||
* explanation mode will throw an {@link IllegalArgumentException}.
|
||||
*
|
||||
* @param aggregation The {@link Aggregation} specification holding the aggregation operations, must not be
|
||||
* {@literal null}.
|
||||
* @param collectionName the collection where the aggregation operation will read from, must not be {@literal null} or
|
||||
* empty.
|
||||
* @param outputType The parameterized type of the returned list, must not be {@literal null}.
|
||||
* @return The results of the aggregation operation.
|
||||
* @since 2.0
|
||||
*/
|
||||
<O> CloseableIterator<O> aggregateStream(Aggregation aggregation, String collectionName, Class<O> outputType);
|
||||
|
||||
/**
|
||||
* Execute a map-reduce operation. The map-reduce operation will be formed with an output type of INLINE
|
||||
*
|
||||
*
|
||||
* @param inputCollectionName the collection where the map-reduce will read from
|
||||
* @param mapFunction The JavaScript map function
|
||||
* @param reduceFunction The JavaScript reduce function
|
||||
@@ -432,7 +508,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Execute a map-reduce operation that takes additional map-reduce options.
|
||||
*
|
||||
*
|
||||
* @param inputCollectionName the collection where the map-reduce will read from
|
||||
* @param mapFunction The JavaScript map function
|
||||
* @param reduceFunction The JavaScript reduce function
|
||||
@@ -446,7 +522,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Execute a map-reduce operation that takes a query. The map-reduce operation will be formed with an output type of
|
||||
* INLINE
|
||||
*
|
||||
*
|
||||
* @param query The query to use to select the data for the map phase
|
||||
* @param inputCollectionName the collection where the map-reduce will read from
|
||||
* @param mapFunction The JavaScript map function
|
||||
@@ -460,7 +536,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Execute a map-reduce operation that takes a query and additional map-reduce options
|
||||
*
|
||||
*
|
||||
* @param query The query to use to select the data for the map phase
|
||||
* @param inputCollectionName the collection where the map-reduce will read from
|
||||
* @param mapFunction The JavaScript map function
|
||||
@@ -477,7 +553,7 @@ public interface MongoOperations {
|
||||
* information to determine the collection the query is ran against. Note, that MongoDB limits the number of results
|
||||
* by default. Make sure to add an explicit limit to the {@link NearQuery} if you expect a particular number of
|
||||
* results.
|
||||
*
|
||||
*
|
||||
* @param near must not be {@literal null}.
|
||||
* @param entityClass must not be {@literal null}.
|
||||
* @return
|
||||
@@ -488,7 +564,7 @@ public interface MongoOperations {
|
||||
* Returns {@link GeoResults} for all entities matching the given {@link NearQuery}. Note, that MongoDB limits the
|
||||
* number of results by default. Make sure to add an explicit limit to the {@link NearQuery} if you expect a
|
||||
* particular number of results.
|
||||
*
|
||||
*
|
||||
* @param near must not be {@literal null}.
|
||||
* @param entityClass must not be {@literal null}.
|
||||
* @param collectionName the collection to trigger the query against. If no collection name is given the entity class
|
||||
@@ -506,7 +582,7 @@ public interface MongoOperations {
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
*
|
||||
*
|
||||
* @param query the query class that specifies the criteria used to find a record and also an optional fields
|
||||
* specification
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
@@ -523,7 +599,7 @@ public interface MongoOperations {
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
*
|
||||
*
|
||||
* @param query the query class that specifies the criteria used to find a record and also an optional fields
|
||||
* specification
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
@@ -534,7 +610,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Determine result of given {@link Query} contains at least one element.
|
||||
*
|
||||
*
|
||||
* @param query the {@link Query} class that specifies the criteria used to find a record.
|
||||
* @param collectionName name of the collection to check for objects.
|
||||
* @return
|
||||
@@ -543,7 +619,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Determine result of given {@link Query} contains at least one element.
|
||||
*
|
||||
*
|
||||
* @param query the {@link Query} class that specifies the criteria used to find a record.
|
||||
* @param entityClass the parameterized type.
|
||||
* @return
|
||||
@@ -552,7 +628,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Determine result of given {@link Query} contains at least one element.
|
||||
*
|
||||
*
|
||||
* @param query the {@link Query} class that specifies the criteria used to find a record.
|
||||
* @param entityClass the parameterized type.
|
||||
* @param collectionName name of the collection to check for objects.
|
||||
@@ -568,7 +644,7 @@ public interface MongoOperations {
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
*
|
||||
*
|
||||
* @param query the query class that specifies the criteria used to find a record and also an optional fields
|
||||
* specification
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
@@ -584,7 +660,7 @@ public interface MongoOperations {
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
*
|
||||
*
|
||||
* @param query the query class that specifies the criteria used to find a record and also an optional fields
|
||||
* specification
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
@@ -596,7 +672,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Returns a document with the given id mapped onto the given class. The collection the query is ran against will be
|
||||
* derived from the given target class as well.
|
||||
*
|
||||
*
|
||||
* @param <T>
|
||||
* @param id the id of the document to return.
|
||||
* @param entityClass the type the document shall be converted into.
|
||||
@@ -606,7 +682,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Returns the document with the given id from the given collection mapped onto the given target class.
|
||||
*
|
||||
*
|
||||
* @param id the id of the document to return
|
||||
* @param entityClass the type to convert the document to
|
||||
* @param collectionName the collection to query for the document
|
||||
@@ -616,9 +692,9 @@ public interface MongoOperations {
|
||||
<T> T findById(Object id, Class<T> entityClass, String collectionName);
|
||||
|
||||
/**
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify
|
||||
* <a/> to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
|
||||
*
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
|
||||
*
|
||||
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||
* fields specification.
|
||||
* @param update the {@link Update} to apply on matching documents.
|
||||
@@ -628,9 +704,9 @@ public interface MongoOperations {
|
||||
<T> T findAndModify(Query query, Update update, Class<T> entityClass);
|
||||
|
||||
/**
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify
|
||||
* <a/> to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
|
||||
*
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
|
||||
*
|
||||
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||
* fields specification.
|
||||
* @param update the {@link Update} to apply on matching documents.
|
||||
@@ -641,10 +717,10 @@ public interface MongoOperations {
|
||||
<T> T findAndModify(Query query, Update update, Class<T> entityClass, String collectionName);
|
||||
|
||||
/**
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify
|
||||
* <a/> to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
|
||||
* {@link FindAndModifyOptions} into account.
|
||||
*
|
||||
*
|
||||
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||
* fields specification.
|
||||
* @param update the {@link Update} to apply on matching documents.
|
||||
@@ -655,10 +731,10 @@ public interface MongoOperations {
|
||||
<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);
|
||||
|
||||
/**
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify
|
||||
* <a/> to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
|
||||
* {@link FindAndModifyOptions} into account.
|
||||
*
|
||||
*
|
||||
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||
* fields specification.
|
||||
* @param update the {@link Update} to apply on matching documents.
|
||||
@@ -679,7 +755,7 @@ public interface MongoOperations {
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
*
|
||||
*
|
||||
* @param query the query class that specifies the criteria used to find a record and also an optional fields
|
||||
* specification
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
@@ -696,7 +772,7 @@ public interface MongoOperations {
|
||||
* <p/>
|
||||
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more
|
||||
* feature rich {@link Query}.
|
||||
*
|
||||
*
|
||||
* @param query the query class that specifies the criteria used to find a record and also an optional fields
|
||||
* specification
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
@@ -707,7 +783,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Returns the number of documents for the given {@link Query} by querying the collection of the given entity class.
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* @param entityClass must not be {@literal null}.
|
||||
* @return
|
||||
@@ -718,7 +794,7 @@ public interface MongoOperations {
|
||||
* Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query}
|
||||
* must solely consist of document field references as we lack type information to map potential property references
|
||||
* onto document fields. TO make sure the query gets mapped, use {@link #count(Query, Class, String)}.
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* @param collectionName must not be {@literal null} or empty.
|
||||
* @return
|
||||
@@ -729,7 +805,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Returns the number of documents for the given {@link Query} by querying the given collection using the given entity
|
||||
* class to map the given {@link Query}.
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* @param entityClass must not be {@literal null}.
|
||||
* @param collectionName must not be {@literal null} or empty.
|
||||
@@ -750,7 +826,7 @@ public interface MongoOperations {
|
||||
* <p/>
|
||||
* <p/>
|
||||
* Insert is used to initially store the object into the database. To update an existing object use the save method.
|
||||
*
|
||||
*
|
||||
* @param objectToSave the object to store in the collection.
|
||||
*/
|
||||
void insert(Object objectToSave);
|
||||
@@ -762,7 +838,7 @@ public interface MongoOperations {
|
||||
* configured otherwise, an instance of MappingMongoConverter will be used.
|
||||
* <p/>
|
||||
* Insert is used to initially store the object into the database. To update an existing object use the save method.
|
||||
*
|
||||
*
|
||||
* @param objectToSave the object to store in the collection
|
||||
* @param collectionName name of the collection to store the object in
|
||||
*/
|
||||
@@ -770,7 +846,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Insert a Collection of objects into a collection in a single batch write to the database.
|
||||
*
|
||||
*
|
||||
* @param batchToSave the list of objects to save.
|
||||
* @param entityClass class that determines the collection to use
|
||||
*/
|
||||
@@ -778,7 +854,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Insert a list of objects into the specified collection in a single batch write to the database.
|
||||
*
|
||||
*
|
||||
* @param batchToSave the list of objects to save.
|
||||
* @param collectionName name of the collection to store the object in
|
||||
*/
|
||||
@@ -787,7 +863,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Insert a mixed Collection of objects into a database collection determining the collection name to use based on the
|
||||
* class.
|
||||
*
|
||||
*
|
||||
* @param collectionToSave the list of objects to save.
|
||||
*/
|
||||
void insertAll(Collection<? extends Object> objectsToSave);
|
||||
@@ -804,7 +880,7 @@ public interface MongoOperations {
|
||||
* property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See
|
||||
* <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert" >
|
||||
* Spring's Type Conversion"</a> for more details.
|
||||
*
|
||||
*
|
||||
* @param objectToSave the object to store in the collection
|
||||
*/
|
||||
void save(Object objectToSave);
|
||||
@@ -821,7 +897,7 @@ public interface MongoOperations {
|
||||
* property type will be handled by Spring's BeanWrapper class that leverages Type Cobnversion API. See <a
|
||||
* http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert">Spring's
|
||||
* Type Conversion"</a> for more details.
|
||||
*
|
||||
*
|
||||
* @param objectToSave the object to store in the collection
|
||||
* @param collectionName name of the collection to store the object in
|
||||
*/
|
||||
@@ -830,7 +906,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
|
||||
* combining the query document and the update document.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to select a record to be upserted
|
||||
* @param update the update document that contains the updated object or $ operators to manipulate the existing object
|
||||
* @param entityClass class that determines the collection to use
|
||||
@@ -841,7 +917,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
|
||||
* combining the query document and the update document.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to select a record to be updated
|
||||
* @param update the update document that contains the updated object or $ operators to manipulate the existing
|
||||
* object.
|
||||
@@ -853,7 +929,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Performs an upsert. If no document is found that matches the query, a new document is created and inserted by
|
||||
* combining the query document and the update document.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to select a record to be upserted
|
||||
* @param update the update document that contains the updated object or $ operators to manipulate the existing object
|
||||
* @param entityClass class of the pojo to be operated on
|
||||
@@ -865,7 +941,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Updates the first object that is found in the collection of the entity class that matches the query document with
|
||||
* the provided update document.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to select a record to be updated
|
||||
* @param update the update document that contains the updated object or $ operators to manipulate the existing
|
||||
* object.
|
||||
@@ -877,7 +953,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Updates the first object that is found in the specified collection that matches the query document criteria with
|
||||
* the provided updated document.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to select a record to be updated
|
||||
* @param update the update document that contains the updated object or $ operators to manipulate the existing
|
||||
* object.
|
||||
@@ -889,7 +965,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Updates the first object that is found in the specified collection that matches the query document criteria with
|
||||
* the provided updated document.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to select a record to be updated
|
||||
* @param update the update document that contains the updated object or $ operators to manipulate the existing
|
||||
* object.
|
||||
@@ -902,7 +978,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
|
||||
* with the provided updated document.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to select a record to be updated
|
||||
* @param update the update document that contains the updated object or $ operators to manipulate the existing
|
||||
* object.
|
||||
@@ -914,7 +990,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Updates all objects that are found in the specified collection that matches the query document criteria with the
|
||||
* provided updated document.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to select a record to be updated
|
||||
* @param update the update document that contains the updated object or $ operators to manipulate the existing
|
||||
* object.
|
||||
@@ -926,7 +1002,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Updates all objects that are found in the collection for the entity class that matches the query document criteria
|
||||
* with the provided updated document.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to select a record to be updated
|
||||
* @param update the update document that contains the updated object or $ operators to manipulate the existing
|
||||
* object.
|
||||
@@ -938,14 +1014,14 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Remove the given object from the collection by id.
|
||||
*
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
DeleteResult remove(Object object);
|
||||
|
||||
/**
|
||||
* Removes the given object from the given collection.
|
||||
*
|
||||
*
|
||||
* @param object
|
||||
* @param collection must not be {@literal null} or empty.
|
||||
*/
|
||||
@@ -954,7 +1030,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Remove all documents that match the provided query document criteria from the the collection used to store the
|
||||
* entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the query.
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* @param entityClass
|
||||
*/
|
||||
@@ -963,7 +1039,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Remove all documents that match the provided query document criteria from the the collection used to store the
|
||||
* entityClass. The Class parameter is also used to help convert the Id of the object if it is present in the query.
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* @param entityClass
|
||||
* @param collectionName
|
||||
@@ -973,7 +1049,7 @@ public interface MongoOperations {
|
||||
/**
|
||||
* Remove all documents from the specified collection that match the provided query document criteria. There is no
|
||||
* conversion/mapping done for any criteria using the id field.
|
||||
*
|
||||
*
|
||||
* @param query the query document that specifies the criteria used to remove a record
|
||||
* @param collectionName name of the collection where the objects will removed
|
||||
*/
|
||||
@@ -981,7 +1057,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Returns and removes all documents form the specified collection that match the provided query.
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* @param collectionName
|
||||
* @return
|
||||
@@ -991,7 +1067,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Returns and removes all documents matching the given query form the collection used to store the entityClass.
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* @param entityClass
|
||||
* @return
|
||||
@@ -1003,7 +1079,7 @@ public interface MongoOperations {
|
||||
* Returns and removes all documents that match the provided query document criteria from the the collection used to
|
||||
* store the entityClass. The Class parameter is also used to help convert the Id of the object if it is present in
|
||||
* the query.
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* @param entityClass
|
||||
* @param collectionName
|
||||
@@ -1014,7 +1090,7 @@ public interface MongoOperations {
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link MongoConverter}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
MongoConverter getConverter();
|
||||
|
||||
@@ -1,255 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
|
||||
import com.mongodb.MongoOptions;
|
||||
|
||||
/**
|
||||
* A factory bean for construction of a {@link MongoOptions} instance. In case used with MongoDB Java driver version 3
|
||||
* porperties not suppprted by the driver will be ignored.
|
||||
*
|
||||
* @author Graeme Rocher
|
||||
* @author Mark Pollack
|
||||
* @author Mike Saavedra
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @deprecated since 1.7. Please use {@link MongoClientOptionsFactoryBean} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class MongoOptionsFactoryBean extends AbstractFactoryBean<MongoOptions> {
|
||||
|
||||
private static final MongoOptions DEFAULT_MONGO_OPTIONS = new MongoOptions();
|
||||
|
||||
private int connectionsPerHost = DEFAULT_MONGO_OPTIONS.getConnectionsPerHost();
|
||||
private int threadsAllowedToBlockForConnectionMultiplier = DEFAULT_MONGO_OPTIONS
|
||||
.getThreadsAllowedToBlockForConnectionMultiplier();
|
||||
private int maxWaitTime = DEFAULT_MONGO_OPTIONS.getMaxWaitTime();
|
||||
private int connectTimeout = DEFAULT_MONGO_OPTIONS.getConnectTimeout();
|
||||
private int socketTimeout = DEFAULT_MONGO_OPTIONS.getSocketTimeout();
|
||||
private boolean socketKeepAlive = DEFAULT_MONGO_OPTIONS.isSocketKeepAlive();
|
||||
private int writeNumber = DEFAULT_MONGO_OPTIONS.getW();
|
||||
private int writeTimeout = DEFAULT_MONGO_OPTIONS.getWtimeout();
|
||||
private boolean writeFsync = DEFAULT_MONGO_OPTIONS.isFsync();
|
||||
|
||||
private boolean autoConnectRetry = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
|
||||
.getAutoConnectRetry(DEFAULT_MONGO_OPTIONS) : false;
|
||||
private long maxAutoConnectRetryTime = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
|
||||
.getMaxAutoConnectRetryTime(DEFAULT_MONGO_OPTIONS) : -1;
|
||||
private boolean slaveOk = !MongoClientVersion.isMongo3Driver() ? ReflectiveMongoOptionsInvoker
|
||||
.getSlaveOk(DEFAULT_MONGO_OPTIONS) : false;
|
||||
|
||||
private boolean ssl;
|
||||
private SSLSocketFactory sslSocketFactory;
|
||||
|
||||
/**
|
||||
* Configures the maximum number of connections allowed per host until we will block.
|
||||
*
|
||||
* @param connectionsPerHost
|
||||
*/
|
||||
public void setConnectionsPerHost(int connectionsPerHost) {
|
||||
this.connectionsPerHost = connectionsPerHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* A multiplier for connectionsPerHost for # of threads that can block a connection. If connectionsPerHost is 10, and
|
||||
* threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block. If more threads try to block an
|
||||
* exception will be thrown.
|
||||
*
|
||||
* @param threadsAllowedToBlockForConnectionMultiplier
|
||||
*/
|
||||
public void setThreadsAllowedToBlockForConnectionMultiplier(int threadsAllowedToBlockForConnectionMultiplier) {
|
||||
this.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Max wait time of a blocking thread for a connection.
|
||||
*
|
||||
* @param maxWaitTime
|
||||
*/
|
||||
public void setMaxWaitTime(int maxWaitTime) {
|
||||
this.maxWaitTime = maxWaitTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the connect timeout in milliseconds. Defaults to 0 (infinite time).
|
||||
*
|
||||
* @param connectTimeout
|
||||
*/
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the socket timeout. Defaults to 0 (infinite time).
|
||||
*
|
||||
* @param socketTimeout
|
||||
*/
|
||||
public void setSocketTimeout(int socketTimeout) {
|
||||
this.socketTimeout = socketTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether or not to have socket keep alive turned on (SO_KEEPALIVE). Defaults to {@literal false}.
|
||||
*
|
||||
* @param socketKeepAlive
|
||||
*/
|
||||
public void setSocketKeepAlive(boolean socketKeepAlive) {
|
||||
this.socketKeepAlive = socketKeepAlive;
|
||||
}
|
||||
|
||||
/**
|
||||
* This specifies the number of servers to wait for on the write operation, and exception raising behavior. The 'w'
|
||||
* option to the getlasterror command. Defaults to 0.
|
||||
* <ul>
|
||||
* <li>-1 = don't even report network errors</li>
|
||||
* <li>0 = default, don't call getLastError by default</li>
|
||||
* <li>1 = basic, call getLastError, but don't wait for slaves</li>
|
||||
* <li>2 += wait for slaves</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param writeNumber the number of servers to wait for on the write operation, and exception raising behavior.
|
||||
*/
|
||||
public void setWriteNumber(int writeNumber) {
|
||||
this.writeNumber = writeNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the timeout for write operations in milliseconds. This defaults to {@literal 0} (indefinite).
|
||||
*
|
||||
* @param writeTimeout
|
||||
*/
|
||||
public void setWriteTimeout(int writeTimeout) {
|
||||
this.writeTimeout = writeTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether or not to fsync. The 'fsync' option to the getlasterror command. Defaults to {@literal false}.
|
||||
*
|
||||
* @param writeFsync to fsync on <code>write (true)<code>, otherwise {@literal false}.
|
||||
*/
|
||||
public void setWriteFsync(boolean writeFsync) {
|
||||
this.writeFsync = writeFsync;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether or not the system retries automatically on a failed connect. This defaults to {@literal false}.
|
||||
*
|
||||
* @deprecated since 1.7.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setAutoConnectRetry(boolean autoConnectRetry) {
|
||||
this.autoConnectRetry = autoConnectRetry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the maximum amount of time in millisecons to spend retrying to open connection to the same server. This
|
||||
* defaults to {@literal 0}, which means to use the default {@literal 15s} if {@link #autoConnectRetry} is on.
|
||||
*
|
||||
* @param maxAutoConnectRetryTime the maxAutoConnectRetryTime to set
|
||||
* @deprecated since 1.7
|
||||
*/
|
||||
@Deprecated
|
||||
public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
|
||||
this.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if the driver is allowed to read from secondaries or slaves. Defaults to {@literal false}.
|
||||
*
|
||||
* @param slaveOk true if the driver should read from secondaries or slaves.
|
||||
* @deprecated since 1.7
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSlaveOk(boolean slaveOk) {
|
||||
this.slaveOk = slaveOk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if the driver should use an SSL connection to Mongo. This defaults to {@literal false}. By default
|
||||
* {@link SSLSocketFactory#getDefault()} will be used. See {@link #setSslSocketFactory(SSLSocketFactory)} if you want
|
||||
* to configure a custom factory.
|
||||
*
|
||||
* @param ssl true if the driver should use an SSL connection.
|
||||
* @see #setSslSocketFactory(SSLSocketFactory)
|
||||
*/
|
||||
public void setSsl(boolean ssl) {
|
||||
this.ssl = ssl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link SSLSocketFactory} to use for creating SSL connections to Mongo. Defaults to
|
||||
* {@link SSLSocketFactory#getDefault()}. Implicitly activates {@link #setSsl(boolean)} if a non-{@literal null} value
|
||||
* is given.
|
||||
*
|
||||
* @param sslSocketFactory the sslSocketFactory to use.
|
||||
* @see #setSsl(boolean)
|
||||
*/
|
||||
public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
|
||||
|
||||
setSsl(sslSocketFactory != null);
|
||||
this.sslSocketFactory = sslSocketFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
|
||||
*/
|
||||
@Override
|
||||
protected MongoOptions createInstance() throws Exception {
|
||||
|
||||
if (MongoClientVersion.isMongo3Driver()) {
|
||||
throw new IllegalArgumentException(
|
||||
String
|
||||
.format("Usage of 'mongo-options' is no longer supported for MongoDB Java driver version 3 and above. Please use 'mongo-client-options' and refer to chapter 'MongoDB 3.0 Support' for details."));
|
||||
}
|
||||
|
||||
MongoOptions options = new MongoOptions();
|
||||
|
||||
options.setConnectionsPerHost(connectionsPerHost);
|
||||
options.setThreadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier);
|
||||
options.setMaxWaitTime(maxWaitTime);
|
||||
options.setConnectTimeout(connectTimeout);
|
||||
options.setSocketTimeout(socketTimeout);
|
||||
options.setSocketKeepAlive(socketKeepAlive);
|
||||
|
||||
options.setW(writeNumber);
|
||||
options.setWtimeout(writeTimeout);
|
||||
options.setFsync(writeFsync);
|
||||
|
||||
if (ssl) {
|
||||
options.setSocketFactory(sslSocketFactory != null ? sslSocketFactory : SSLSocketFactory.getDefault());
|
||||
}
|
||||
|
||||
ReflectiveMongoOptionsInvoker.setAutoConnectRetry(options, autoConnectRetry);
|
||||
ReflectiveMongoOptionsInvoker.setMaxAutoConnectRetryTime(options, maxAutoConnectRetryTime);
|
||||
ReflectiveMongoOptionsInvoker.setSlaveOk(options, slaveOk);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
public Class<?> getObjectType() {
|
||||
return MongoOptions.class;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,10 +46,10 @@ import reactor.core.publisher.Mono;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 2.0
|
||||
* @see Flux
|
||||
* @see Mono
|
||||
* @see http://projectreactor.io/docs/
|
||||
* @since 2.0
|
||||
* @see <a href="http://projectreactor.io/docs/">Project Reactor</a>
|
||||
*/
|
||||
public interface ReactiveMongoOperations {
|
||||
|
||||
@@ -393,7 +393,7 @@ public interface ReactiveMongoOperations {
|
||||
<T> Flux<GeoResult<T>> geoNear(NearQuery near, Class<T> entityClass, String collectionName);
|
||||
|
||||
/**
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* Triggers <a href="https://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
|
||||
*
|
||||
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||
@@ -405,7 +405,7 @@ public interface ReactiveMongoOperations {
|
||||
<T> Mono<T> findAndModify(Query query, Update update, Class<T> entityClass);
|
||||
|
||||
/**
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* Triggers <a href="https://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query}.
|
||||
*
|
||||
* @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
|
||||
@@ -418,7 +418,7 @@ public interface ReactiveMongoOperations {
|
||||
<T> Mono<T> findAndModify(Query query, Update update, Class<T> entityClass, String collectionName);
|
||||
|
||||
/**
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* Triggers <a href="https://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
|
||||
* {@link FindAndModifyOptions} into account.
|
||||
*
|
||||
@@ -432,7 +432,7 @@ public interface ReactiveMongoOperations {
|
||||
<T> Mono<T> findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);
|
||||
|
||||
/**
|
||||
* Triggers <a href="http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* Triggers <a href="https://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify <a/>
|
||||
* to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
|
||||
* {@link FindAndModifyOptions} into account.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,10 @@ package org.springframework.data.mongodb.core;
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.*;
|
||||
import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -27,6 +31,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -54,6 +59,7 @@ import org.springframework.data.convert.EntityReader;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResult;
|
||||
import org.springframework.data.geo.Metric;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
@@ -87,6 +93,7 @@ import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
import org.springframework.data.util.Optionals;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -115,10 +122,6 @@ import com.mongodb.reactivestreams.client.MongoDatabase;
|
||||
import com.mongodb.reactivestreams.client.Success;
|
||||
import com.mongodb.util.JSONParseException;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
/**
|
||||
* Primary implementation of {@link ReactiveMongoOperations}. It simplifies the use of Reactive MongoDB usage and helps
|
||||
* to avoid common errors. It executes core MongoDB workflow, leaving application code to provide {@link Document} and
|
||||
@@ -335,11 +338,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#executeCommand(org.bson.Document)
|
||||
*/
|
||||
public Mono<Document> executeCommand(final Document command) {
|
||||
|
||||
Assert.notNull(command, "Command must not be null!");
|
||||
|
||||
return createFlux(db -> readPreference != null ? db.runCommand(command, readPreference) : db.runCommand(command))
|
||||
.next();
|
||||
return executeCommand(command, null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -349,8 +348,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
|
||||
Assert.notNull(command, "Command must not be null!");
|
||||
|
||||
return createFlux(db -> readPreference != null ? db.runCommand(command, readPreference) : db.runCommand(command))
|
||||
.next();
|
||||
return createFlux(db -> readPreference != null ? db.runCommand(command, readPreference, Document.class)
|
||||
: db.runCommand(command, Document.class)).next();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -373,7 +372,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#execute(java.lang.String, org.springframework.data.mongodb.core.ReactiveCollectionCallback)
|
||||
*/
|
||||
public <T> Flux<T> execute(String collectionName, ReactiveCollectionCallback<T> callback) {
|
||||
Assert.notNull(callback);
|
||||
|
||||
Assert.notNull(callback, "ReactiveCollectionCallback must not be null!");
|
||||
return createFlux(collectionName, callback);
|
||||
}
|
||||
|
||||
@@ -386,9 +386,9 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public <T> Flux<T> createFlux(ReactiveDatabaseCallback<T> callback) {
|
||||
|
||||
Assert.notNull(callback);
|
||||
Assert.notNull(callback, "ReactiveDatabaseCallback must not be null!");
|
||||
|
||||
return Flux.defer(() -> callback.doInDB(getMongoDatabase())).onErrorResumeWith(translateFluxException());
|
||||
return Flux.defer(() -> callback.doInDB(getMongoDatabase())).onErrorMap(translateException());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,9 +400,9 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public <T> Mono<T> createMono(final ReactiveDatabaseCallback<T> callback) {
|
||||
|
||||
Assert.notNull(callback);
|
||||
Assert.notNull(callback, "ReactiveDatabaseCallback must not be null!");
|
||||
|
||||
return Mono.defer(() -> Mono.from(callback.doInDB(getMongoDatabase()))).otherwise(translateMonoException());
|
||||
return Mono.defer(() -> Mono.from(callback.doInDB(getMongoDatabase()))).onErrorMap(translateException());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -414,13 +414,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public <T> Flux<T> createFlux(String collectionName, ReactiveCollectionCallback<T> callback) {
|
||||
|
||||
Assert.hasText(collectionName);
|
||||
Assert.notNull(callback);
|
||||
Assert.hasText(collectionName, "Collection name must not be null or empty!");
|
||||
Assert.notNull(callback, "ReactiveDatabaseCallback must not be null!");
|
||||
|
||||
Mono<MongoCollection<Document>> collectionPublisher = Mono
|
||||
.fromCallable(() -> getAndPrepareCollection(getMongoDatabase(), collectionName));
|
||||
|
||||
return collectionPublisher.flatMap(callback::doInCollection).onErrorResumeWith(translateFluxException());
|
||||
return collectionPublisher.flatMapMany(callback::doInCollection).onErrorMap(translateException());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -433,14 +433,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public <T> Mono<T> createMono(String collectionName, ReactiveCollectionCallback<T> callback) {
|
||||
|
||||
Assert.hasText(collectionName);
|
||||
Assert.notNull(callback);
|
||||
Assert.hasText(collectionName, "Collection name must not be null or empty!");
|
||||
Assert.notNull(callback, "ReactiveCollectionCallback must not be null!");
|
||||
|
||||
Mono<MongoCollection<Document>> collectionPublisher = Mono
|
||||
.fromCallable(() -> getAndPrepareCollection(getMongoDatabase(), collectionName));
|
||||
|
||||
return collectionPublisher.then(collection -> Mono.from(callback.doInCollection(collection)))
|
||||
.otherwise(translateMonoException());
|
||||
return collectionPublisher.flatMap(collection -> Mono.from(callback.doInCollection(collection)))
|
||||
.onErrorMap(translateException());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -539,8 +539,9 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public <T> Mono<T> findOne(Query query, Class<T> entityClass, String collectionName) {
|
||||
|
||||
if (query.getSortObject() == null) {
|
||||
return doFindOne(collectionName, query.getQueryObject(), query.getFieldsObject(), entityClass);
|
||||
if (ObjectUtils.isEmpty(query.getSortObject())) {
|
||||
return doFindOne(collectionName, query.getQueryObject(), query.getFieldsObject(), entityClass,
|
||||
query.getCollation().orElse(null));
|
||||
}
|
||||
|
||||
query.limit(1);
|
||||
@@ -573,7 +574,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
return createFlux(collectionName, collection -> {
|
||||
|
||||
Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(), getPersistentEntity(entityClass));
|
||||
return collection.find(mappedQuery).limit(1);
|
||||
FindPublisher<Document> findPublisher = collection.find(mappedQuery).projection(new Document("_id", 1));
|
||||
|
||||
findPublisher = query.getCollation().map(Collation::toMongoCollation).map(findPublisher::collation)
|
||||
.orElse(findPublisher);
|
||||
|
||||
return findPublisher.limit(1);
|
||||
}).hasElements();
|
||||
}
|
||||
|
||||
@@ -609,12 +615,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public <T> Mono<T> findById(Object id, Class<T> entityClass, String collectionName) {
|
||||
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityClass);
|
||||
MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty();
|
||||
Optional<? extends MongoPersistentEntity<?>> persistentEntity = mappingContext.getPersistentEntity(entityClass);
|
||||
MongoPersistentProperty idProperty = persistentEntity.flatMap(PersistentEntity::getIdProperty).orElse(null);
|
||||
|
||||
String idKey = idProperty == null ? ID_FIELD : idProperty.getName();
|
||||
|
||||
return doFindOne(collectionName, new Document(idKey, id), null, entityClass);
|
||||
return doFindOne(collectionName, new Document(idKey, id), null, entityClass, null);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -663,19 +669,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
GeoNearResultDbObjectCallback<T> callback = new GeoNearResultDbObjectCallback<T>(
|
||||
new ReadDocumentCallback<T>(mongoConverter, entityClass, collectionName), near.getMetric());
|
||||
|
||||
return executeCommand(command, this.readPreference).flatMap(document -> {
|
||||
return executeCommand(command, this.readPreference).flatMapMany(document -> {
|
||||
|
||||
List<Document> l = document.get("results", List.class);
|
||||
if (l == null) {
|
||||
return Flux.empty();
|
||||
}
|
||||
return Flux.fromIterable(l);
|
||||
}).skip(near.getSkip() != null ? near.getSkip() : 0).map(new Function<Document, GeoResult<T>>() {
|
||||
@Override
|
||||
public GeoResult<T> apply(Document object) {
|
||||
return callback.doWith(object);
|
||||
}
|
||||
});
|
||||
}).skip(near.getSkip() != null ? near.getSkip() : 0).map(callback::doWith);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -705,8 +706,18 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public <T> Mono<T> findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass,
|
||||
String collectionName) {
|
||||
|
||||
FindAndModifyOptions optionsToUse = FindAndModifyOptions.of(options);
|
||||
|
||||
Optionals.ifAllPresent(query.getCollation(), optionsToUse.getCollation(), (l, r) -> {
|
||||
throw new IllegalArgumentException(
|
||||
"Both Query and FindAndModifyOptions define a collation. Please provide the collation only via one of the two.");
|
||||
});
|
||||
|
||||
query.getCollation().ifPresent(optionsToUse::collation);
|
||||
|
||||
return doFindAndModify(collectionName, query.getQueryObject(), query.getFieldsObject(),
|
||||
getMappedSortObject(query, entityClass), entityClass, update, options);
|
||||
getMappedSortObject(query, entityClass), entityClass, update, optionsToUse);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -722,14 +733,16 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
public <T> Mono<T> findAndRemove(Query query, Class<T> entityClass, String collectionName) {
|
||||
|
||||
return doFindAndRemove(collectionName, query.getQueryObject(), query.getFieldsObject(),
|
||||
getMappedSortObject(query, entityClass), entityClass);
|
||||
getMappedSortObject(query, entityClass), query.getCollation().orElse(null), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.ReactiveMongoOperations#count(org.springframework.data.mongodb.core.query.Query, java.lang.Class)
|
||||
*/
|
||||
public Mono<Long> count(Query query, Class<?> entityClass) {
|
||||
Assert.notNull(entityClass);
|
||||
|
||||
Assert.notNull(entityClass, "Entity class must not be null!");
|
||||
|
||||
return count(query, entityClass, determineCollectionName(entityClass));
|
||||
}
|
||||
|
||||
@@ -745,13 +758,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public Mono<Long> count(final Query query, final Class<?> entityClass, String collectionName) {
|
||||
|
||||
Assert.hasText(collectionName);
|
||||
Assert.hasText(collectionName, "Collection name must not be null or empty!");
|
||||
|
||||
return createMono(collectionName, collection -> {
|
||||
|
||||
final Document Document = query == null ? null
|
||||
: queryMapper.getMappedObject(query.getQueryObject(),
|
||||
entityClass == null ? null : mappingContext.getPersistentEntity(entityClass));
|
||||
entityClass == null ? Optional.empty() : mappingContext.getPersistentEntity(entityClass));
|
||||
|
||||
return collection.count(Document);
|
||||
});
|
||||
@@ -762,7 +775,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
@Override
|
||||
public <T> Mono<T> insert(Mono<? extends T> objectToSave) {
|
||||
return objectToSave.then(this::insert);
|
||||
return objectToSave.flatMap(this::insert);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -812,7 +825,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
|
||||
maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc, collectionName));
|
||||
|
||||
Mono<T> afterInsert = insertDBObject(collectionName, dbDoc, objectToSave.getClass()).then(id -> {
|
||||
Mono<T> afterInsert = insertDBObject(collectionName, dbDoc, objectToSave.getClass()).flatMap(id -> {
|
||||
populateIdIfNecessary(objectToSave, id);
|
||||
maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc, collectionName));
|
||||
return Mono.just(objectToSave);
|
||||
@@ -856,11 +869,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
final Map<String, List<T>> elementsByCollection = new HashMap<String, List<T>>();
|
||||
|
||||
listToSave.forEach(element -> {
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(element.getClass());
|
||||
|
||||
if (entity == null) {
|
||||
throw new InvalidDataAccessApiUsageException("No PersistentEntity information found for " + element.getClass());
|
||||
}
|
||||
MongoPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(element.getClass());
|
||||
|
||||
String collection = entity.getCollection();
|
||||
List<T> collectionElements = elementsByCollection.get(collection);
|
||||
@@ -880,7 +889,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
protected <T> Flux<T> doInsertBatch(final String collectionName, final Collection<? extends T> batchToSave,
|
||||
final MongoWriter<Object> writer) {
|
||||
|
||||
Assert.notNull(writer);
|
||||
Assert.notNull(writer, "MongoWriter must not be null!");
|
||||
|
||||
Mono<List<Tuple2<T, Document>>> prepareDocuments = Flux.fromIterable(batchToSave)
|
||||
.flatMap(new Function<T, Flux<Tuple2<T, Document>>>() {
|
||||
@@ -897,7 +906,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
}
|
||||
}).collectList();
|
||||
|
||||
Flux<Tuple2<T, Document>> insertDocuments = prepareDocuments.flatMap(tuples -> {
|
||||
Flux<Tuple2<T, Document>> insertDocuments = prepareDocuments.flatMapMany(tuples -> {
|
||||
|
||||
List<Document> dbObjects = tuples.stream().map(Tuple2::getT2).collect(Collectors.toList());
|
||||
|
||||
@@ -917,7 +926,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
@Override
|
||||
public <T> Mono<T> save(Mono<? extends T> objectToSave) {
|
||||
return objectToSave.then(this::save);
|
||||
return objectToSave.flatMap(this::save);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -925,7 +934,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
@Override
|
||||
public <T> Mono<T> save(Mono<? extends T> objectToSave, String collectionName) {
|
||||
return objectToSave.then(o -> save(o, collectionName));
|
||||
return objectToSave.flatMap(o -> save(o, collectionName));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -933,7 +942,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public <T> Mono<T> save(T objectToSave) {
|
||||
|
||||
Assert.notNull(objectToSave);
|
||||
Assert.notNull(objectToSave, "Object to save must not be null!");
|
||||
return save(objectToSave, determineEntityCollectionName(objectToSave));
|
||||
}
|
||||
|
||||
@@ -942,8 +951,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public <T> Mono<T> save(T objectToSave, String collectionName) {
|
||||
|
||||
Assert.notNull(objectToSave);
|
||||
Assert.hasText(collectionName);
|
||||
Assert.notNull(objectToSave, "Object to save must not be null!");
|
||||
Assert.hasText(collectionName, "Collection name must not be null or empty!");
|
||||
|
||||
MongoPersistentEntity<?> mongoPersistentEntity = getPersistentEntity(objectToSave.getClass());
|
||||
|
||||
@@ -962,25 +971,29 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
ConvertingPropertyAccessor convertingAccessor = new ConvertingPropertyAccessor(
|
||||
entity.getPropertyAccessor(objectToSave), mongoConverter.getConversionService());
|
||||
|
||||
MongoPersistentProperty idProperty = entity.getIdProperty();
|
||||
MongoPersistentProperty versionProperty = entity.getVersionProperty();
|
||||
MongoPersistentProperty idProperty = entity.getIdProperty()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No id property present!"));
|
||||
MongoPersistentProperty versionProperty = entity.getVersionProperty()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No version property present!"));
|
||||
;
|
||||
|
||||
Object version = convertingAccessor.getProperty(versionProperty);
|
||||
Number versionNumber = convertingAccessor.getProperty(versionProperty, Number.class);
|
||||
Optional<Object> version = convertingAccessor.getProperty(versionProperty);
|
||||
Optional<Number> versionNumber = convertingAccessor.getProperty(versionProperty, Number.class);
|
||||
|
||||
// Fresh instance -> initialize version property
|
||||
if (version == null) {
|
||||
if (!version.isPresent()) {
|
||||
return doInsert(collectionName, objectToSave, mongoConverter);
|
||||
}
|
||||
|
||||
ReactiveMongoTemplate.this.assertUpdateableIdIfNotSet(objectToSave);
|
||||
|
||||
// Create query for entity with the id and old version
|
||||
Object id = convertingAccessor.getProperty(idProperty);
|
||||
Query query = new Query(Criteria.where(idProperty.getName()).is(id).and(versionProperty.getName()).is(version));
|
||||
Optional<Object> id = convertingAccessor.getProperty(idProperty);
|
||||
Query query = new Query(
|
||||
Criteria.where(idProperty.getName()).is(id.get()).and(versionProperty.getName()).is(version.get()));
|
||||
|
||||
// Bump version number
|
||||
convertingAccessor.setProperty(versionProperty, versionNumber.longValue() + 1);
|
||||
convertingAccessor.setProperty(versionProperty, Optional.of(versionNumber.orElse(0).longValue() + 1));
|
||||
|
||||
ReactiveMongoTemplate.this.maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave, collectionName));
|
||||
|
||||
@@ -1077,34 +1090,35 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
return collectionToUse;
|
||||
}
|
||||
|
||||
protected Mono<Object> saveDocument(final String collectionName, final Document dbDoc, final Class<?> entityClass) {
|
||||
protected Mono<Object> saveDocument(final String collectionName, final Document document,
|
||||
final Class<?> entityClass) {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Saving Document containing fields: " + dbDoc.keySet());
|
||||
LOGGER.debug("Saving Document containing fields: " + document.keySet());
|
||||
}
|
||||
|
||||
return createMono(collectionName, collection -> {
|
||||
|
||||
MongoAction mongoAction = new MongoAction(writeConcern, MongoActionOperation.SAVE, collectionName, entityClass,
|
||||
dbDoc, null);
|
||||
document, null);
|
||||
WriteConcern writeConcernToUse = prepareWriteConcern(mongoAction);
|
||||
|
||||
Publisher<?> publisher;
|
||||
if (!dbDoc.containsKey(ID_FIELD)) {
|
||||
if (!document.containsKey(ID_FIELD)) {
|
||||
if (writeConcernToUse == null) {
|
||||
publisher = collection.insertOne(dbDoc);
|
||||
publisher = collection.insertOne(document);
|
||||
} else {
|
||||
publisher = collection.withWriteConcern(writeConcernToUse).insertOne(dbDoc);
|
||||
publisher = collection.withWriteConcern(writeConcernToUse).insertOne(document);
|
||||
}
|
||||
} else if (writeConcernToUse == null) {
|
||||
publisher = collection.replaceOne(Filters.eq(ID_FIELD, dbDoc.get(ID_FIELD)), dbDoc,
|
||||
publisher = collection.replaceOne(Filters.eq(ID_FIELD, document.get(ID_FIELD)), document,
|
||||
new UpdateOptions().upsert(true));
|
||||
} else {
|
||||
publisher = collection.withWriteConcern(writeConcernToUse).replaceOne(Filters.eq(ID_FIELD, dbDoc.get(ID_FIELD)),
|
||||
dbDoc, new UpdateOptions().upsert(true));
|
||||
publisher = collection.withWriteConcern(writeConcernToUse)
|
||||
.replaceOne(Filters.eq(ID_FIELD, document.get(ID_FIELD)), document, new UpdateOptions().upsert(true));
|
||||
}
|
||||
|
||||
return Mono.from(publisher).map(o -> dbDoc.get(ID_FIELD));
|
||||
return Mono.from(publisher).map(o -> document.get(ID_FIELD));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1196,6 +1210,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
MongoCollection<Document> collectionToUse = prepareCollection(collection, writeConcernToUse);
|
||||
|
||||
UpdateOptions updateOptions = new UpdateOptions().upsert(upsert);
|
||||
query.getCollation().map(Collation::toMongoCollation).ifPresent(updateOptions::collation);
|
||||
|
||||
if (!UpdateMapper.isUpdateObject(updateObj)) {
|
||||
return collectionToUse.replaceOne(queryObj, updateObj, updateOptions);
|
||||
@@ -1226,7 +1241,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
private void increaseVersionForUpdateIfNecessary(MongoPersistentEntity<?> persistentEntity, Update update) {
|
||||
|
||||
if (persistentEntity != null && persistentEntity.hasVersionProperty()) {
|
||||
String versionFieldName = persistentEntity.getVersionProperty().getFieldName();
|
||||
String versionFieldName = persistentEntity.getVersionProperty().get().getFieldName();
|
||||
if (!update.modifies(versionFieldName)) {
|
||||
update.inc(versionFieldName, 1L);
|
||||
}
|
||||
@@ -1239,7 +1254,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
return false;
|
||||
}
|
||||
|
||||
return document.containsKey(persistentEntity.getVersionProperty().getFieldName());
|
||||
return document.containsKey(persistentEntity.getVersionProperty().get().getFieldName());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -1247,7 +1262,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
@Override
|
||||
public Mono<DeleteResult> remove(Mono<? extends Object> objectToRemove) {
|
||||
return objectToRemove.then(this::remove);
|
||||
return objectToRemove.flatMap(this::remove);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -1255,7 +1270,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
@Override
|
||||
public Mono<DeleteResult> remove(Mono<? extends Object> objectToRemove, String collection) {
|
||||
return objectToRemove.then(o -> remove(objectToRemove, collection));
|
||||
return objectToRemove.flatMap(o -> remove(objectToRemove, collection));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -1275,7 +1290,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
public Mono<DeleteResult> remove(Object object, String collection) {
|
||||
|
||||
Assert.hasText(collection);
|
||||
Assert.hasText(collection, "Collection name must not be null or empty!");
|
||||
|
||||
if (object == null) {
|
||||
return null;
|
||||
@@ -1301,15 +1316,15 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
return Collections.singletonMap(ID_FIELD, ((Document) object).get(ID_FIELD)).entrySet().iterator().next();
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(objectType);
|
||||
MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
|
||||
Optional<? extends MongoPersistentEntity<?>> entity = mappingContext.getPersistentEntity(objectType);
|
||||
MongoPersistentProperty idProp = entity.flatMap(PersistentEntity::getIdProperty).orElse(null);
|
||||
|
||||
if (idProp == null) {
|
||||
throw new MappingException("No id property found for object of type " + objectType);
|
||||
}
|
||||
|
||||
Object idValue = entity.getPropertyAccessor(object).getProperty(idProp);
|
||||
return Collections.singletonMap(idProp.getFieldName(), idValue).entrySet().iterator().next();
|
||||
Optional<Object> idValue = entity.get().getPropertyAccessor(object).getProperty(idProp);
|
||||
return Collections.singletonMap(idProp.getFieldName(), idValue.get()).entrySet().iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1349,19 +1364,21 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
|
||||
private void assertUpdateableIdIfNotSet(Object entity) {
|
||||
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entity.getClass());
|
||||
MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty();
|
||||
Optional<? extends MongoPersistentEntity<?>> persistentEntity = mappingContext
|
||||
.getPersistentEntity(entity.getClass());
|
||||
Optional<MongoPersistentProperty> idProperty = persistentEntity.isPresent() ? persistentEntity.get().getIdProperty()
|
||||
: Optional.empty();
|
||||
|
||||
if (idProperty == null) {
|
||||
if (!idProperty.isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object idValue = persistentEntity.getPropertyAccessor(entity).getProperty(idProperty);
|
||||
Optional<Object> idValue = persistentEntity.get().getPropertyAccessor(entity).getProperty(idProperty.get());
|
||||
|
||||
if (idValue == null && !MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(idProperty.getType())) {
|
||||
if (!idValue.isPresent() && !MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(idProperty.get().getType())) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
String.format("Cannot autogenerate id of type %s for entity of type %s!", idProperty.getType().getName(),
|
||||
entity.getClass().getName()));
|
||||
String.format("Cannot autogenerate id of type %s for entity of type %s!",
|
||||
idProperty.get().getType().getName(), entity.getClass().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1414,7 +1431,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
new Object[] { serializeToJsonSafely(dboq), collectionName });
|
||||
}
|
||||
|
||||
query.getCollation().ifPresent(val -> {
|
||||
|
||||
// TODO: add collation support as soon as it's there! See https://jira.mongodb.org/browse/JAVARS-27
|
||||
throw new IllegalArgumentException("DeleteMany does currently not accept collation settings.");
|
||||
});
|
||||
|
||||
return collectionToUse.deleteMany(dboq);
|
||||
|
||||
}).doOnNext(deleteResult -> maybeEmitEvent(new AfterDeleteEvent<T>(queryObject, entityClass, collectionName)))
|
||||
.next();
|
||||
}
|
||||
@@ -1496,7 +1520,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
Flux<T> flux = find(query, entityClass, collectionName);
|
||||
|
||||
return Flux.from(flux).collectList()
|
||||
.flatMap(list -> Flux.from(remove(getIdInQueryFor(list), entityClass, collectionName))
|
||||
.flatMapMany(list -> Flux.from(remove(getIdInQueryFor(list), entityClass, collectionName))
|
||||
.flatMap(deleteResult -> Flux.fromIterable(list)));
|
||||
}
|
||||
|
||||
@@ -1530,9 +1554,10 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
* @return the {@link List} of converted objects.
|
||||
*/
|
||||
protected <T> Mono<T> doFindOne(String collectionName, Document query, Document fields, Class<T> entityClass) {
|
||||
protected <T> Mono<T> doFindOne(String collectionName, Document query, Document fields, Class<T> entityClass,
|
||||
Collation collation) {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
Optional<? extends MongoPersistentEntity<?>> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
Document mappedQuery = queryMapper.getMappedObject(query, entity);
|
||||
Document mappedFields = fields == null ? null : queryMapper.getMappedObject(fields, entity);
|
||||
|
||||
@@ -1541,7 +1566,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
serializeToJsonSafely(query), mappedFields, entityClass, collectionName));
|
||||
}
|
||||
|
||||
return executeFindOneInternal(new FindOneCallback(mappedQuery, mappedFields),
|
||||
return executeFindOneInternal(new FindOneCallback(mappedQuery, mappedFields, collation),
|
||||
new ReadDocumentCallback<T>(this.mongoConverter, entityClass, collectionName), collectionName);
|
||||
}
|
||||
|
||||
@@ -1582,7 +1607,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
protected <S, T> Flux<T> doFind(String collectionName, Document query, Document fields, Class<S> entityClass,
|
||||
FindPublisherPreparer preparer, DocumentCallback<T> objectCallback) {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
Optional<? extends MongoPersistentEntity<?>> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
|
||||
Document mappedFields = queryMapper.getMappedFields(fields, entity);
|
||||
Document mappedQuery = queryMapper.getMappedObject(query, entity);
|
||||
@@ -1601,17 +1626,10 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
CreateCollectionOptions result = new CreateCollectionOptions();
|
||||
if (collectionOptions != null) {
|
||||
|
||||
if (collectionOptions.getCapped() != null) {
|
||||
result = result.capped(collectionOptions.getCapped());
|
||||
}
|
||||
|
||||
if (collectionOptions.getSize() != null) {
|
||||
result = result.sizeInBytes(collectionOptions.getSize());
|
||||
}
|
||||
|
||||
if (collectionOptions.getMaxDocuments() != null) {
|
||||
result = result.maxDocuments(collectionOptions.getMaxDocuments());
|
||||
}
|
||||
collectionOptions.getCapped().ifPresent(result::capped);
|
||||
collectionOptions.getSize().ifPresent(result::sizeInBytes);
|
||||
collectionOptions.getMaxDocuments().ifPresent(result::maxDocuments);
|
||||
collectionOptions.getCollation().map(Collation::toMongoCollation).ifPresent(result::collation);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1624,38 +1642,35 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*
|
||||
* @param collectionName name of the collection to retrieve the objects from
|
||||
* @param query the query document that specifies the criteria used to find a record
|
||||
* @param collation collation
|
||||
* @param entityClass the parameterized type of the returned list.
|
||||
* @return the List of converted objects.
|
||||
*/
|
||||
protected <T> Mono<T> doFindAndRemove(String collectionName, Document query, Document fields, Document sort,
|
||||
Class<T> entityClass) {
|
||||
Collation collation, Class<T> entityClass) {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("findAndRemove using query: %s fields: %s sort: %s for class: %s in collection: %s",
|
||||
serializeToJsonSafely(query), fields, sort, entityClass, collectionName));
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
Optional<? extends MongoPersistentEntity<?>> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
|
||||
return executeFindOneInternal(new FindAndRemoveCallback(queryMapper.getMappedObject(query, entity), fields, sort),
|
||||
return executeFindOneInternal(
|
||||
new FindAndRemoveCallback(queryMapper.getMappedObject(query, entity), fields, sort, collation),
|
||||
new ReadDocumentCallback<T>(this.mongoConverter, entityClass, collectionName), collectionName);
|
||||
}
|
||||
|
||||
protected <T> Mono<T> doFindAndModify(String collectionName, Document query, Document fields, Document sort,
|
||||
Class<T> entityClass, Update update, FindAndModifyOptions options) {
|
||||
|
||||
FindAndModifyOptions optionsToUse;
|
||||
if (options == null) {
|
||||
optionsToUse = new FindAndModifyOptions();
|
||||
} else {
|
||||
optionsToUse = options;
|
||||
}
|
||||
FindAndModifyOptions optionsToUse = options != null ? options : new FindAndModifyOptions();
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
Optional<? extends MongoPersistentEntity<?>> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
|
||||
return Mono.defer(() -> {
|
||||
|
||||
increaseVersionForUpdateIfNecessary(entity, update);
|
||||
increaseVersionForUpdateIfNecessary(entity.get(), update);
|
||||
|
||||
Document mappedQuery = queryMapper.getMappedObject(query, entity);
|
||||
Document mappedUpdate = updateMapper.getMappedObject(update.getUpdateObject(), entity);
|
||||
@@ -1703,14 +1718,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
}
|
||||
|
||||
ConversionService conversionService = mongoConverter.getConversionService();
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(savedObject.getClass());
|
||||
MongoPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(savedObject.getClass());
|
||||
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(savedObject);
|
||||
|
||||
if (accessor.getProperty(idProp) != null) {
|
||||
if (accessor.getProperty(idProp).isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
new ConvertingPropertyAccessor(accessor, conversionService).setProperty(idProp, id);
|
||||
new ConvertingPropertyAccessor(accessor, conversionService).setProperty(idProp, Optional.ofNullable(id));
|
||||
}
|
||||
|
||||
private MongoCollection<Document> getAndPrepareCollection(MongoDatabase db, String collectionName) {
|
||||
@@ -1839,7 +1854,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
|
||||
private <T> T execute(MongoDatabaseCallback<T> action) {
|
||||
|
||||
Assert.notNull(action);
|
||||
Assert.notNull(action, "MongoDatabaseCallback must not be null!");
|
||||
|
||||
try {
|
||||
MongoDatabase db = this.getMongoDatabase();
|
||||
@@ -1850,36 +1865,19 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception translation {@link Function} intended for {@link Flux#onErrorResumeWith(Function)} usage.
|
||||
* Exception translation {@link Function} intended for {@link Flux#mapError(Function)}} usage.
|
||||
*
|
||||
* @return the exception translation {@link Function}
|
||||
*/
|
||||
private <T> Function<Throwable, Publisher<? extends T>> translateFluxException() {
|
||||
private Function<Throwable, Throwable> translateException() {
|
||||
|
||||
return throwable -> {
|
||||
|
||||
if (throwable instanceof RuntimeException) {
|
||||
return Flux.error(potentiallyConvertRuntimeException((RuntimeException) throwable, exceptionTranslator));
|
||||
return potentiallyConvertRuntimeException((RuntimeException) throwable, exceptionTranslator);
|
||||
}
|
||||
|
||||
return Flux.error(throwable);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception translation {@link Function} intended for {@link Mono#otherwise(Function)} usage.
|
||||
*
|
||||
* @return the exception translation {@link Function}
|
||||
*/
|
||||
private <T> Function<Throwable, Mono<? extends T>> translateMonoException() {
|
||||
|
||||
return throwable -> {
|
||||
|
||||
if (throwable instanceof RuntimeException) {
|
||||
return Mono.error(potentiallyConvertRuntimeException((RuntimeException) throwable, exceptionTranslator));
|
||||
}
|
||||
|
||||
return Mono.error(throwable);
|
||||
return throwable;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1898,12 +1896,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
}
|
||||
|
||||
private MongoPersistentEntity<?> getPersistentEntity(Class<?> type) {
|
||||
return type == null ? null : mappingContext.getPersistentEntity(type);
|
||||
return type == null ? null : mappingContext.getPersistentEntity(type).orElse(null);
|
||||
}
|
||||
|
||||
private MongoPersistentProperty getIdPropertyFor(Class<?> type) {
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(type);
|
||||
return persistentEntity == null ? null : persistentEntity.getIdProperty();
|
||||
|
||||
Optional<? extends MongoPersistentEntity<?>> persistentEntity = mappingContext.getPersistentEntity(type);
|
||||
return persistentEntity.flatMap(PersistentEntity::getIdProperty).orElse(null);
|
||||
}
|
||||
|
||||
private <T> String determineEntityCollectionName(T obj) {
|
||||
@@ -1922,13 +1921,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
"No class parameter provided, entity collection can't be determined!");
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
|
||||
if (entity == null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"No Persistent Entity information found for the class " + entityClass.getName());
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(entityClass);
|
||||
return entity.getCollection();
|
||||
}
|
||||
|
||||
@@ -1983,7 +1976,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
if (mongoPersistentEntity != null && mongoPersistentEntity.hasVersionProperty()) {
|
||||
ConvertingPropertyAccessor accessor = new ConvertingPropertyAccessor(
|
||||
mongoPersistentEntity.getPropertyAccessor(entity), mongoConverter.getConversionService());
|
||||
accessor.setProperty(mongoPersistentEntity.getVersionProperty(), 0);
|
||||
accessor.setProperty(mongoPersistentEntity.getVersionProperty().get(), Optional.of(0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1999,34 +1992,34 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
private static class FindOneCallback implements ReactiveCollectionCallback<Document> {
|
||||
|
||||
private final Document query;
|
||||
private final Document fields;
|
||||
private final Optional<Document> fields;
|
||||
private final Optional<Collation> collation;
|
||||
|
||||
FindOneCallback(Document query, Document fields) {
|
||||
FindOneCallback(Document query, Document fields, Collation collation) {
|
||||
this.query = query;
|
||||
this.fields = fields;
|
||||
this.fields = Optional.ofNullable(fields);
|
||||
this.collation = Optional.ofNullable(collation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<Document> doInCollection(MongoCollection<Document> collection)
|
||||
throws MongoException, DataAccessException {
|
||||
|
||||
if (fields == null) {
|
||||
FindPublisher<Document> publisher = collection.find(query);
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("findOne using query: %s in db.collection: %s", serializeToJsonSafely(query),
|
||||
collection.getNamespace().getFullName()));
|
||||
}
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
|
||||
return collection.find(query).limit(1).first();
|
||||
} else {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format("findOne using query: %s fields: %s in db.collection: %s",
|
||||
serializeToJsonSafely(query), fields, collection.getNamespace().getFullName()));
|
||||
}
|
||||
|
||||
return collection.find(query).projection(fields).limit(1);
|
||||
LOGGER.debug("findOne using query: {} fields: {} in db.collection: {}", serializeToJsonSafely(query),
|
||||
serializeToJsonSafely(fields.orElseGet(Document::new)), collection.getNamespace().getFullName());
|
||||
}
|
||||
|
||||
if (fields.isPresent()) {
|
||||
publisher = publisher.projection(fields.get());
|
||||
}
|
||||
|
||||
publisher = collation.map(Collation::toMongoCollation).map(publisher::collation).orElse(publisher);
|
||||
|
||||
return publisher.limit(1).first();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2079,12 +2072,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
private final Document query;
|
||||
private final Document fields;
|
||||
private final Document sort;
|
||||
private final Optional<Collation> collation;
|
||||
|
||||
FindAndRemoveCallback(Document query, Document fields, Document sort) {
|
||||
FindAndRemoveCallback(Document query, Document fields, Document sort, Collation collation) {
|
||||
|
||||
this.query = query;
|
||||
this.fields = fields;
|
||||
this.sort = sort;
|
||||
this.collation = Optional.ofNullable(collation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2092,6 +2087,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
throws MongoException, DataAccessException {
|
||||
|
||||
FindOneAndDeleteOptions findOneAndDeleteOptions = convertToFindOneAndDeleteOptions(fields, sort);
|
||||
collation.map(Collation::toMongoCollation).ifPresent(findOneAndDeleteOptions::collation);
|
||||
|
||||
return collection.findOneAndDelete(query, findOneAndDeleteOptions);
|
||||
}
|
||||
}
|
||||
@@ -2123,6 +2120,10 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
|
||||
if (options.isRemove()) {
|
||||
FindOneAndDeleteOptions findOneAndDeleteOptions = convertToFindOneAndDeleteOptions(fields, sort);
|
||||
|
||||
findOneAndDeleteOptions = options.getCollation().map(Collation::toMongoCollation)
|
||||
.map(findOneAndDeleteOptions::collation).orElse(findOneAndDeleteOptions);
|
||||
|
||||
return collection.findOneAndDelete(query, findOneAndDeleteOptions);
|
||||
}
|
||||
|
||||
@@ -2143,6 +2144,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
result = result.returnDocument(ReturnDocument.BEFORE);
|
||||
}
|
||||
|
||||
result = options.getCollation().map(Collation::toMongoCollation).map(result::collation).orElse(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -2202,8 +2205,9 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
|
||||
ReadDocumentCallback(EntityReader<? super T, Bson> reader, Class<T> type, String collectionName) {
|
||||
|
||||
Assert.notNull(reader);
|
||||
Assert.notNull(type);
|
||||
Assert.notNull(reader, "EntityReader must not be null!");
|
||||
Assert.notNull(type, "Entity type must not be null!");
|
||||
|
||||
this.reader = reader;
|
||||
this.type = type;
|
||||
this.collectionName = collectionName;
|
||||
@@ -2240,7 +2244,8 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
GeoNearResultDbObjectCallback(DocumentCallback<T> delegate, Metric metric) {
|
||||
|
||||
Assert.notNull(delegate);
|
||||
Assert.notNull(delegate, "DocumentCallback must not be null!");
|
||||
|
||||
this.delegate = delegate;
|
||||
this.metric = metric;
|
||||
}
|
||||
@@ -2276,21 +2281,24 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
return findPublisher;
|
||||
}
|
||||
|
||||
FindPublisher<T> findPublisherToUse;
|
||||
|
||||
findPublisherToUse = query.getCollation().map(Collation::toMongoCollation).map(findPublisher::collation)
|
||||
.orElse(findPublisher);
|
||||
|
||||
if (query.getSkip() <= 0 && query.getLimit() <= 0 && query.getSortObject() == null
|
||||
&& !StringUtils.hasText(query.getHint()) && !query.getMeta().hasValues()) {
|
||||
return findPublisher;
|
||||
return findPublisherToUse;
|
||||
}
|
||||
|
||||
FindPublisher<T> findPublisherToUse = findPublisher;
|
||||
|
||||
try {
|
||||
if (query.getSkip() > 0) {
|
||||
findPublisherToUse = findPublisherToUse.skip(query.getSkip());
|
||||
findPublisherToUse = findPublisherToUse.skip((int) query.getSkip());
|
||||
}
|
||||
if (query.getLimit() > 0) {
|
||||
findPublisherToUse = findPublisherToUse.limit(query.getLimit());
|
||||
}
|
||||
if (query.getSortObject() != null) {
|
||||
if (!ObjectUtils.isEmpty(query.getSortObject())) {
|
||||
Document sort = type != null ? getMappedSortObject(query, type) : query.getSortObject();
|
||||
findPublisherToUse = findPublisherToUse.sort(sort);
|
||||
}
|
||||
@@ -2341,9 +2349,9 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
static class NoOpDbRefResolver implements DbRefResolver {
|
||||
|
||||
@Override
|
||||
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||
public Optional<Object> resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||
DbRefProxyHandler proxyHandler) {
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
|
||||
import com.mongodb.DBCollection;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveDBCollectionInvoker} provides reflective access to {@link DBCollection} API that is not consistently
|
||||
* available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
class ReflectiveDBCollectionInvoker {
|
||||
|
||||
private static final Method GEN_INDEX_NAME_METHOD;
|
||||
private static final Method RESET_INDEX_CHACHE_METHOD;
|
||||
|
||||
static {
|
||||
|
||||
GEN_INDEX_NAME_METHOD = findMethod(DBCollection.class, "genIndexName", Document.class);
|
||||
RESET_INDEX_CHACHE_METHOD = findMethod(DBCollection.class, "resetIndexCache");
|
||||
}
|
||||
|
||||
private ReflectiveDBCollectionInvoker() {}
|
||||
|
||||
/**
|
||||
* Convenience method to generate an index name from the set of fields it is over. Will fall back to a MongoDB Java
|
||||
* driver version 2 compatible way of generating index name in case of {@link MongoClientVersion#isMongo3Driver()}.
|
||||
*
|
||||
* @param keys the names of the fields used in this index
|
||||
* @return
|
||||
*/
|
||||
public static String generateIndexName(Document keys) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return genIndexName(keys);
|
||||
}
|
||||
return (String) invokeMethod(GEN_INDEX_NAME_METHOD, null, keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of MongoDB Java driver version 2 all indices that have not yet been applied to this collection will be
|
||||
* cleared. Since this method is not available for the MongoDB Java driver version 3 the operation will throw
|
||||
* {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @param dbCollection
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static void resetIndexCache(DBCollection dbCollection) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException("The mongo java driver 3 does no loger support resetIndexCache!");
|
||||
}
|
||||
|
||||
invokeMethod(RESET_INDEX_CHACHE_METHOD, dbCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Borrowed from MongoDB Java driver version 2. See
|
||||
* <a href="http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754" >
|
||||
* http://github.com/mongodb/mongo-java-driver/blob/r2.13.0/src/main/com/mongodb/DBCollection.java#L754</a>
|
||||
*
|
||||
* @param keys
|
||||
* @return
|
||||
*/
|
||||
private static String genIndexName(Document keys) {
|
||||
|
||||
StringBuilder name = new StringBuilder();
|
||||
|
||||
for (String s : keys.keySet()) {
|
||||
|
||||
if (name.length() > 0) {
|
||||
name.append('_');
|
||||
}
|
||||
|
||||
name.append(s).append('_');
|
||||
Object val = keys.get(s);
|
||||
|
||||
if (val instanceof Number || val instanceof String) {
|
||||
name.append(val.toString().replace(' ', '_'));
|
||||
}
|
||||
}
|
||||
|
||||
return name.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
|
||||
import org.springframework.data.mongodb.util.MongoClientVersion;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveDbInvoker} provides reflective access to {@link DB} API that is not consistently available for
|
||||
* various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
final class ReflectiveDbInvoker {
|
||||
|
||||
private static final Method DB_IS_AUTHENTICATED_METHOD;
|
||||
private static final Method DB_AUTHENTICATE_METHOD;
|
||||
private static final Method DB_REQUEST_DONE_METHOD;
|
||||
private static final Method DB_ADD_USER_METHOD;
|
||||
private static final Method DB_REQUEST_START_METHOD;
|
||||
|
||||
static {
|
||||
|
||||
DB_IS_AUTHENTICATED_METHOD = findMethod(DB.class, "isAuthenticated");
|
||||
DB_AUTHENTICATE_METHOD = findMethod(DB.class, "authenticate", String.class, char[].class);
|
||||
DB_REQUEST_DONE_METHOD = findMethod(DB.class, "requestDone");
|
||||
DB_ADD_USER_METHOD = findMethod(DB.class, "addUser", String.class, char[].class);
|
||||
DB_REQUEST_START_METHOD = findMethod(DB.class, "requestStart");
|
||||
}
|
||||
|
||||
private ReflectiveDbInvoker() {}
|
||||
|
||||
/**
|
||||
* Authenticate against database using provided credentials in case of a MongoDB Java driver version 2.
|
||||
*
|
||||
* @param mongo must not be {@literal null}.
|
||||
* @param db must not be {@literal null}.
|
||||
* @param credentials must not be {@literal null}.
|
||||
* @param authenticationDatabaseName
|
||||
*/
|
||||
public static void authenticate(Mongo mongo, DB db, UserCredentials credentials, String authenticationDatabaseName) {
|
||||
|
||||
String databaseName = db.getName();
|
||||
|
||||
DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
|
||||
|
||||
synchronized (authDb) {
|
||||
|
||||
Boolean isAuthenticated = (Boolean) invokeMethod(DB_IS_AUTHENTICATED_METHOD, authDb);
|
||||
if (!isAuthenticated) {
|
||||
|
||||
String username = credentials.getUsername();
|
||||
String password = credentials.hasPassword() ? credentials.getPassword() : null;
|
||||
|
||||
Boolean authenticated = (Boolean) invokeMethod(DB_AUTHENTICATE_METHOD, authDb, username,
|
||||
password == null ? null : password.toCharArray());
|
||||
if (!authenticated) {
|
||||
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
|
||||
+ credentials.toString(), databaseName, credentials);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new 'consistent request' in case of MongoDB Java driver version 2. Will do nothing for MongoDB Java driver
|
||||
* version 3 since the operation is no longer available.
|
||||
*
|
||||
* @param db
|
||||
*/
|
||||
public static void requestStart(DB db) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
invokeMethod(DB_REQUEST_START_METHOD, db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the current 'consistent request'. a new 'consistent request' in case of MongoDB Java driver version 2. Will do
|
||||
* nothing for MongoDB Java driver version 3 since the operation is no longer available
|
||||
*
|
||||
* @param db
|
||||
*/
|
||||
public static void requestDone(DB db) {
|
||||
|
||||
if (MongoClientVersion.isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
invokeMethod(DB_REQUEST_DONE_METHOD, db);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param db
|
||||
* @param username
|
||||
* @param password
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static void addUser(DB db, String username, char[] password) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Please use DB.command(…) to call either the createUser or updateUser command!");
|
||||
}
|
||||
|
||||
invokeMethod(DB_ADD_USER_METHOD, db, username, password);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.MapReduceCommand;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveMapReduceInvoker} provides reflective access to {@link MapReduceCommand} API that is not
|
||||
* consistently available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
final class ReflectiveMapReduceInvoker {
|
||||
|
||||
private static final Method ADD_EXTRA_OPTION_METHOD;
|
||||
|
||||
static {
|
||||
|
||||
ADD_EXTRA_OPTION_METHOD = findMethod(MapReduceCommand.class, "addExtraOption", String.class, Object.class);
|
||||
}
|
||||
|
||||
private ReflectiveMapReduceInvoker() {}
|
||||
|
||||
/**
|
||||
* Sets the extra option for MongoDB Java driver version 2. Will do nothing for MongoDB Java driver version 2.
|
||||
*
|
||||
* @param cmd can be {@literal null} for MongoDB Java driver version 2.
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public static void addExtraOption(MapReduceCommand cmd, String key, Object value) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.notNull(cmd, "MapReduceCommand must not be null!");
|
||||
invokeMethod(ADD_EXTRA_OPTION_METHOD, cmd, key, value);
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.mongodb.MongoOptions;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveMongoOptionsInvoker} provides reflective access to {@link MongoOptions} API that is not consistently
|
||||
* available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
class ReflectiveMongoOptionsInvoker {
|
||||
|
||||
private static final Method GET_AUTO_CONNECT_RETRY_METHOD;
|
||||
private static final Method SET_AUTO_CONNECT_RETRY_METHOD;
|
||||
private static final Method GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD;
|
||||
private static final Method SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD;
|
||||
|
||||
static {
|
||||
|
||||
SET_AUTO_CONNECT_RETRY_METHOD = ReflectionUtils
|
||||
.findMethod(MongoOptions.class, "setAutoConnectRetry", boolean.class);
|
||||
GET_AUTO_CONNECT_RETRY_METHOD = ReflectionUtils.findMethod(MongoOptions.class, "isAutoConnectRetry");
|
||||
SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD = ReflectionUtils.findMethod(MongoOptions.class,
|
||||
"setMaxAutoConnectRetryTime", long.class);
|
||||
GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD = ReflectionUtils.findMethod(MongoOptions.class,
|
||||
"getMaxAutoConnectRetryTime");
|
||||
}
|
||||
|
||||
private ReflectiveMongoOptionsInvoker() {}
|
||||
|
||||
/**
|
||||
* Sets the retry connection flag for MongoDB Java driver version 2. Will do nothing for MongoDB Java driver version 3
|
||||
* since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @param autoConnectRetry
|
||||
*/
|
||||
public static void setAutoConnectRetry(MongoOptions options, boolean autoConnectRetry) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
invokeMethod(SET_AUTO_CONNECT_RETRY_METHOD, options, autoConnectRetry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maxAutoConnectRetryTime attribute for MongoDB Java driver version 2. Will do nothing for MongoDB Java
|
||||
* driver version 3 since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @param maxAutoConnectRetryTime
|
||||
*/
|
||||
public static void setMaxAutoConnectRetryTime(MongoOptions options, long maxAutoConnectRetryTime) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
invokeMethod(SET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD, options, maxAutoConnectRetryTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the slaveOk attribute for MongoDB Java driver version 2. Will do nothing for MongoDB Java driver version 3
|
||||
* since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @param slaveOk
|
||||
*/
|
||||
public static void setSlaveOk(MongoOptions options, boolean slaveOk) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
new DirectFieldAccessor(options).setPropertyValue("slaveOk", slaveOk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the slaveOk attribute for MongoDB Java driver version 2. Throws {@link UnsupportedOperationException} for
|
||||
* MongoDB Java driver version 3 since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @return
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static boolean getSlaveOk(MongoOptions options) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot get value for autoConnectRetry which has been removed in MongoDB Java driver version 3.");
|
||||
}
|
||||
|
||||
return ((Boolean) new DirectFieldAccessor(options).getPropertyValue("slaveOk")).booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the autoConnectRetry attribute for MongoDB Java driver version 2. Throws {@link UnsupportedOperationException}
|
||||
* for MongoDB Java driver version 3 since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @return
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static boolean getAutoConnectRetry(MongoOptions options) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot get value for autoConnectRetry which has been removed in MongoDB Java driver version 3.");
|
||||
}
|
||||
|
||||
return ((Boolean) invokeMethod(GET_AUTO_CONNECT_RETRY_METHOD, options)).booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maxAutoConnectRetryTime attribute for MongoDB Java driver version 2. Throws
|
||||
* {@link UnsupportedOperationException} for MongoDB Java driver version 3 since the method has been removed.
|
||||
*
|
||||
* @param options can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @return
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static long getMaxAutoConnectRetryTime(MongoOptions options) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot get value for maxAutoConnectRetryTime which has been removed in MongoDB Java driver version 3.");
|
||||
}
|
||||
|
||||
return ((Long) invokeMethod(GET_MAX_AUTO_CONNECT_RETRY_TIME_METHOD, options)).longValue();
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
|
||||
import com.mongodb.WriteConcern;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveWriteConcernInvoker} provides reflective access to {@link WriteConcern} API that is not consistently
|
||||
* available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
class ReflectiveWriteConcernInvoker {
|
||||
|
||||
private static final WriteConcern NONE_OR_UNACKNOWLEDGED;
|
||||
|
||||
static {
|
||||
|
||||
NONE_OR_UNACKNOWLEDGED = isMongo3Driver() ? WriteConcern.UNACKNOWLEDGED : (WriteConcern) new DirectFieldAccessor(
|
||||
new WriteConcern()).getPropertyValue("NONE");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link WriteConcern#NONE} for MongoDB Java driver version 2, otherwise {@link WriteConcern#UNACKNOWLEDGED}.
|
||||
*/
|
||||
public static WriteConcern noneOrUnacknowledged() {
|
||||
return NONE_OR_UNACKNOWLEDGED;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core;
|
||||
|
||||
import static org.springframework.data.mongodb.util.MongoClientVersion.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
import com.mongodb.WriteResult;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
|
||||
/**
|
||||
* {@link ReflectiveWriteResultInvoker} provides reflective access to {@link WriteResult} API that is not consistently
|
||||
* available for various driver versions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @since 1.7
|
||||
*/
|
||||
final class ReflectiveWriteResultInvoker {
|
||||
|
||||
private static final Method GET_ERROR_METHOD;
|
||||
private static final Method WAS_ACKNOWLEDGED_METHOD;
|
||||
private static final Method WAS_ACKNOWLEDGED_METHOD_UR;
|
||||
|
||||
private ReflectiveWriteResultInvoker() {}
|
||||
|
||||
static {
|
||||
|
||||
GET_ERROR_METHOD = findMethod(WriteResult.class, "getError");
|
||||
WAS_ACKNOWLEDGED_METHOD = findMethod(WriteResult.class, "wasAcknowledged");
|
||||
WAS_ACKNOWLEDGED_METHOD_UR = findMethod(UpdateResult.class, "wasAcknowledged");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param writeResult can be {@literal null} for MongoDB Java driver version 3.
|
||||
* @return null in case of MongoDB Java driver version 3 since errors are thrown as {@link MongoException}.
|
||||
*/
|
||||
public static String getError(WriteResult writeResult) {
|
||||
|
||||
if (isMongo3Driver()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (String) invokeMethod(GET_ERROR_METHOD, writeResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param writeResult
|
||||
* @return return in case of MongoDB Java driver version 2.
|
||||
*/
|
||||
public static boolean wasAcknowledged(WriteResult writeResult) {
|
||||
return isMongo3Driver() ? ((Boolean) invokeMethod(WAS_ACKNOWLEDGED_METHOD, writeResult)).booleanValue() : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param writeResult
|
||||
* @return return in case of MongoDB Java driver version 2.
|
||||
*/
|
||||
public static boolean wasAcknowledged(UpdateResult writeResult) {
|
||||
return isMongo3Driver() ? ((Boolean) invokeMethod(WAS_ACKNOWLEDGED_METHOD_UR, writeResult)).booleanValue() : true;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
* Copyright 2011-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,24 +19,18 @@ import java.net.UnknownHostException;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.authentication.UserCredentials;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientURI;
|
||||
import com.mongodb.MongoException;
|
||||
import com.mongodb.MongoURI;
|
||||
import com.mongodb.WriteConcern;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
|
||||
/**
|
||||
* Factory to create {@link DB} instances from a {@link Mongo} instance.
|
||||
* Factory to create {@link DB} instances from a {@link MongoClient} instance.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Oliver Gierke
|
||||
@@ -45,70 +39,13 @@ import com.mongodb.client.MongoDatabase;
|
||||
*/
|
||||
public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
|
||||
private final Mongo mongo;
|
||||
private final MongoClient mongoClient;
|
||||
private final String databaseName;
|
||||
private final boolean mongoInstanceCreated;
|
||||
private final UserCredentials credentials;
|
||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||
private final String authenticationDatabaseName;
|
||||
|
||||
private WriteConcern writeConcern;
|
||||
|
||||
/**
|
||||
* Create an instance of {@link SimpleMongoDbFactory} given the {@link Mongo} instance and database name.
|
||||
*
|
||||
* @param mongo Mongo instance, must not be {@literal null}.
|
||||
* @param databaseName database name, not be {@literal null} or empty.
|
||||
* @deprecated since 1.7. Please use {@link #SimpleMongoDbFactory(MongoClient, String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
|
||||
this(mongo, databaseName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of SimpleMongoDbFactory given the Mongo instance, database name, and username/password
|
||||
*
|
||||
* @param mongo Mongo instance, must not be {@literal null}.
|
||||
* @param databaseName Database name, must not be {@literal null} or empty.
|
||||
* @param credentials username and password.
|
||||
* @deprecated since 1.7. The credentials used should be provided by {@link MongoClient#getCredentialsList()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) {
|
||||
this(mongo, databaseName, credentials, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of SimpleMongoDbFactory given the Mongo instance, database name, and username/password
|
||||
*
|
||||
* @param mongo Mongo instance, must not be {@literal null}.
|
||||
* @param databaseName Database name, must not be {@literal null} or empty.
|
||||
* @param credentials username and password.
|
||||
* @param authenticationDatabaseName the database name to use for authentication
|
||||
* @deprecated since 1.7. The credentials used should be provided by {@link MongoClient#getCredentialsList()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||
String authenticationDatabaseName) {
|
||||
this(mongo, databaseName, credentials, false, authenticationDatabaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoURI}.
|
||||
*
|
||||
* @param uri must not be {@literal null}.
|
||||
* @throws MongoException
|
||||
* @throws UnknownHostException
|
||||
* @see MongoURI
|
||||
* @deprecated since 1.7. Please use {@link #SimpleMongoDbFactory(MongoClientURI)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public SimpleMongoDbFactory(MongoURI uri) throws MongoException, UnknownHostException {
|
||||
this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), parseChars(uri.getPassword())), true,
|
||||
uri.getDatabase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoClientURI}.
|
||||
*
|
||||
@@ -116,7 +53,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
* @throws UnknownHostException
|
||||
* @since 1.7
|
||||
*/
|
||||
public SimpleMongoDbFactory(MongoClientURI uri) throws UnknownHostException {
|
||||
public SimpleMongoDbFactory(MongoClientURI uri) {
|
||||
this(new MongoClient(uri), uri.getDatabase(), true);
|
||||
}
|
||||
|
||||
@@ -131,48 +68,23 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
this(mongoClient, databaseName, false);
|
||||
}
|
||||
|
||||
private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
|
||||
boolean mongoInstanceCreated, String authenticationDatabaseName) {
|
||||
|
||||
if (mongo instanceof MongoClient && (credentials != null && !UserCredentials.NO_CREDENTIALS.equals(credentials))) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Usage of 'UserCredentials' with 'MongoClient' is no longer supported. Please use 'MongoCredential' for 'MongoClient' or just 'Mongo'.");
|
||||
}
|
||||
|
||||
Assert.notNull(mongo, "Mongo must not be null");
|
||||
Assert.hasText(databaseName, "Database name must not be empty");
|
||||
Assert.isTrue(databaseName.matches("[\\w-]+"),
|
||||
"Database name must only contain letters, numbers, underscores and dashes!");
|
||||
|
||||
this.mongo = mongo;
|
||||
this.databaseName = databaseName;
|
||||
this.mongoInstanceCreated = mongoInstanceCreated;
|
||||
this.credentials = credentials == null ? UserCredentials.NO_CREDENTIALS : credentials;
|
||||
this.exceptionTranslator = new MongoExceptionTranslator();
|
||||
this.authenticationDatabaseName = StringUtils.hasText(authenticationDatabaseName) ? authenticationDatabaseName
|
||||
: databaseName;
|
||||
|
||||
Assert.isTrue(this.authenticationDatabaseName.matches("[\\w-]+"),
|
||||
"Authentication database name must only contain letters, numbers, underscores and dashes!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param client
|
||||
* @param databaseName
|
||||
* @param mongoInstanceCreated
|
||||
* @since 1.7
|
||||
*/
|
||||
private SimpleMongoDbFactory(MongoClient client, String databaseName, boolean mongoInstanceCreated) {
|
||||
private SimpleMongoDbFactory(MongoClient mongoClient, String databaseName, boolean mongoInstanceCreated) {
|
||||
|
||||
Assert.notNull(client, "MongoClient must not be null!");
|
||||
Assert.notNull(mongoClient, "MongoClient must not be null!");
|
||||
Assert.hasText(databaseName, "Database name must not be empty!");
|
||||
Assert.isTrue(databaseName.matches("[\\w-]+"),
|
||||
"Database name must only contain letters, numbers, underscores and dashes!");
|
||||
|
||||
this.mongo = client;
|
||||
this.mongoClient = mongoClient;
|
||||
this.databaseName = databaseName;
|
||||
this.mongoInstanceCreated = mongoInstanceCreated;
|
||||
this.exceptionTranslator = new MongoExceptionTranslator();
|
||||
this.credentials = UserCredentials.NO_CREDENTIALS;
|
||||
this.authenticationDatabaseName = databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,7 +112,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
|
||||
Assert.hasText(dbName, "Database name must not be empty.");
|
||||
|
||||
MongoDatabase db = ((MongoClient) mongo).getDatabase(dbName);
|
||||
MongoDatabase db = mongoClient.getDatabase(dbName);
|
||||
|
||||
if (writeConcern == null) {
|
||||
return db;
|
||||
@@ -216,14 +128,10 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
*/
|
||||
public void destroy() throws Exception {
|
||||
if (mongoInstanceCreated) {
|
||||
mongo.close();
|
||||
mongoClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static String parseChars(char[] chars) {
|
||||
return chars == null ? null : String.valueOf(chars);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.MongoDbFactory#getExceptionTranslator()
|
||||
@@ -236,6 +144,6 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public DB getLegacyDb() {
|
||||
return mongo.getDB(databaseName);
|
||||
return mongoClient.getDB(databaseName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,12 +17,12 @@ package org.springframework.data.mongodb.core;
|
||||
|
||||
/**
|
||||
* Enum to represent how strict the check of {@link com.mongodb.WriteResult} shall be. It can either be skipped entirely
|
||||
* (use {@link #NONE}), or errors can be logged ({@link #LOG}) or cause an exception to be thrown {@link #EXCEPTION}.
|
||||
*
|
||||
* (use {@link #NONE}) or cause an exception to be thrown {@link #EXCEPTION}.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public enum WriteResultChecking {
|
||||
|
||||
NONE, LOG, EXCEPTION
|
||||
NONE, EXCEPTION
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
abstract class AbstractAggregationExpression implements AggregationExpression {
|
||||
|
||||
private final Object value;
|
||||
|
||||
protected AbstractAggregationExpression(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
return toDocument(this.value, context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Document toDocument(Object value, AggregationOperationContext context) {
|
||||
|
||||
Object valueToUse;
|
||||
if (value instanceof List) {
|
||||
|
||||
List<Object> arguments = (List<Object>) value;
|
||||
List<Object> args = new ArrayList<Object>(arguments.size());
|
||||
|
||||
for (Object val : arguments) {
|
||||
args.add(unpack(val, context));
|
||||
}
|
||||
valueToUse = args;
|
||||
} else if (value instanceof java.util.Map) {
|
||||
|
||||
Document dbo = new Document();
|
||||
for (java.util.Map.Entry<String, Object> entry : ((java.util.Map<String, Object>) value).entrySet()) {
|
||||
dbo.put(entry.getKey(), unpack(entry.getValue(), context));
|
||||
}
|
||||
valueToUse = dbo;
|
||||
} else {
|
||||
valueToUse = unpack(value, context);
|
||||
}
|
||||
|
||||
return new Document(getMongoMethod(), valueToUse);
|
||||
}
|
||||
|
||||
protected static List<Field> asFields(String... fieldRefs) {
|
||||
|
||||
if (ObjectUtils.isEmpty(fieldRefs)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Fields.fields(fieldRefs).asList();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object unpack(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof AggregationExpression) {
|
||||
return ((AggregationExpression) value).toDocument(context);
|
||||
}
|
||||
|
||||
if (value instanceof Field) {
|
||||
return context.getReference((Field) value).toString();
|
||||
}
|
||||
|
||||
if (value instanceof List) {
|
||||
|
||||
List<Object> sourceList = (List<Object>) value;
|
||||
List<Object> mappedList = new ArrayList<Object>(sourceList.size());
|
||||
|
||||
for (Object item : sourceList) {
|
||||
mappedList.add(unpack(item, context));
|
||||
}
|
||||
return mappedList;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
protected List<Object> append(Object value) {
|
||||
|
||||
if (this.value instanceof List) {
|
||||
|
||||
List<Object> clone = new ArrayList<Object>((List) this.value);
|
||||
|
||||
if (value instanceof List) {
|
||||
for (Object val : (List) value) {
|
||||
clone.add(val);
|
||||
}
|
||||
} else {
|
||||
clone.add(value);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
return Arrays.asList(this.value, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected java.util.Map<String, Object> append(String key, Object value) {
|
||||
|
||||
if (!(this.value instanceof java.util.Map)) {
|
||||
throw new IllegalArgumentException("o_O");
|
||||
}
|
||||
java.util.Map<String, Object> clone = new LinkedHashMap<String, Object>((java.util.Map<String, Object>) this.value);
|
||||
clone.put(key, value);
|
||||
return clone;
|
||||
|
||||
}
|
||||
|
||||
protected List<Object> values() {
|
||||
|
||||
if (value instanceof List) {
|
||||
return new ArrayList<Object>((List) value);
|
||||
}
|
||||
if (value instanceof java.util.Map) {
|
||||
return new ArrayList<Object>(((java.util.Map) value).values());
|
||||
}
|
||||
return new ArrayList<Object>(Collections.singletonList(value));
|
||||
}
|
||||
|
||||
protected abstract String getMongoMethod();
|
||||
}
|
||||
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Gateway to {@literal accumulator} aggregation operations.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
* @soundtrack Rage Against The Machine - Killing In The Name
|
||||
*/
|
||||
public class AccumulatorOperators {
|
||||
|
||||
/**
|
||||
* Take the numeric value referenced by given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static AccumulatorOperatorFactory valueOf(String fieldReference) {
|
||||
return new AccumulatorOperatorFactory(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the numeric value referenced resulting from given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static AccumulatorOperatorFactory valueOf(AggregationExpression expression) {
|
||||
return new AccumulatorOperatorFactory(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class AccumulatorOperatorFactory {
|
||||
|
||||
private final String fieldReference;
|
||||
private final AggregationExpression expression;
|
||||
|
||||
/**
|
||||
* Creates new {@link AccumulatorOperatorFactory} for given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
*/
|
||||
public AccumulatorOperatorFactory(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
this.fieldReference = fieldReference;
|
||||
this.expression = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AccumulatorOperatorFactory} for given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
*/
|
||||
public AccumulatorOperatorFactory(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
this.fieldReference = null;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and calculates and
|
||||
* returns the sum.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Sum sum() {
|
||||
return usesFieldRef() ? Sum.sumOf(fieldReference) : Sum.sumOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and returns the
|
||||
* average value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Avg avg() {
|
||||
return usesFieldRef() ? Avg.avgOf(fieldReference) : Avg.avgOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and returns the
|
||||
* maximum value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Max max() {
|
||||
return usesFieldRef() ? Max.maxOf(fieldReference) : Max.maxOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and returns the
|
||||
* minimum value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Min min() {
|
||||
return usesFieldRef() ? Min.minOf(fieldReference) : Min.minOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and calculates the
|
||||
* population standard deviation of the input values.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public StdDevPop stdDevPop() {
|
||||
return usesFieldRef() ? StdDevPop.stdDevPopOf(fieldReference) : StdDevPop.stdDevPopOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that takes the associated numeric value expression and calculates the
|
||||
* sample standard deviation of the input values.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public StdDevSamp stdDevSamp() {
|
||||
return usesFieldRef() ? StdDevSamp.stdDevSampOf(fieldReference) : StdDevSamp.stdDevSampOf(expression);
|
||||
}
|
||||
|
||||
private boolean usesFieldRef() {
|
||||
return fieldReference != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $sum}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Sum extends AbstractAggregationExpression {
|
||||
|
||||
private Sum(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$sum";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Sum}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Sum sumOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Sum(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Sum}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Sum sumOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Sum(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Sum} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Sum and(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Sum(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Sum} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Sum and(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Sum(append(expression));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Document toDocument(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof List) {
|
||||
if (((List) value).size() == 1) {
|
||||
return super.toDocument(((List<Object>) value).iterator().next(), context);
|
||||
}
|
||||
}
|
||||
|
||||
return super.toDocument(value, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $avg}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Avg extends AbstractAggregationExpression {
|
||||
|
||||
private Avg(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$avg";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Avg}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Avg avgOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Avg(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Avg}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Avg avgOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Avg(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Avg} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Avg and(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Avg(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Avg} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Avg and(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Avg(append(expression));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Document toDocument(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof List) {
|
||||
if (((List) value).size() == 1) {
|
||||
return super.toDocument(((List<Object>) value).iterator().next(), context);
|
||||
}
|
||||
}
|
||||
|
||||
return super.toDocument(value, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $max}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Max extends AbstractAggregationExpression {
|
||||
|
||||
private Max(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$max";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Max}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Max maxOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Max(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Max}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Max maxOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Max(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Max} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Max and(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Max(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Max} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Max and(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Max(append(expression));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Document toDocument(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof List) {
|
||||
if (((List) value).size() == 1) {
|
||||
return super.toDocument(((List<Object>) value).iterator().next(), context);
|
||||
}
|
||||
}
|
||||
|
||||
return super.toDocument(value, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $min}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Min extends AbstractAggregationExpression {
|
||||
|
||||
private Min(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$min";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Min}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Min minOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Min(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Min}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Min minOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Min(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Min} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Min and(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Min(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Min} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Min and(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Min(append(expression));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Document toDocument(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof List) {
|
||||
if (((List) value).size() == 1) {
|
||||
return super.toDocument(((List<Object>) value).iterator().next(), context);
|
||||
}
|
||||
}
|
||||
|
||||
return super.toDocument(value, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $stdDevPop}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class StdDevPop extends AbstractAggregationExpression {
|
||||
|
||||
private StdDevPop(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$stdDevPop";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link StdDevPop}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static StdDevPop stdDevPopOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new StdDevPop(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link StdDevPop} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static StdDevPop stdDevPopOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new StdDevPop(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link StdDevPop} with all previously added arguments appending the given one. <br/>
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public StdDevPop and(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new StdDevPop(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link StdDevSamp} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public StdDevPop and(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new StdDevPop(append(expression));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Document toDocument(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof List) {
|
||||
if (((List) value).size() == 1) {
|
||||
return super.toDocument(((List<Object>) value).iterator().next(), context);
|
||||
}
|
||||
}
|
||||
|
||||
return super.toDocument(value, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $stdDevSamp}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class StdDevSamp extends AbstractAggregationExpression {
|
||||
|
||||
private StdDevSamp(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$stdDevSamp";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link StdDevSamp}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static StdDevSamp stdDevSampOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new StdDevSamp(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link StdDevSamp}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static StdDevSamp stdDevSampOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new StdDevSamp(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link StdDevSamp} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public StdDevSamp and(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new StdDevSamp(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link StdDevSamp} with all previously added arguments appending the given one. <br />
|
||||
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public StdDevSamp and(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new StdDevSamp(append(expression));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Document toDocument(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof List) {
|
||||
if (((List) value).size() == 1) {
|
||||
return super.toDocument(((List<Object>) value).iterator().next(), context);
|
||||
}
|
||||
}
|
||||
|
||||
return super.toDocument(value, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,18 +17,19 @@ package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import static org.springframework.data.mongodb.core.aggregation.Fields.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
|
||||
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
|
||||
import org.springframework.data.mongodb.core.aggregation.CountOperation.CountOperationBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.FacetOperation.FacetOperationBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.GraphLookupOperation.StartWithBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.ReplaceRootOperation.ReplaceRootDocumentOperationBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.ReplaceRootOperation.ReplaceRootOperationBuilder;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
import org.springframework.data.mongodb.core.query.SerializationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -44,6 +45,7 @@ import org.springframework.util.Assert;
|
||||
* @author Alessio Fachechi
|
||||
* @author Christoph Strobl
|
||||
* @author Nikolay Bogdanov
|
||||
* @author Gustavo de Geus
|
||||
* @since 1.3
|
||||
*/
|
||||
public class Aggregation {
|
||||
@@ -60,7 +62,7 @@ public class Aggregation {
|
||||
*/
|
||||
public static final String CURRENT = SystemVariable.CURRENT.toString();
|
||||
|
||||
public static final AggregationOperationContext DEFAULT_CONTEXT = new NoOpAggregationOperationContext();
|
||||
public static final AggregationOperationContext DEFAULT_CONTEXT = AggregationOperationRenderer.DEFAULT_CONTEXT;
|
||||
public static final AggregationOptions DEFAULT_OPTIONS = newAggregationOptions().build();
|
||||
|
||||
protected final List<AggregationOperation> operations;
|
||||
@@ -194,7 +196,7 @@ public class Aggregation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ProjectionOperation} includeing the given {@link Fields}.
|
||||
* Creates a new {@link ProjectionOperation} including the given {@link Fields}.
|
||||
*
|
||||
* @param fields must not be {@literal null}.
|
||||
* @return
|
||||
@@ -213,6 +215,40 @@ public class Aggregation {
|
||||
return new UnwindOperation(field(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link ReplaceRootOperation} for the field with the given name.
|
||||
*
|
||||
* @param fieldName must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static ReplaceRootOperation replaceRoot(String fieldName) {
|
||||
return ReplaceRootOperation.builder().withValueOf(fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link ReplaceRootOperation} for the field with the given
|
||||
* {@link AggregationExpression}.
|
||||
*
|
||||
* @param aggregationExpression must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static ReplaceRootOperation replaceRoot(AggregationExpression aggregationExpression) {
|
||||
return ReplaceRootOperation.builder().withValueOf(aggregationExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link ReplaceRootDocumentOperationBuilder} to configure a
|
||||
* {@link ReplaceRootOperation}.
|
||||
*
|
||||
* @return the {@literal ReplaceRootDocumentOperationBuilder}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public static ReplaceRootOperationBuilder replaceRoot() {
|
||||
return ReplaceRootOperation.builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link UnwindOperation} for the field with the given name and
|
||||
* {@code preserveNullAndEmptyArrays}. Note that extended unwind is supported in MongoDB version 3.2+.
|
||||
@@ -277,6 +313,18 @@ public class Aggregation {
|
||||
return new GroupOperation(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GraphLookupOperation.GraphLookupOperationFromBuilder} to construct a
|
||||
* {@link GraphLookupOperation} given {@literal fromCollection}.
|
||||
*
|
||||
* @param fromCollection must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static StartWithBuilder graphLookup(String fromCollection) {
|
||||
return GraphLookupOperation.builder().from(fromCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link SortOperation} for the given {@link Sort}.
|
||||
*
|
||||
@@ -295,7 +343,7 @@ public class Aggregation {
|
||||
* @return
|
||||
*/
|
||||
public static SortOperation sort(Direction direction, String... fields) {
|
||||
return new SortOperation(new Sort(direction, fields));
|
||||
return new SortOperation(Sort.by(direction, fields));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -329,6 +377,17 @@ public class Aggregation {
|
||||
return new LimitOperation(maxElements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SampleOperation} to select the specified number of documents from its input randomly.
|
||||
*
|
||||
* @param sampleSize must not be less than zero.
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
public static SampleOperation sample(long sampleSize) {
|
||||
return new SampleOperation(sampleSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link MatchOperation} using the given {@link Criteria}.
|
||||
*
|
||||
@@ -339,6 +398,17 @@ public class Aggregation {
|
||||
return new MatchOperation(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link MatchOperation} using the given {@link CriteriaDefinition}.
|
||||
*
|
||||
* @param criteria must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static MatchOperation match(CriteriaDefinition criteria) {
|
||||
return new MatchOperation(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link OutOperation} using the given collection name. This operation must be the last operation in
|
||||
* the pipeline.
|
||||
@@ -353,6 +423,73 @@ public class Aggregation {
|
||||
return new OutOperation(outCollectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperation} given {@literal groupByField}.
|
||||
*
|
||||
* @param groupByField must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static BucketOperation bucket(String groupByField) {
|
||||
return new BucketOperation(field(groupByField));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperation} given {@link AggregationExpression group-by expression}.
|
||||
*
|
||||
* @param groupByExpression must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static BucketOperation bucket(AggregationExpression groupByExpression) {
|
||||
return new BucketOperation(groupByExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperation} given {@literal groupByField}.
|
||||
*
|
||||
* @param groupByField must not be {@literal null} or empty.
|
||||
* @param buckets number of buckets, must be a positive integer.
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static BucketAutoOperation bucketAuto(String groupByField, int buckets) {
|
||||
return new BucketAutoOperation(field(groupByField), buckets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperation} given {@link AggregationExpression group-by expression}.
|
||||
*
|
||||
* @param groupByExpression must not be {@literal null}.
|
||||
* @param buckets number of buckets, must be a positive integer.
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static BucketAutoOperation bucketAuto(AggregationExpression groupByExpression, int buckets) {
|
||||
return new BucketAutoOperation(groupByExpression, buckets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FacetOperation}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static FacetOperation facet() {
|
||||
return FacetOperation.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FacetOperationBuilder} given {@link Aggregation}.
|
||||
*
|
||||
* @param aggregationOperations the sub-pipeline, must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public static FacetOperationBuilder facet(AggregationOperation... aggregationOperations) {
|
||||
return facet().and(aggregationOperations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link LookupOperation}.
|
||||
*
|
||||
@@ -382,65 +519,13 @@ public class Aggregation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link IfNullOperator} for the given {@code field} and {@code replacement} value.
|
||||
* Creates a new {@link CountOperationBuilder}.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @param replacement must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public static IfNullOperator ifNull(String field, Object replacement) {
|
||||
return IfNullOperator.newBuilder().ifNull(field).thenReplaceWith(replacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link IfNullOperator} for the given {@link Field} and {@link Field} to obtain a value from.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @param replacement must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public static IfNullOperator ifNull(Field field, Field replacement) {
|
||||
return IfNullOperator.newBuilder().ifNull(field).thenReplaceWith(replacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link IfNullOperator} for the given {@link Field} and {@code replacement} value.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @param replacement must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public static IfNullOperator ifNull(Field field, Object replacement) {
|
||||
return IfNullOperator.newBuilder().ifNull(field).thenReplaceWith(replacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConditionalOperator} for the given {@link Field} that holds a {@literal boolean} value.
|
||||
*
|
||||
* @param booleanField must not be {@literal null}.
|
||||
* @param then must not be {@literal null}.
|
||||
* @param otherwise must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public static ConditionalOperator conditional(Field booleanField, Object then, Object otherwise) {
|
||||
return ConditionalOperator.newBuilder().when(booleanField).then(then).otherwise(otherwise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConditionalOperator} for the given {@link Criteria}.
|
||||
*
|
||||
* @param criteria must not be {@literal null}.
|
||||
* @param then must not be {@literal null}.
|
||||
* @param otherwise must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public static ConditionalOperator conditional(Criteria criteria, Object then, Object otherwise) {
|
||||
return ConditionalOperator.newBuilder().when(criteria).then(then).otherwise(otherwise);
|
||||
public static CountOperationBuilder count() {
|
||||
return new CountOperationBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,24 +581,7 @@ public class Aggregation {
|
||||
*/
|
||||
public Document toDocument(String inputCollectionName, AggregationOperationContext rootContext) {
|
||||
|
||||
AggregationOperationContext context = rootContext;
|
||||
List<Document> operationDocuments = new ArrayList<Document>(operations.size());
|
||||
|
||||
for (AggregationOperation operation : operations) {
|
||||
|
||||
operationDocuments.add(operation.toDocument(context));
|
||||
|
||||
if (operation instanceof FieldsExposingAggregationOperation) {
|
||||
|
||||
FieldsExposingAggregationOperation exposedFieldsOperation = (FieldsExposingAggregationOperation) operation;
|
||||
|
||||
if (operation instanceof InheritsFieldsAggregationOperation) {
|
||||
context = new InheritingExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), context);
|
||||
} else {
|
||||
context = new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), context);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Document> operationDocuments = AggregationOperationRenderer.toDocument(operations, rootContext);
|
||||
|
||||
Document command = new Document("aggregate", inputCollectionName);
|
||||
command.put("pipeline", operationDocuments);
|
||||
@@ -523,56 +591,20 @@ public class Aggregation {
|
||||
return command;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return SerializationUtils
|
||||
.serializeToJsonSafely(toDocument("__collection__", new NoOpAggregationOperationContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple {@link AggregationOperationContext} that just returns {@link FieldReference}s as is.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class NoOpAggregationOperationContext implements AggregationOperationContext {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.Document)
|
||||
*/
|
||||
@Override
|
||||
public Document getMappedObject(Document document) {
|
||||
return document;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(org.springframework.data.mongodb.core.aggregation.ExposedFields.AvailableField)
|
||||
*/
|
||||
@Override
|
||||
public FieldReference getReference(Field field) {
|
||||
return new FieldReference(new ExposedField(field, true));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public FieldReference getReference(String name) {
|
||||
return new FieldReference(new ExposedField(new AggregationField(name), true));
|
||||
}
|
||||
return SerializationUtils.serializeToJsonSafely(toDocument("__collection__", DEFAULT_CONTEXT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the system variables available in MongoDB aggregation framework pipeline expressions.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation-variables
|
||||
* @see <a href="https://docs.mongodb.org/manual/reference/aggregation-variables">Aggregation Variables</a>
|
||||
*/
|
||||
enum SystemVariable {
|
||||
|
||||
@@ -605,7 +637,7 @@ public class Aggregation {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Enum#toString()
|
||||
*/
|
||||
|
||||
@@ -30,10 +30,12 @@ import org.springframework.util.Assert;
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 1.7
|
||||
* @deprecated since 1.10. Please use {@link ArithmeticOperators} and {@link ComparisonOperators} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum AggregationFunctionExpressions {
|
||||
|
||||
SIZE;
|
||||
SIZE, CMP, EQ, GT, GTE, LT, LTE, NE, SUBTRACT, ADD, MULTIPLY;
|
||||
|
||||
/**
|
||||
* Returns an {@link AggregationExpression} build from the current {@link Enum} name and the given parameters.
|
||||
@@ -52,7 +54,7 @@ public enum AggregationFunctionExpressions {
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.10
|
||||
* @since 1.7
|
||||
*/
|
||||
static class FunctionExpression implements AggregationExpression {
|
||||
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.DirectFieldReference;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
|
||||
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
|
||||
|
||||
/**
|
||||
* Rendering support for {@link AggregationOperation} into a {@link List} of {@link org.bson.Document}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
class AggregationOperationRenderer {
|
||||
|
||||
static final AggregationOperationContext DEFAULT_CONTEXT = new NoOpAggregationOperationContext();
|
||||
|
||||
/**
|
||||
* Render a {@link List} of {@link AggregationOperation} given {@link AggregationOperationContext} into their
|
||||
* {@link Document} representation.
|
||||
*
|
||||
* @param operations must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
* @return the {@link List} of {@link Document}.
|
||||
*/
|
||||
static List<Document> toDocument(List<AggregationOperation> operations, AggregationOperationContext rootContext) {
|
||||
|
||||
List<Document> operationDocuments = new ArrayList<Document>(operations.size());
|
||||
|
||||
AggregationOperationContext contextToUse = rootContext;
|
||||
|
||||
for (AggregationOperation operation : operations) {
|
||||
|
||||
operationDocuments.add(operation.toDocument(contextToUse));
|
||||
|
||||
if (operation instanceof FieldsExposingAggregationOperation) {
|
||||
|
||||
FieldsExposingAggregationOperation exposedFieldsOperation = (FieldsExposingAggregationOperation) operation;
|
||||
ExposedFields fields = exposedFieldsOperation.getFields();
|
||||
|
||||
if (operation instanceof InheritsFieldsAggregationOperation) {
|
||||
contextToUse = new InheritingExposedFieldsAggregationOperationContext(fields, contextToUse);
|
||||
} else {
|
||||
contextToUse = fields.exposesNoFields() ? DEFAULT_CONTEXT
|
||||
: new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), contextToUse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return operationDocuments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple {@link AggregationOperationContext} that just returns {@link FieldReference}s as is.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class NoOpAggregationOperationContext implements AggregationOperationContext {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(org.bson.Document)
|
||||
*/
|
||||
@Override
|
||||
public Document getMappedObject(Document document) {
|
||||
return document;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(org.springframework.data.mongodb.core.aggregation.ExposedFields.AvailableField)
|
||||
*/
|
||||
@Override
|
||||
public FieldReference getReference(Field field) {
|
||||
return new DirectFieldReference(new ExposedField(field, true));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public FieldReference getReference(String name) {
|
||||
return new DirectFieldReference(new ExposedField(new AggregationField(name), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,48 +15,105 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.core.Collation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Holds a set of configurable aggregation options that can be used within an aggregation pipeline. A list of support
|
||||
* aggregation options can be found in the MongoDB reference documentation
|
||||
* http://docs.mongodb.org/manual/reference/command/aggregate/#aggregate
|
||||
*
|
||||
* https://docs.mongodb.org/manual/reference/command/aggregate/#aggregate
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @see Aggregation#withOptions(AggregationOptions)
|
||||
* @see TypedAggregation#withOptions(AggregationOptions)
|
||||
* @since 1.6
|
||||
*/
|
||||
public class AggregationOptions {
|
||||
|
||||
private static final String BATCH_SIZE = "batchSize";
|
||||
private static final String CURSOR = "cursor";
|
||||
private static final String EXPLAIN = "explain";
|
||||
private static final String ALLOW_DISK_USE = "allowDiskUse";
|
||||
private static final String COLLATION = "collation";
|
||||
|
||||
private final boolean allowDiskUse;
|
||||
private final boolean explain;
|
||||
private final Document cursor;
|
||||
private final Optional<Document> cursor;
|
||||
private final Optional<Collation> collation;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AggregationOptions}.
|
||||
*
|
||||
*
|
||||
* @param allowDiskUse whether to off-load intensive sort-operations to disk.
|
||||
* @param explain whether to get the execution plan for the aggregation instead of the actual results.
|
||||
* @param cursor can be {@literal null}, used to pass additional options to the aggregation.
|
||||
*/
|
||||
public AggregationOptions(boolean allowDiskUse, boolean explain, Document cursor) {
|
||||
this(allowDiskUse, explain, cursor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AggregationOptions}.
|
||||
*
|
||||
* @param allowDiskUse whether to off-load intensive sort-operations to disk.
|
||||
* @param explain whether to get the execution plan for the aggregation instead of the actual results.
|
||||
* @param cursor can be {@literal null}, used to pass additional options (such as {@code batchSize}) to the
|
||||
* aggregation.
|
||||
* @param collation collation for string comparison. Can be {@literal null}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public AggregationOptions(boolean allowDiskUse, boolean explain, Document cursor, Collation collation) {
|
||||
|
||||
this.allowDiskUse = allowDiskUse;
|
||||
this.explain = explain;
|
||||
this.cursor = cursor;
|
||||
this.cursor = Optional.ofNullable(cursor);
|
||||
this.collation = Optional.ofNullable(collation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AggregationOptions}.
|
||||
*
|
||||
* @param allowDiskUse whether to off-load intensive sort-operations to disk.
|
||||
* @param explain whether to get the execution plan for the aggregation instead of the actual results.
|
||||
* @param cursorBatchSize initial cursor batch size.
|
||||
* @since 2.0
|
||||
*/
|
||||
public AggregationOptions(boolean allowDiskUse, boolean explain, int cursorBatchSize) {
|
||||
this(allowDiskUse, explain, createCursor(cursorBatchSize), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationOptions} given {@link DBObject} containing aggregation options.
|
||||
*
|
||||
* @param document must not be {@literal null}.
|
||||
* @return the {@link AggregationOptions}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static AggregationOptions fromDocument(Document document) {
|
||||
|
||||
Assert.notNull(document, "Document must not be null!");
|
||||
|
||||
boolean allowDiskUse = document.getBoolean(ALLOW_DISK_USE, false);
|
||||
boolean explain = document.getBoolean(EXPLAIN, false);
|
||||
Document cursor = document.get(CURSOR, Document.class);
|
||||
Collation collation = document.containsKey(COLLATION) ? Collation.from(document.get(COLLATION, Document.class))
|
||||
: null;
|
||||
|
||||
return new AggregationOptions(allowDiskUse, explain, cursor, collation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables writing to temporary files. When set to true, aggregation stages can write data to the _tmp subdirectory in
|
||||
* the dbPath directory.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAllowDiskUse() {
|
||||
@@ -65,26 +122,51 @@ public class AggregationOptions {
|
||||
|
||||
/**
|
||||
* Specifies to return the information on the processing of the pipeline.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isExplain() {
|
||||
return explain;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial cursor batch size, if available, otherwise {@literal null}.
|
||||
*
|
||||
* @return the batch size or {@literal null}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public Integer getCursorBatchSize() {
|
||||
|
||||
if (cursor.filter(val -> val.containsKey(BATCH_SIZE)).isPresent()) {
|
||||
return cursor.get().get(BATCH_SIZE, Integer.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a document that contains options that control the creation of the cursor object.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Document getCursor() {
|
||||
public Optional<Document> getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get collation settings for string comparison.
|
||||
*
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
public Optional<Collation> getCollation() {
|
||||
return collation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new potentially adjusted copy for the given {@code aggregationCommandObject} with the configuration
|
||||
* applied.
|
||||
*
|
||||
*
|
||||
* @param command the aggregation command.
|
||||
* @return
|
||||
*/
|
||||
@@ -100,8 +182,12 @@ public class AggregationOptions {
|
||||
result.put(EXPLAIN, explain);
|
||||
}
|
||||
|
||||
if (cursor != null && !result.containsKey(CURSOR)) {
|
||||
result.put("cursor", cursor);
|
||||
if (!result.containsKey(CURSOR)) {
|
||||
cursor.ifPresent(val -> result.put(CURSOR, val));
|
||||
}
|
||||
|
||||
if (!result.containsKey(COLLATION)) {
|
||||
collation.map(Collation::toDocument).ifPresent(val -> result.append(COLLATION, val));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -109,7 +195,7 @@ public class AggregationOptions {
|
||||
|
||||
/**
|
||||
* Returns a {@link Document} representation of this {@link AggregationOptions}.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Document toDocument() {
|
||||
@@ -117,7 +203,9 @@ public class AggregationOptions {
|
||||
Document document = new Document();
|
||||
document.put(ALLOW_DISK_USE, allowDiskUse);
|
||||
document.put(EXPLAIN, explain);
|
||||
document.put(CURSOR, cursor);
|
||||
|
||||
cursor.ifPresent(val -> document.put(CURSOR, val));
|
||||
collation.ifPresent(val -> document.append(COLLATION, val.toDocument()));
|
||||
|
||||
return document;
|
||||
}
|
||||
@@ -130,20 +218,26 @@ public class AggregationOptions {
|
||||
return toDocument().toJson();
|
||||
}
|
||||
|
||||
static Document createCursor(int cursorBatchSize) {
|
||||
return new Document("batchSize", cursorBatchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* A Builder for {@link AggregationOptions}.
|
||||
*
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private boolean allowDiskUse;
|
||||
private boolean explain;
|
||||
private Document cursor;
|
||||
private Collation collation;
|
||||
|
||||
/**
|
||||
* Defines whether to off-load intensive sort-operations to disk.
|
||||
*
|
||||
*
|
||||
* @param allowDiskUse
|
||||
* @return
|
||||
*/
|
||||
@@ -155,7 +249,7 @@ public class AggregationOptions {
|
||||
|
||||
/**
|
||||
* Defines whether to get the execution plan for the aggregation instead of the actual results.
|
||||
*
|
||||
*
|
||||
* @param explain
|
||||
* @return
|
||||
*/
|
||||
@@ -167,7 +261,7 @@ public class AggregationOptions {
|
||||
|
||||
/**
|
||||
* Additional options to the aggregation.
|
||||
*
|
||||
*
|
||||
* @param cursor
|
||||
* @return
|
||||
*/
|
||||
@@ -177,13 +271,38 @@ public class AggregationOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the initial cursor batch size.
|
||||
*
|
||||
* @param batchSize
|
||||
* @return
|
||||
* @since 2.0
|
||||
*/
|
||||
public Builder cursorBatchSize(int batchSize) {
|
||||
|
||||
this.cursor = createCursor(batchSize);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define collation settings for string comparison.
|
||||
*
|
||||
* @param collation can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Builder collation(Collation collation) {
|
||||
|
||||
this.collation = collation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link AggregationOptions} instance with the given configuration.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public AggregationOptions build() {
|
||||
return new AggregationOptions(allowDiskUse, explain, cursor);
|
||||
return new AggregationOptions(allowDiskUse, explain, cursor, collation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,6 +29,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @param <T> The class in which the results are mapped onto.
|
||||
* @since 1.3
|
||||
*/
|
||||
@@ -46,8 +47,8 @@ public class AggregationResults<T> implements Iterable<T> {
|
||||
*/
|
||||
public AggregationResults(List<T> mappedResults, Document rawResults) {
|
||||
|
||||
Assert.notNull(mappedResults);
|
||||
Assert.notNull(rawResults);
|
||||
Assert.notNull(mappedResults, "List of mapped results must not be null!");
|
||||
Assert.notNull(rawResults, "Raw results must not be null!");
|
||||
|
||||
this.mappedResults = Collections.unmodifiableList(mappedResults);
|
||||
this.rawResults = rawResults;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AggregationExpression} that renders a MongoDB Aggregation Framework expression from the AST of a
|
||||
* <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html">SpEL
|
||||
* expression</a>. <br />
|
||||
* <br />
|
||||
* <strong>Samples:</strong> <br />
|
||||
* <code>
|
||||
* <pre>
|
||||
* // { $and: [ { $gt: [ "$qty", 100 ] }, { $lt: [ "$qty", 250 ] } ] }
|
||||
* expressionOf("qty > 100 && qty < 250);
|
||||
*
|
||||
* // { $cond : { if : { $gte : [ "$a", 42 ]}, then : "answer", else : "no-answer" } }
|
||||
* expressionOf("cond(a >= 42, 'answer', 'no-answer')");
|
||||
* </pre>
|
||||
* </code>
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @see SpelExpressionTransformer
|
||||
* @since 1.10
|
||||
*/
|
||||
public class AggregationSpELExpression implements AggregationExpression {
|
||||
|
||||
private static final SpelExpressionTransformer TRANSFORMER = new SpelExpressionTransformer();
|
||||
private final String rawExpression;
|
||||
private final Object[] parameters;
|
||||
|
||||
private AggregationSpELExpression(String rawExpression, Object[] parameters) {
|
||||
|
||||
this.rawExpression = rawExpression;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationSpELExpression} for the given {@literal expressionString} and {@literal parameters}.
|
||||
*
|
||||
* @param expressionString must not be {@literal null}.
|
||||
* @param parameters can be empty.
|
||||
* @return
|
||||
*/
|
||||
public static AggregationSpELExpression expressionOf(String expressionString, Object... parameters) {
|
||||
|
||||
Assert.notNull(expressionString, "ExpressionString must not be null!");
|
||||
return new AggregationSpELExpression(expressionString, parameters);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
return (Document) TRANSFORMER.transform(rawExpression, context, parameters);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Range;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility methods for aggregation operation implementations.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
interface AggregationUtils {
|
||||
|
||||
/**
|
||||
* Converts the given {@link Range} into an array of values.
|
||||
*
|
||||
* @param range must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static List<Long> toRangeValues(Range<Long> range) {
|
||||
|
||||
Assert.notNull(range, "Range must not be null!");
|
||||
|
||||
List<Long> result = new ArrayList<Long>(2);
|
||||
result.add(range.getLowerBound().getValue()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Lower bound of range must be bounded!")));
|
||||
range.getUpperBound().getValue().ifPresent(it -> result.add(it));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Gateway to {@literal boolean expressions} that evaluate their argument expressions as booleans and return a boolean
|
||||
* as the result.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public class BooleanOperators {
|
||||
|
||||
/**
|
||||
* Take the array referenced by given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static BooleanOperatorFactory valueOf(String fieldReference) {
|
||||
return new BooleanOperatorFactory(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the value resulting of the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static BooleanOperatorFactory valueOf(AggregationExpression fieldReference) {
|
||||
return new BooleanOperatorFactory(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates the boolean value of the referenced field and returns the
|
||||
* opposite boolean value.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Not not(String fieldReference) {
|
||||
return Not.not(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates the boolean value of {@link AggregationExpression} result
|
||||
* and returns the opposite boolean value.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Not not(AggregationExpression expression) {
|
||||
return Not.not(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class BooleanOperatorFactory {
|
||||
|
||||
private final String fieldReference;
|
||||
private final AggregationExpression expression;
|
||||
|
||||
/**
|
||||
* Creates new {@link BooleanOperatorFactory} for given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
*/
|
||||
public BooleanOperatorFactory(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
this.fieldReference = fieldReference;
|
||||
this.expression = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link BooleanOperatorFactory} for given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
*/
|
||||
public BooleanOperatorFactory(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
this.fieldReference = null;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates one or more expressions and returns {@literal true} if
|
||||
* all of the expressions are {@literal true}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public And and(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return createAnd().andExpression(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates one or more expressions and returns {@literal true} if
|
||||
* all of the expressions are {@literal true}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public And and(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return createAnd().andField(fieldReference);
|
||||
}
|
||||
|
||||
private And createAnd() {
|
||||
return usesFieldRef() ? And.and(Fields.field(fieldReference)) : And.and(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates one or more expressions and returns {@literal true} if
|
||||
* any of the expressions are {@literal true}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Or or(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return createOr().orExpression(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates one or more expressions and returns {@literal true} if
|
||||
* any of the expressions are {@literal true}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Or or(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return createOr().orField(fieldReference);
|
||||
}
|
||||
|
||||
private Or createOr() {
|
||||
return usesFieldRef() ? Or.or(Fields.field(fieldReference)) : Or.or(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates a boolean and returns the opposite boolean value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Not not() {
|
||||
return usesFieldRef() ? Not.not(fieldReference) : Not.not(expression);
|
||||
}
|
||||
|
||||
private boolean usesFieldRef() {
|
||||
return this.fieldReference != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $and}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class And extends AbstractAggregationExpression {
|
||||
|
||||
private And(List<?> values) {
|
||||
super(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$and";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link And} that evaluates one or more expressions and returns {@literal true} if all of the
|
||||
* expressions are {@literal true}.
|
||||
*
|
||||
* @param expressions
|
||||
* @return
|
||||
*/
|
||||
public static And and(Object... expressions) {
|
||||
return new And(Arrays.asList(expressions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link And} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public And andExpression(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new And(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link And} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public And andField(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new And(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link And} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public And andValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new And(append(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $or}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Or extends AbstractAggregationExpression {
|
||||
|
||||
private Or(List<?> values) {
|
||||
super(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$or";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Or} that evaluates one or more expressions and returns {@literal true} if any of the
|
||||
* expressions are {@literal true}.
|
||||
*
|
||||
* @param expressions must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Or or(Object... expressions) {
|
||||
|
||||
Assert.notNull(expressions, "Expressions must not be null!");
|
||||
return new Or(Arrays.asList(expressions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Or} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Or orExpression(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Or(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Or} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Or orField(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Or(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Or} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Or orValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Or(append(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $not}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Not extends AbstractAggregationExpression {
|
||||
|
||||
private Not(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$not";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Not} that evaluates the boolean value of the referenced field and returns the opposite boolean
|
||||
* value.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Not not(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Not(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Not} that evaluates the resulting boolean value of the given {@link AggregationExpression} and
|
||||
* returns the opposite boolean value.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Not not(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Not(Collections.singletonList(expression));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.BucketAutoOperation.BucketAutoOperationOutputBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $bucketAuto}-operation. <br />
|
||||
* Bucket stage is typically used with {@link Aggregation} and {@code $facet}. Categorizes incoming documents into a
|
||||
* specific number of groups, called buckets, based on a specified expression. Bucket boundaries are automatically
|
||||
* determined in an attempt to evenly distribute the documents into the specified number of buckets. <br />
|
||||
* We recommend to use the static factory method {@link Aggregation#bucketAuto(String, int)} instead of creating
|
||||
* instances of this class directly.
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.org/manual/reference/aggregation/bucketAuto/">https://docs.mongodb.org/manual/reference/aggregation/bucketAuto/</a>
|
||||
* @see BucketOperationSupport
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public class BucketAutoOperation extends BucketOperationSupport<BucketAutoOperation, BucketAutoOperationOutputBuilder>
|
||||
implements FieldsExposingAggregationOperation {
|
||||
|
||||
private final int buckets;
|
||||
private final String granularity;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperation} given a {@link Field group-by field}.
|
||||
*
|
||||
* @param groupByField must not be {@literal null}.
|
||||
* @param buckets number of buckets, must be a positive integer.
|
||||
*/
|
||||
public BucketAutoOperation(Field groupByField, int buckets) {
|
||||
|
||||
super(groupByField);
|
||||
|
||||
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0!");
|
||||
|
||||
this.buckets = buckets;
|
||||
this.granularity = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperation} given a {@link AggregationExpression group-by expression}.
|
||||
*
|
||||
* @param groupByExpression must not be {@literal null}.
|
||||
* @param buckets number of buckets, must be a positive integer.
|
||||
*/
|
||||
public BucketAutoOperation(AggregationExpression groupByExpression, int buckets) {
|
||||
|
||||
super(groupByExpression);
|
||||
|
||||
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0!");
|
||||
|
||||
this.buckets = buckets;
|
||||
this.granularity = null;
|
||||
}
|
||||
|
||||
private BucketAutoOperation(BucketAutoOperation bucketOperation, Outputs outputs) {
|
||||
|
||||
super(bucketOperation, outputs);
|
||||
|
||||
this.buckets = bucketOperation.buckets;
|
||||
this.granularity = bucketOperation.granularity;
|
||||
}
|
||||
|
||||
private BucketAutoOperation(BucketAutoOperation bucketOperation, int buckets, String granularity) {
|
||||
|
||||
super(bucketOperation);
|
||||
|
||||
this.buckets = buckets;
|
||||
this.granularity = granularity;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document options = new Document();
|
||||
|
||||
options.put("buckets", buckets);
|
||||
|
||||
if (granularity != null) {
|
||||
options.put("granularity", granularity);
|
||||
}
|
||||
|
||||
options.putAll(super.toDocument(context));
|
||||
|
||||
return new Document("$bucketAuto", options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a number of bucket {@literal buckets} and return a new {@link BucketAutoOperation}.
|
||||
*
|
||||
* @param buckets must be a positive number.
|
||||
* @return
|
||||
*/
|
||||
public BucketAutoOperation withBuckets(int buckets) {
|
||||
|
||||
Assert.isTrue(buckets > 0, "Number of buckets must be greater 0!");
|
||||
return new BucketAutoOperation(this, buckets, granularity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@link Granularity granularity} that specifies the preferred number series to use to ensure that the
|
||||
* calculated boundary edges end on preferred round numbers or their powers of 10 and return a new
|
||||
* {@link BucketAutoOperation}. <br />
|
||||
* Use either predefined {@link Granularities} or provide a own one.
|
||||
*
|
||||
* @param granularity must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public BucketAutoOperation withGranularity(Granularity granularity) {
|
||||
|
||||
Assert.notNull(granularity, "Granularity must not be null!");
|
||||
|
||||
return new BucketAutoOperation(this, buckets, granularity.getMongoRepresentation());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#newBucketOperation(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.Outputs)
|
||||
*/
|
||||
@Override
|
||||
protected BucketAutoOperation newBucketOperation(Outputs outputs) {
|
||||
return new BucketAutoOperation(this, outputs);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutputExpression(java.lang.String, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public ExpressionBucketAutoOperationBuilder andOutputExpression(String expression, Object... params) {
|
||||
return new ExpressionBucketAutoOperationBuilder(expression, this, params);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutput(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
|
||||
*/
|
||||
@Override
|
||||
public BucketAutoOperationOutputBuilder andOutput(AggregationExpression expression) {
|
||||
return new BucketAutoOperationOutputBuilder(expression, this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutput(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public BucketAutoOperationOutputBuilder andOutput(String fieldName) {
|
||||
return new BucketAutoOperationOutputBuilder(Fields.field(fieldName), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link OutputBuilder} implementation for {@link BucketAutoOperation}.
|
||||
*/
|
||||
public static class BucketAutoOperationOutputBuilder
|
||||
extends OutputBuilder<BucketAutoOperationOutputBuilder, BucketAutoOperation> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketAutoOperationOutputBuilder} fot the given value and {@link BucketAutoOperation}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
*/
|
||||
protected BucketAutoOperationOutputBuilder(Object value, BucketAutoOperation operation) {
|
||||
super(value, operation);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder#apply(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OperationOutput)
|
||||
*/
|
||||
@Override
|
||||
protected BucketAutoOperationOutputBuilder apply(OperationOutput operationOutput) {
|
||||
return new BucketAutoOperationOutputBuilder(operationOutput, this.operation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ExpressionBucketOperationBuilderSupport} implementation for {@link BucketAutoOperation} using SpEL
|
||||
* expression based {@link Output}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static class ExpressionBucketAutoOperationBuilder
|
||||
extends ExpressionBucketOperationBuilderSupport<BucketAutoOperationOutputBuilder, BucketAutoOperation> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionBucketAutoOperationBuilder} for the given value, {@link BucketAutoOperation} and
|
||||
* parameters.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
* @param parameters
|
||||
*/
|
||||
protected ExpressionBucketAutoOperationBuilder(String expression, BucketAutoOperation operation,
|
||||
Object[] parameters) {
|
||||
super(expression, operation, parameters);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder#apply(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OperationOutput)
|
||||
*/
|
||||
@Override
|
||||
protected BucketAutoOperationOutputBuilder apply(OperationOutput operationOutput) {
|
||||
return new BucketAutoOperationOutputBuilder(operationOutput, this.operation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface Granularity {
|
||||
|
||||
/**
|
||||
* @return a String that represents a MongoDB granularity to be used with {@link BucketAutoOperation}. Never
|
||||
* {@literal null}.
|
||||
*/
|
||||
String getMongoRepresentation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported MongoDB granularities.
|
||||
*
|
||||
* @see <a
|
||||
* href="https://docs.mongodb.com/manual/reference/operator/aggregation/bucketAuto/#granularity>https://docs.mongodb.com/manual/reference/operator/aggregation/bucketAuto/#granularity</a>
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public enum Granularities implements Granularity {
|
||||
|
||||
R5, R10, R20, R40, R80, //
|
||||
|
||||
SERIES_1_2_5("1-2-5"), //
|
||||
|
||||
E6, E12, E24, E48, E96, E192, //
|
||||
|
||||
POWERSOF2;
|
||||
|
||||
private final String granularity;
|
||||
|
||||
Granularities() {
|
||||
this.granularity = name();
|
||||
}
|
||||
|
||||
Granularities(String granularity) {
|
||||
this.granularity = granularity;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.GranularitytoMongoGranularity()
|
||||
*/
|
||||
@Override
|
||||
public String getMongoRepresentation() {
|
||||
return granularity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.BucketOperation.BucketOperationOutputBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $bucket}-operation. <br />
|
||||
*
|
||||
* Bucket stage is typically used with {@link Aggregation} and {@code $facet}. Categorizes incoming documents into
|
||||
* groups, called buckets, based on a specified expression and bucket boundaries. <br />
|
||||
*
|
||||
* We recommend to use the static factory method {@link Aggregation#bucket(String)} instead of creating instances of
|
||||
* this class directly.
|
||||
*
|
||||
* @see <a href="https://docs.mongodb.org/manual/reference/aggregation/bucket/">https://docs.mongodb.org/manual/reference/aggregation/bucket/</a>
|
||||
* @see BucketOperationSupport
|
||||
* @author Mark Paluch
|
||||
* @since 1.10
|
||||
*/
|
||||
public class BucketOperation extends BucketOperationSupport<BucketOperation, BucketOperationOutputBuilder>
|
||||
implements FieldsExposingAggregationOperation {
|
||||
|
||||
private final List<Object> boundaries;
|
||||
private final Object defaultBucket;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperation} given a {@link Field group-by field}.
|
||||
*
|
||||
* @param groupByField must not be {@literal null}.
|
||||
*/
|
||||
public BucketOperation(Field groupByField) {
|
||||
|
||||
super(groupByField);
|
||||
|
||||
this.boundaries = Collections.emptyList();
|
||||
this.defaultBucket = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperation} given a {@link AggregationExpression group-by expression}.
|
||||
*
|
||||
* @param groupByExpression must not be {@literal null}.
|
||||
*/
|
||||
public BucketOperation(AggregationExpression groupByExpression) {
|
||||
|
||||
super(groupByExpression);
|
||||
|
||||
this.boundaries = Collections.emptyList();
|
||||
this.defaultBucket = null;
|
||||
}
|
||||
|
||||
private BucketOperation(BucketOperation bucketOperation, Outputs outputs) {
|
||||
|
||||
super(bucketOperation, outputs);
|
||||
|
||||
this.boundaries = bucketOperation.boundaries;
|
||||
this.defaultBucket = bucketOperation.defaultBucket;
|
||||
}
|
||||
|
||||
private BucketOperation(BucketOperation bucketOperation, List<Object> boundaries, Object defaultBucket) {
|
||||
|
||||
super(bucketOperation);
|
||||
|
||||
this.boundaries = new ArrayList<Object>(boundaries);
|
||||
this.defaultBucket = defaultBucket;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document options = new Document();
|
||||
|
||||
options.put("boundaries", context.getMappedObject(new Document("$set", boundaries)).get("$set"));
|
||||
|
||||
if (defaultBucket != null) {
|
||||
options.put("default", context.getMappedObject(new Document("$set", defaultBucket)).get("$set"));
|
||||
}
|
||||
|
||||
options.putAll(super.toDocument(context));
|
||||
|
||||
return new Document("$bucket", options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a default bucket {@literal literal} and return a new {@link BucketOperation}.
|
||||
*
|
||||
* @param literal must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public BucketOperation withDefaultBucket(Object literal) {
|
||||
|
||||
Assert.notNull(literal, "Default bucket literal must not be null!");
|
||||
return new BucketOperation(this, boundaries, literal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@literal boundaries} and return a new {@link BucketOperation}. Existing {@literal boundaries} are
|
||||
* preserved and the new {@literal boundaries} are appended.
|
||||
*
|
||||
* @param boundaries must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public BucketOperation withBoundaries(Object... boundaries) {
|
||||
|
||||
Assert.notNull(boundaries, "Boundaries must not be null!");
|
||||
Assert.noNullElements(boundaries, "Boundaries must not contain null values!");
|
||||
|
||||
List<Object> newBoundaries = new ArrayList<Object>(this.boundaries.size() + boundaries.length);
|
||||
newBoundaries.addAll(this.boundaries);
|
||||
newBoundaries.addAll(Arrays.asList(boundaries));
|
||||
|
||||
return new BucketOperation(this, newBoundaries, defaultBucket);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#newBucketOperation(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.Outputs)
|
||||
*/
|
||||
@Override
|
||||
protected BucketOperation newBucketOperation(Outputs outputs) {
|
||||
return new BucketOperation(this, outputs);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutputExpression(java.lang.String, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public ExpressionBucketOperationBuilder andOutputExpression(String expression, Object... params) {
|
||||
return new ExpressionBucketOperationBuilder(expression, this, params);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutput(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
|
||||
*/
|
||||
@Override
|
||||
public BucketOperationOutputBuilder andOutput(AggregationExpression expression) {
|
||||
return new BucketOperationOutputBuilder(expression, this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport#andOutput(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public BucketOperationOutputBuilder andOutput(String fieldName) {
|
||||
return new BucketOperationOutputBuilder(Fields.field(fieldName), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link OutputBuilder} implementation for {@link BucketOperation}.
|
||||
*/
|
||||
public static class BucketOperationOutputBuilder
|
||||
extends BucketOperationSupport.OutputBuilder<BucketOperationOutputBuilder, BucketOperation> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperationOutputBuilder} fot the given value and {@link BucketOperation}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
*/
|
||||
protected BucketOperationOutputBuilder(Object value, BucketOperation operation) {
|
||||
super(value, operation);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder#apply(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OperationOutput)
|
||||
*/
|
||||
@Override
|
||||
protected BucketOperationOutputBuilder apply(OperationOutput operationOutput) {
|
||||
return new BucketOperationOutputBuilder(operationOutput, this.operation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ExpressionBucketOperationBuilderSupport} implementation for {@link BucketOperation} using SpEL expression
|
||||
* based {@link Output}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static class ExpressionBucketOperationBuilder
|
||||
extends ExpressionBucketOperationBuilderSupport<BucketOperationOutputBuilder, BucketOperation> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionBucketOperationBuilderSupport} for the given value, {@link BucketOperation}
|
||||
* and parameters.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
* @param parameters
|
||||
*/
|
||||
protected ExpressionBucketOperationBuilder(String expression, BucketOperation operation, Object[] parameters) {
|
||||
super(expression, operation, parameters);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder#apply(org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OperationOutput)
|
||||
*/
|
||||
@Override
|
||||
protected BucketOperationOutputBuilder apply(OperationOutput operationOutput) {
|
||||
return new BucketOperationOutputBuilder(operationOutput, this.operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,679 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.OutputBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder;
|
||||
import org.springframework.expression.spel.ast.Projection;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* Base class for bucket operations that support output expressions the aggregation framework. <br />
|
||||
* Bucket stages collect documents into buckets and can contribute output fields. <br />
|
||||
* Implementing classes are required to provide an {@link OutputBuilder}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public abstract class BucketOperationSupport<T extends BucketOperationSupport<T, B>, B extends OutputBuilder<B, T>>
|
||||
implements FieldsExposingAggregationOperation {
|
||||
|
||||
private final Field groupByField;
|
||||
private final AggregationExpression groupByExpression;
|
||||
private final Outputs outputs;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperationSupport} given a {@link Field group-by field}.
|
||||
*
|
||||
* @param groupByField must not be {@literal null}.
|
||||
*/
|
||||
protected BucketOperationSupport(Field groupByField) {
|
||||
|
||||
Assert.notNull(groupByField, "Group by field must not be null!");
|
||||
|
||||
this.groupByField = groupByField;
|
||||
this.groupByExpression = null;
|
||||
this.outputs = Outputs.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperationSupport} given a {@link AggregationExpression group-by expression}.
|
||||
*
|
||||
* @param groupByExpression must not be {@literal null}.
|
||||
*/
|
||||
protected BucketOperationSupport(AggregationExpression groupByExpression) {
|
||||
|
||||
Assert.notNull(groupByExpression, "Group by AggregationExpression must not be null!");
|
||||
|
||||
this.groupByExpression = groupByExpression;
|
||||
this.groupByField = null;
|
||||
this.outputs = Outputs.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of {@link BucketOperationSupport}.
|
||||
*
|
||||
* @param operationSupport must not be {@literal null}.
|
||||
*/
|
||||
protected BucketOperationSupport(BucketOperationSupport<?, ?> operationSupport) {
|
||||
this(operationSupport, operationSupport.outputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of {@link BucketOperationSupport} and applies the new {@link Outputs}.
|
||||
*
|
||||
* @param operationSupport must not be {@literal null}.
|
||||
* @param outputs must not be {@literal null}.
|
||||
*/
|
||||
protected BucketOperationSupport(BucketOperationSupport<?, ?> operationSupport, Outputs outputs) {
|
||||
|
||||
Assert.notNull(operationSupport, "BucketOperationSupport must not be null!");
|
||||
Assert.notNull(outputs, "Outputs must not be null!");
|
||||
|
||||
this.groupByField = operationSupport.groupByField;
|
||||
this.groupByExpression = operationSupport.groupByExpression;
|
||||
this.outputs = outputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionBucketOperationBuilderSupport} given a SpEL {@literal expression} and optional
|
||||
* {@literal params} to add an output field to the resulting bucket documents.
|
||||
*
|
||||
* @param expression the SpEL expression, must not be {@literal null} or empty.
|
||||
* @param params must not be {@literal null}
|
||||
* @return
|
||||
*/
|
||||
public abstract ExpressionBucketOperationBuilderSupport<B, T> andOutputExpression(String expression,
|
||||
Object... params);
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperationSupport} given an {@link AggregationExpression} to add an output field to the
|
||||
* resulting bucket documents.
|
||||
*
|
||||
* @param expression the SpEL expression, must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public abstract B andOutput(AggregationExpression expression);
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperationSupport} given {@literal fieldName} to add an output field to the resulting
|
||||
* bucket documents. {@link BucketOperationSupport} exposes accumulation operations that can be applied to
|
||||
* {@literal fieldName}.
|
||||
*
|
||||
* @param fieldName must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public abstract B andOutput(String fieldName);
|
||||
|
||||
/**
|
||||
* Creates a new {@link BucketOperationSupport} given to add a count field to the resulting bucket documents.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B andOutputCount() {
|
||||
return andOutput(new AggregationExpression() {
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
return new Document("$sum", 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document document = new Document();
|
||||
|
||||
document.put("groupBy", groupByExpression == null ? context.getReference(groupByField).toString()
|
||||
: groupByExpression.toDocument(context));
|
||||
|
||||
if (!outputs.isEmpty()) {
|
||||
document.put("output", outputs.toDocument(context));
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields()
|
||||
*/
|
||||
@Override
|
||||
public ExposedFields getFields() {
|
||||
return outputs.asExposedFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation hook to create a new bucket operation.
|
||||
*
|
||||
* @param outputs the outputs
|
||||
* @return the new bucket operation.
|
||||
*/
|
||||
protected abstract T newBucketOperation(Outputs outputs);
|
||||
|
||||
protected T andOutput(Output output) {
|
||||
return newBucketOperation(outputs.and(output));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for SpEL expression-based {@link Output}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract static class ExpressionBucketOperationBuilderSupport<B extends OutputBuilder<B, T>, T extends BucketOperationSupport<T, B>>
|
||||
extends OutputBuilder<B, T> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionBucketOperationBuilderSupport} for the given value, {@link BucketOperationSupport}
|
||||
* and parameters.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
* @param parameters
|
||||
*/
|
||||
protected ExpressionBucketOperationBuilderSupport(String expression, T operation, Object[] parameters) {
|
||||
super(new SpelExpressionOutput(expression, parameters), operation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for {@link Output} builders that result in a {@link BucketOperationSupport} providing the built
|
||||
* {@link Output}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract static class OutputBuilder<B extends OutputBuilder<B, T>, T extends BucketOperationSupport<T, B>> {
|
||||
|
||||
protected final Object value;
|
||||
protected final T operation;
|
||||
|
||||
/**
|
||||
* Creates a new {@link OutputBuilder} for the given value and {@link BucketOperationSupport}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @param operation must not be {@literal null}.
|
||||
*/
|
||||
protected OutputBuilder(Object value, T operation) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null or empty!");
|
||||
Assert.notNull(operation, "ProjectionOperation must not be null!");
|
||||
|
||||
this.value = value;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for a {@code $sum}-expression. <br />
|
||||
* Count expressions are emulated via {@code $sum: 1}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B count() {
|
||||
return sum(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for a {@code $sum}-expression for the current value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B sum() {
|
||||
return apply(Accumulators.SUM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for a {@code $sum}-expression for the given {@literal value}.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public B sum(Number value) {
|
||||
return apply(new OperationOutput(Accumulators.SUM.getMongoOperator(), Collections.singleton(value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for an {@code $last}-expression for the current value..
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B last() {
|
||||
return apply(Accumulators.LAST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for a {@code $first}-expression the current value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B first() {
|
||||
return apply(Accumulators.FIRST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for an {@code $avg}-expression for the current value.
|
||||
*
|
||||
* @param reference
|
||||
* @return
|
||||
*/
|
||||
public B avg() {
|
||||
return apply(Accumulators.AVG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for an {@code $min}-expression for the current value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B min() {
|
||||
return apply(Accumulators.MIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for an {@code $max}-expression for the current value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B max() {
|
||||
return apply(Accumulators.MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for an {@code $push}-expression for the current value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B push() {
|
||||
return apply(Accumulators.PUSH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a builder for an {@code $addToSet}-expression for the current value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public B addToSet() {
|
||||
return apply(Accumulators.ADDTOSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply an operator to the current value.
|
||||
*
|
||||
* @param operation the operation name, must not be {@literal null} or empty.
|
||||
* @param values must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public B apply(String operation, Object... values) {
|
||||
|
||||
Assert.hasText(operation, "Operation must not be empty or null!");
|
||||
Assert.notNull(value, "Values must not be null!");
|
||||
|
||||
List<Object> objects = new ArrayList<Object>(values.length + 1);
|
||||
objects.add(value);
|
||||
objects.addAll(Arrays.asList(values));
|
||||
return apply(new OperationOutput(operation, objects));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply an {@link OperationOutput} to this output.
|
||||
*
|
||||
* @param operationOutput must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected abstract B apply(OperationOutput operationOutput);
|
||||
|
||||
private B apply(Accumulators operation) {
|
||||
return this.apply(operation.getMongoOperator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the finally to be applied {@link BucketOperation} with the given alias.
|
||||
*
|
||||
* @param alias will never be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public T as(String alias) {
|
||||
|
||||
if (value instanceof OperationOutput) {
|
||||
return this.operation.andOutput(((OperationOutput) this.value).withAlias(alias));
|
||||
}
|
||||
|
||||
if (value instanceof Field) {
|
||||
throw new IllegalStateException("Cannot add a field as top-level output. Use accumulator expressions.");
|
||||
}
|
||||
|
||||
return this.operation
|
||||
.andOutput(new AggregationExpressionOutput(Fields.field(alias), (AggregationExpression) value));
|
||||
}
|
||||
}
|
||||
|
||||
private enum Accumulators {
|
||||
|
||||
SUM("$sum"), AVG("$avg"), FIRST("$first"), LAST("$last"), MAX("$max"), MIN("$min"), PUSH("$push"), ADDTOSET(
|
||||
"$addToSet");
|
||||
|
||||
private String mongoOperator;
|
||||
|
||||
Accumulators(String mongoOperator) {
|
||||
this.mongoOperator = mongoOperator;
|
||||
}
|
||||
|
||||
public String getMongoOperator() {
|
||||
return mongoOperator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates {@link Output}s.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
protected static class Outputs implements AggregationExpression {
|
||||
|
||||
protected static final Outputs EMPTY = new Outputs();
|
||||
|
||||
private List<Output> outputs;
|
||||
|
||||
/**
|
||||
* Creates a new, empty {@link Outputs}.
|
||||
*/
|
||||
private Outputs() {
|
||||
this.outputs = new ArrayList<Output>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Outputs} containing all given {@link Output}s.
|
||||
*
|
||||
* @param current
|
||||
* @param output
|
||||
*/
|
||||
private Outputs(Collection<Output> current, Output output) {
|
||||
|
||||
this.outputs = new ArrayList<Output>(current.size() + 1);
|
||||
this.outputs.addAll(current);
|
||||
this.outputs.add(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link ExposedFields} derived from {@link Output}.
|
||||
*/
|
||||
protected ExposedFields asExposedFields() {
|
||||
|
||||
// The count field is included by default when the output is not specified.
|
||||
if (isEmpty()) {
|
||||
return ExposedFields.from(new ExposedField("count", true));
|
||||
}
|
||||
|
||||
ExposedFields fields = ExposedFields.from();
|
||||
|
||||
for (Output output : outputs) {
|
||||
fields = fields.and(output.getExposedField());
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Outputs} that contains the new {@link Output}.
|
||||
*
|
||||
* @param output must not be {@literal null}.
|
||||
* @return the new {@link Outputs} that contains the new {@link Output}
|
||||
*/
|
||||
protected Outputs and(Output output) {
|
||||
|
||||
Assert.notNull(output, "BucketOutput must not be null!");
|
||||
return new Outputs(this.outputs, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if {@link Outputs} contains no {@link Output}.
|
||||
*/
|
||||
protected boolean isEmpty() {
|
||||
return outputs.isEmpty();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document document = new Document();
|
||||
|
||||
for (Output output : outputs) {
|
||||
document.put(output.getExposedField().getName(), output.toDocument(context));
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates an output field in a bucket aggregation stage. <br />
|
||||
* Output fields can be either top-level fields that define a valid field name or nested output fields using
|
||||
* operators.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
protected abstract static class Output implements AggregationExpression {
|
||||
|
||||
private final ExposedField field;
|
||||
|
||||
/**
|
||||
* Creates new {@link Projection} for the given {@link Field}.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
*/
|
||||
protected Output(Field field) {
|
||||
|
||||
Assert.notNull(field, "Field must not be null!");
|
||||
this.field = new ExposedField(field, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field exposed by the {@link Output}.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
protected ExposedField getExposedField() {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output field that uses a Mongo operation (expression object) to generate an output field value. <br />
|
||||
* {@link OperationOutput} is used either with a regular field name or an operation keyword (e.g.
|
||||
* {@literal $sum, $count}).
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
protected static class OperationOutput extends Output {
|
||||
|
||||
private final String operation;
|
||||
private final List<Object> values;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Output} for the given field.
|
||||
*
|
||||
* @param operation the actual operation key, must not be {@literal null} or empty.
|
||||
* @param values the values to pass into the operation, must not be {@literal null}.
|
||||
*/
|
||||
public OperationOutput(String operation, Collection<? extends Object> values) {
|
||||
|
||||
super(Fields.field(operation));
|
||||
|
||||
Assert.hasText(operation, "Operation must not be null or empty!");
|
||||
Assert.notNull(values, "Values must not be null!");
|
||||
|
||||
this.operation = operation;
|
||||
this.values = new ArrayList<Object>(values);
|
||||
}
|
||||
|
||||
private OperationOutput(Field field, OperationOutput operationOutput) {
|
||||
|
||||
super(field);
|
||||
|
||||
this.operation = operationOutput.operation;
|
||||
this.values = operationOutput.values;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ProjectionOperation.Projection#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
List<Object> operationArguments = getOperationArguments(context);
|
||||
return new Document(operation,
|
||||
operationArguments.size() == 1 ? operationArguments.get(0) : operationArguments);
|
||||
}
|
||||
|
||||
protected List<Object> getOperationArguments(AggregationOperationContext context) {
|
||||
|
||||
List<Object> result = new ArrayList<Object>(values != null ? values.size() : 1);
|
||||
|
||||
for (Object element : values) {
|
||||
|
||||
if (element instanceof Field) {
|
||||
result.add(context.getReference((Field) element).toString());
|
||||
} else if (element instanceof Fields) {
|
||||
for (Field field : (Fields) element) {
|
||||
result.add(context.getReference(field).toString());
|
||||
}
|
||||
} else if (element instanceof AggregationExpression) {
|
||||
result.add(((AggregationExpression) element).toDocument(context));
|
||||
} else {
|
||||
result.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field that holds the {@link ProjectionOperationBuilder.OperationProjection}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected Field getField() {
|
||||
return getExposedField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this {@link OperationOutput} with the given alias.
|
||||
*
|
||||
* @param alias the alias to set
|
||||
* @return
|
||||
*/
|
||||
public OperationOutput withAlias(String alias) {
|
||||
|
||||
final Field aliasedField = Fields.field(alias);
|
||||
return new OperationOutput(aliasedField, this) {
|
||||
|
||||
@Override
|
||||
protected Field getField() {
|
||||
return aliasedField;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Object> getOperationArguments(AggregationOperationContext context) {
|
||||
|
||||
// We have to make sure that we use the arguments from the "previous" OperationOutput that we replace
|
||||
// with this new instance.
|
||||
return OperationOutput.this.getOperationArguments(context);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link Output} based on a SpEL expression.
|
||||
*/
|
||||
private static class SpelExpressionOutput extends Output {
|
||||
|
||||
private static final SpelExpressionTransformer TRANSFORMER = new SpelExpressionTransformer();
|
||||
|
||||
private final String expression;
|
||||
private final Object[] params;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpelExpressionOutput} for the given field, SpEL expression and parameters.
|
||||
*
|
||||
* @param expression must not be {@literal null} or empty.
|
||||
* @param parameters must not be {@literal null}.
|
||||
*/
|
||||
public SpelExpressionOutput(String expression, Object[] parameters) {
|
||||
|
||||
super(Fields.field(expression));
|
||||
|
||||
Assert.hasText(expression, "Expression must not be null!");
|
||||
Assert.notNull(parameters, "Parameters must not be null!");
|
||||
|
||||
this.expression = expression;
|
||||
this.params = parameters.clone();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.Output#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
return (Document) TRANSFORMER.transform(expression, context, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
private static class AggregationExpressionOutput extends Output {
|
||||
|
||||
private final AggregationExpression expression;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AggregationExpressionOutput}.
|
||||
*
|
||||
* @param field
|
||||
* @param expression
|
||||
*/
|
||||
protected AggregationExpressionOutput(Field field, AggregationExpression expression) {
|
||||
|
||||
super(field);
|
||||
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.Output#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
return expression.toDocument(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,879 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Gateway to {@literal comparison expressions}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public class ComparisonOperators {
|
||||
|
||||
/**
|
||||
* Take the field referenced by given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ComparisonOperatorFactory valueOf(String fieldReference) {
|
||||
return new ComparisonOperatorFactory(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the value resulting from the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ComparisonOperatorFactory valueOf(AggregationExpression expression) {
|
||||
return new ComparisonOperatorFactory(expression);
|
||||
}
|
||||
|
||||
public static class ComparisonOperatorFactory {
|
||||
|
||||
private final String fieldReference;
|
||||
private final AggregationExpression expression;
|
||||
|
||||
/**
|
||||
* Creates new {@link ComparisonOperatorFactory} for given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
*/
|
||||
public ComparisonOperatorFactory(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
this.fieldReference = fieldReference;
|
||||
this.expression = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link ComparisonOperatorFactory} for given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
*/
|
||||
public ComparisonOperatorFactory(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
this.fieldReference = null;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Cmp compareTo(String fieldReference) {
|
||||
return createCmp().compareTo(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Cmp compareTo(AggregationExpression expression) {
|
||||
return createCmp().compareTo(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Cmp compareToValue(Object value) {
|
||||
return createCmp().compareToValue(value);
|
||||
}
|
||||
|
||||
private Cmp createCmp() {
|
||||
return usesFieldRef() ? Cmp.valueOf(fieldReference) : Cmp.valueOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is equal to the value of the referenced field.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Eq equalTo(String fieldReference) {
|
||||
return createEq().equalTo(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is equal to the expression result.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Eq equalTo(AggregationExpression expression) {
|
||||
return createEq().equalTo(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is equal to the given value.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Eq equalToValue(Object value) {
|
||||
return createEq().equalToValue(value);
|
||||
}
|
||||
|
||||
private Eq createEq() {
|
||||
return usesFieldRef() ? Eq.valueOf(fieldReference) : Eq.valueOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is greater than the value of the referenced field.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gt greaterThan(String fieldReference) {
|
||||
return createGt().greaterThan(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is greater than the expression result.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gt greaterThan(AggregationExpression expression) {
|
||||
return createGt().greaterThan(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is greater than the given value.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gt greaterThanValue(Object value) {
|
||||
return createGt().greaterThanValue(value);
|
||||
}
|
||||
|
||||
private Gt createGt() {
|
||||
return usesFieldRef() ? Gt.valueOf(fieldReference) : Gt.valueOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is greater than or equivalent to the value of the referenced field.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gte greaterThanEqualTo(String fieldReference) {
|
||||
return createGte().greaterThanEqualTo(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is greater than or equivalent to the expression result.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gte greaterThanEqualTo(AggregationExpression expression) {
|
||||
return createGte().greaterThanEqualTo(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is greater than or equivalent to the given value.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gte greaterThanEqualToValue(Object value) {
|
||||
return createGte().greaterThanEqualToValue(value);
|
||||
}
|
||||
|
||||
private Gte createGte() {
|
||||
return usesFieldRef() ? Gte.valueOf(fieldReference) : Gte.valueOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is less than the value of the referenced field.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lt lessThan(String fieldReference) {
|
||||
return createLt().lessThan(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is less than the expression result.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lt lessThan(AggregationExpression expression) {
|
||||
return createLt().lessThan(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is less than to the given value.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lt lessThanValue(Object value) {
|
||||
return createLt().lessThanValue(value);
|
||||
}
|
||||
|
||||
private Lt createLt() {
|
||||
return usesFieldRef() ? Lt.valueOf(fieldReference) : Lt.valueOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is less than or equivalent to the value of the referenced field.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lte lessThanEqualTo(String fieldReference) {
|
||||
return createLte().lessThanEqualTo(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is less than or equivalent to the expression result.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lte lessThanEqualTo(AggregationExpression expression) {
|
||||
return createLte().lessThanEqualTo(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the first
|
||||
* value is less than or equivalent to the given value.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public Lte lessThanEqualToValue(Object value) {
|
||||
return createLte().lessThanEqualToValue(value);
|
||||
}
|
||||
|
||||
private Lte createLte() {
|
||||
return usesFieldRef() ? Lte.valueOf(fieldReference) : Lte.valueOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the values
|
||||
* are not equivalent.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Ne notEqualTo(String fieldReference) {
|
||||
return createNe().notEqualTo(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the values
|
||||
* are not equivalent.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Ne notEqualTo(AggregationExpression expression) {
|
||||
return createNe().notEqualTo(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that compares two values and returns {@literal true} when the values
|
||||
* are not equivalent.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Ne notEqualToValue(Object value) {
|
||||
return createNe().notEqualToValue(value);
|
||||
}
|
||||
|
||||
private Ne createNe() {
|
||||
return usesFieldRef() ? Ne.valueOf(fieldReference) : Ne.valueOf(expression);
|
||||
}
|
||||
|
||||
private boolean usesFieldRef() {
|
||||
return fieldReference != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $cmp}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Cmp extends AbstractAggregationExpression {
|
||||
|
||||
private Cmp(List<?> value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$cmp";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Cmp}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Cmp valueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Cmp(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Cmp}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Cmp valueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Cmp(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Cmp} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Cmp compareTo(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Cmp(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Cmp} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Cmp compareTo(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Cmp(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Cmp} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Cmp compareToValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Cmp(append(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $eq}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Eq extends AbstractAggregationExpression {
|
||||
|
||||
private Eq(List<?> value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$eq";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Eq}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Eq valueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Eq(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Eq}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Eq valueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Eq(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Eq} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Eq equalTo(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Eq(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Eq} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Eq equalTo(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Eq(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Eq} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Eq equalToValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Eq(append(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $gt}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Gt extends AbstractAggregationExpression {
|
||||
|
||||
private Gt(List<?> value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$gt";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gt}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Gt valueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Gt(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gt}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Gt valueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Gt(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gt} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gt greaterThan(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Gt(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gt} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gt greaterThan(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Gt(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gt} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gt greaterThanValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Gt(append(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $lt}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Lt extends AbstractAggregationExpression {
|
||||
|
||||
private Lt(List<?> value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$lt";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lt}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Lt valueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Lt(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lt}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Lt valueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Lt(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lt} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lt lessThan(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Lt(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lt} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lt lessThan(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Lt(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lt} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lt lessThanValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Lt(append(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $gte}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Gte extends AbstractAggregationExpression {
|
||||
|
||||
private Gte(List<?> value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$gte";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gte}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Gte valueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Gte(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gte}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Gte valueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Gte(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gte} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gte greaterThanEqualTo(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Gte(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gte} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gte greaterThanEqualTo(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Gte(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Gte} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Gte greaterThanEqualToValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Gte(append(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $lte}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Lte extends AbstractAggregationExpression {
|
||||
|
||||
private Lte(List<?> value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$lte";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lte}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Lte valueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Lte(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lte}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Lte valueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Lte(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lte} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lte lessThanEqualTo(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Lte(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lte} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lte lessThanEqualTo(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Lte(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Lte} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Lte lessThanEqualToValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Lte(append(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $ne}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Ne extends AbstractAggregationExpression {
|
||||
|
||||
private Ne(List<?> value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$ne";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Ne}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Ne valueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Ne(asFields(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Ne}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Ne valueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Ne(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Ne} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Ne notEqualTo(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Ne(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Ne} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Ne notEqualTo(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Ne(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Eq} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Ne notEqualToValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Ne(append(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,392 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $cond} operator. A {@link ConditionalOperator} allows nested conditions
|
||||
* {@code if-then[if-then-else]-else} using {@link Field}, {@link CriteriaDefinition} or a {@link Document custom}
|
||||
* condition. Replacement values can be either {@link Field field references}, values of simple MongoDB types or values
|
||||
* that can be converted to a simple MongoDB type.
|
||||
*
|
||||
* @see http://docs.mongodb.com/manual/reference/operator/aggregation/cond/
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public class ConditionalOperator implements AggregationExpression {
|
||||
|
||||
private final Object condition;
|
||||
private final Object thenValue;
|
||||
private final Object otherwiseValue;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConditionalOperator} for a given {@link Field} and {@code then}/{@code otherwise} values.
|
||||
*
|
||||
* @param condition must not be {@literal null}.
|
||||
* @param thenValue must not be {@literal null}.
|
||||
* @param otherwiseValue must not be {@literal null}.
|
||||
*/
|
||||
public ConditionalOperator(Field condition, Object thenValue, Object otherwiseValue) {
|
||||
this((Object) condition, thenValue, otherwiseValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConditionalOperator} for a given {@link CriteriaDefinition} and {@code then}/{@code otherwise}
|
||||
* values.
|
||||
*
|
||||
* @param condition must not be {@literal null}.
|
||||
* @param thenValue must not be {@literal null}.
|
||||
* @param otherwiseValue must not be {@literal null}.
|
||||
*/
|
||||
public ConditionalOperator(CriteriaDefinition condition, Object thenValue, Object otherwiseValue) {
|
||||
this((Object) condition, thenValue, otherwiseValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConditionalOperator} for a given {@link Document criteria} and {@code then}/{@code otherwise}
|
||||
* values.
|
||||
*
|
||||
* @param condition must not be {@literal null}.
|
||||
* @param thenValue must not be {@literal null}.
|
||||
* @param otherwiseValue must not be {@literal null}.
|
||||
*/
|
||||
public ConditionalOperator(Document condition, Object thenValue, Object otherwiseValue) {
|
||||
this((Object) condition, thenValue, otherwiseValue);
|
||||
}
|
||||
|
||||
private ConditionalOperator(Object condition, Object thenValue, Object otherwiseValue) {
|
||||
|
||||
Assert.notNull(condition, "Condition must not be null!");
|
||||
Assert.notNull(thenValue, "'Then value' must not be null!");
|
||||
Assert.notNull(otherwiseValue, "'Otherwise value' must not be null!");
|
||||
|
||||
assertNotBuilder(condition, "Condition");
|
||||
assertNotBuilder(thenValue, "'Then value'");
|
||||
assertNotBuilder(otherwiseValue, "'Otherwise value'");
|
||||
|
||||
this.condition = condition;
|
||||
this.thenValue = thenValue;
|
||||
this.otherwiseValue = otherwiseValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document condObject = new Document();
|
||||
|
||||
condObject.append("if", resolveCriteria(context, condition));
|
||||
condObject.append("then", resolveValue(context, thenValue));
|
||||
condObject.append("else", resolveValue(context, otherwiseValue));
|
||||
|
||||
return new Document("$cond", condObject);
|
||||
}
|
||||
|
||||
private Object resolveValue(AggregationOperationContext context, Object value) {
|
||||
|
||||
if (value instanceof Document || value instanceof Field) {
|
||||
return resolve(context, value);
|
||||
}
|
||||
|
||||
if (value instanceof ConditionalOperator) {
|
||||
return ((ConditionalOperator) value).toDocument(context);
|
||||
}
|
||||
|
||||
return context.getMappedObject(new Document("$set", value)).get("$set");
|
||||
}
|
||||
|
||||
private Object resolveCriteria(AggregationOperationContext context, Object value) {
|
||||
|
||||
if (value instanceof Document || value instanceof Field) {
|
||||
return resolve(context, value);
|
||||
}
|
||||
|
||||
if (value instanceof CriteriaDefinition) {
|
||||
|
||||
Document mappedObject = context.getMappedObject(((CriteriaDefinition) value).getCriteriaObject());
|
||||
List<Object> clauses = new ArrayList<Object>();
|
||||
|
||||
clauses.addAll(getClauses(context, mappedObject));
|
||||
|
||||
if (clauses.size() == 1) {
|
||||
return clauses.get(0);
|
||||
}
|
||||
|
||||
return clauses;
|
||||
}
|
||||
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
String.format("Invalid value in condition. Supported: Document, Field references, Criteria, got: %s", value));
|
||||
}
|
||||
|
||||
private List<Object> getClauses(AggregationOperationContext context, Document mappedObject) {
|
||||
|
||||
List<Object> clauses = new ArrayList<Object>();
|
||||
|
||||
for (String key : mappedObject.keySet()) {
|
||||
|
||||
Object predicate = mappedObject.get(key);
|
||||
clauses.addAll(getClauses(context, key, predicate));
|
||||
}
|
||||
|
||||
return clauses;
|
||||
}
|
||||
|
||||
private List<Object> getClauses(AggregationOperationContext context, String key, Object predicate) {
|
||||
|
||||
List<Object> clauses = new ArrayList<Object>();
|
||||
|
||||
if (predicate instanceof List) {
|
||||
|
||||
List<Object> args = new ArrayList<Object>();
|
||||
for (Object clause : (List<?>) predicate) {
|
||||
if (clause instanceof Document) {
|
||||
args.addAll(getClauses(context, (Document) clause));
|
||||
}
|
||||
}
|
||||
|
||||
clauses.add(new Document(key, args));
|
||||
|
||||
} else if (predicate instanceof Document) {
|
||||
|
||||
Document nested = (Document) predicate;
|
||||
|
||||
for (String s : nested.keySet()) {
|
||||
|
||||
if (!isKeyword(s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Object> args = new ArrayList<Object>();
|
||||
args.add("$" + key);
|
||||
args.add(nested.get(s));
|
||||
clauses.add(new Document(s, args));
|
||||
}
|
||||
|
||||
} else if (!isKeyword(key)) {
|
||||
|
||||
List<Object> args = new ArrayList<Object>();
|
||||
args.add("$" + key);
|
||||
args.add(predicate);
|
||||
clauses.add(new Document("$eq", args));
|
||||
}
|
||||
|
||||
return clauses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link String} is a MongoDB keyword.
|
||||
*
|
||||
* @param candidate
|
||||
* @return
|
||||
*/
|
||||
private boolean isKeyword(String candidate) {
|
||||
return candidate.startsWith("$");
|
||||
}
|
||||
|
||||
private Object resolve(AggregationOperationContext context, Object value) {
|
||||
|
||||
if (value instanceof Document) {
|
||||
return context.getMappedObject((Document) value);
|
||||
}
|
||||
|
||||
return context.getReference((Field) value).toString();
|
||||
}
|
||||
|
||||
private void assertNotBuilder(Object toCheck, String name) {
|
||||
Assert.isTrue(!ClassUtils.isAssignableValue(ConditionalExpressionBuilder.class, toCheck),
|
||||
String.format("%s must not be of type %s", name, ConditionalExpressionBuilder.class.getSimpleName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builder that allows fluent creation of {@link ConditionalOperator}.
|
||||
*
|
||||
* @return a new {@link ConditionalExpressionBuilder}.
|
||||
*/
|
||||
public static ConditionalExpressionBuilder newBuilder() {
|
||||
return ConditionalExpressionBuilder.newBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.10
|
||||
*/
|
||||
public static interface WhenBuilder {
|
||||
|
||||
/**
|
||||
* @param booleanExpression expression that yields in a boolean result, must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder when(Document booleanExpression);
|
||||
|
||||
/**
|
||||
* @param booleanField reference to a field holding a boolean value, must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder when(Field booleanField);
|
||||
|
||||
/**
|
||||
* @param booleanField name of a field holding a boolean value, must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder when(String booleanField);
|
||||
|
||||
/**
|
||||
* @param criteria criteria to evaluate, must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder when(CriteriaDefinition criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.10
|
||||
*/
|
||||
public static interface ThenBuilder {
|
||||
|
||||
/**
|
||||
* @param value the value to be used if the condition evaluates {@literal true}. Can be a {@link Document}, a value
|
||||
* that is supported by MongoDB or a value that can be converted to a MongoDB representation but must not
|
||||
* be {@literal null}.
|
||||
* @return the {@link OtherwiseBuilder}
|
||||
*/
|
||||
OtherwiseBuilder then(Object value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.10
|
||||
*/
|
||||
public static interface OtherwiseBuilder {
|
||||
|
||||
/**
|
||||
* @param value the value to be used if the condition evaluates {@literal false}. Can be a {@link Document}, a value
|
||||
* that is supported by MongoDB or a value that can be converted to a MongoDB representation but must not
|
||||
* be {@literal null}.
|
||||
* @return the {@link ConditionalOperator}
|
||||
*/
|
||||
ConditionalOperator otherwise(Object value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for fluent {@link ConditionalOperator} creation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.10
|
||||
*/
|
||||
public static final class ConditionalExpressionBuilder implements WhenBuilder, ThenBuilder, OtherwiseBuilder {
|
||||
|
||||
private Object condition;
|
||||
private Object thenValue;
|
||||
|
||||
private ConditionalExpressionBuilder() {}
|
||||
|
||||
/**
|
||||
* Creates a new builder for {@link ConditionalOperator}.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public static ConditionalExpressionBuilder newBuilder() {
|
||||
return new ConditionalExpressionBuilder();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.WhenBuilder#when(org.bson.Document)
|
||||
*/
|
||||
@Override
|
||||
public ConditionalExpressionBuilder when(Document booleanExpression) {
|
||||
|
||||
Assert.notNull(booleanExpression, "'Boolean expression' must not be null!");
|
||||
|
||||
this.condition = booleanExpression;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.WhenBuilder#when(org.springframework.data.mongodb.core.query.CriteriaDefinition)
|
||||
*/
|
||||
@Override
|
||||
public ThenBuilder when(CriteriaDefinition criteria) {
|
||||
|
||||
Assert.notNull(criteria, "Criteria must not be null!");
|
||||
|
||||
this.condition = criteria;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.WhenBuilder#when(org.springframework.data.mongodb.core.aggregation.Field)
|
||||
*/
|
||||
@Override
|
||||
public ThenBuilder when(Field booleanField) {
|
||||
|
||||
Assert.notNull(booleanField, "Boolean field must not be null!");
|
||||
|
||||
this.condition = booleanField;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.WhenBuilder#when(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ThenBuilder when(String booleanField) {
|
||||
|
||||
Assert.hasText(booleanField, "Boolean field name must not be null or empty!");
|
||||
|
||||
this.condition = Fields.field(booleanField);
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.ThenBuilder#then(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public OtherwiseBuilder then(Object thenValue) {
|
||||
|
||||
Assert.notNull(thenValue, "'Then-value' must not be null!");
|
||||
|
||||
this.thenValue = thenValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperator.OtherwiseBuilder#otherwise(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public ConditionalOperator otherwise(Object otherwiseValue) {
|
||||
|
||||
Assert.notNull(otherwiseValue, "'Otherwise-value' must not be null!");
|
||||
|
||||
return new ConditionalOperator(condition, thenValue, otherwiseValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,976 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.OtherwiseBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.ThenBuilder;
|
||||
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Switch.CaseOperator;
|
||||
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Gateway to {@literal conditional expressions} that evaluate their argument expressions as booleans to a value.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.10
|
||||
*/
|
||||
public class ConditionalOperators {
|
||||
|
||||
/**
|
||||
* Take the field referenced by given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ConditionalOperatorFactory when(String fieldReference) {
|
||||
return new ConditionalOperatorFactory(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the value resulting from the given {@literal expression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ConditionalOperatorFactory when(AggregationExpression expression) {
|
||||
return new ConditionalOperatorFactory(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the value resulting from the given {@literal criteriaDefinition}.
|
||||
*
|
||||
* @param criteriaDefinition must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ConditionalOperatorFactory when(CriteriaDefinition criteriaDefinition) {
|
||||
return new ConditionalOperatorFactory(criteriaDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates an expression and returns the value of the expression if
|
||||
* the expression evaluates to a non-null value. If the expression evaluates to a {@literal null} value, including
|
||||
* instances of undefined values or missing fields, returns the value of the replacement expression.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static IfNull.ThenBuilder ifNull(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return IfNull.ifNull(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates an expression and returns the value of the expression if
|
||||
* the expression evaluates to a non-null value. If the expression evaluates to a {@literal null} value, including
|
||||
* instances of undefined values or missing fields, returns the value of the replacement expression.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static IfNull.ThenBuilder ifNull(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return IfNull.ifNull(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates a series of {@link CaseOperator} expressions. When it
|
||||
* finds an expression which evaluates to {@literal true}, {@code $switch} executes a specified expression and breaks
|
||||
* out of the control flow.
|
||||
*
|
||||
* @param conditions must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Switch switchCases(CaseOperator... conditions) {
|
||||
return Switch.switchCases(conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates a series of {@link CaseOperator} expressions. When it
|
||||
* finds an expression which evaluates to {@literal true}, {@code $switch} executes a specified expression and breaks
|
||||
* out of the control flow.
|
||||
*
|
||||
* @param conditions must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Switch switchCases(List<CaseOperator> conditions) {
|
||||
return Switch.switchCases(conditions);
|
||||
}
|
||||
|
||||
public static class ConditionalOperatorFactory {
|
||||
|
||||
private final String fieldReference;
|
||||
private final AggregationExpression expression;
|
||||
private final CriteriaDefinition criteriaDefinition;
|
||||
|
||||
/**
|
||||
* Creates new {@link ConditionalOperatorFactory} for given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
*/
|
||||
public ConditionalOperatorFactory(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
|
||||
this.fieldReference = fieldReference;
|
||||
this.expression = null;
|
||||
this.criteriaDefinition = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link ConditionalOperatorFactory} for given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
*/
|
||||
public ConditionalOperatorFactory(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
|
||||
this.fieldReference = null;
|
||||
this.expression = expression;
|
||||
this.criteriaDefinition = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link ConditionalOperatorFactory} for given {@link CriteriaDefinition}.
|
||||
*
|
||||
* @param criteriaDefinition must not be {@literal null}.
|
||||
*/
|
||||
public ConditionalOperatorFactory(CriteriaDefinition criteriaDefinition) {
|
||||
|
||||
Assert.notNull(criteriaDefinition, "CriteriaDefinition must not be null!");
|
||||
|
||||
this.fieldReference = null;
|
||||
this.expression = null;
|
||||
this.criteriaDefinition = criteriaDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates a boolean expression to return one of the two specified
|
||||
* return expressions.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public OtherwiseBuilder then(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return createThenBuilder().then(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates a boolean expression to return one of the two specified
|
||||
* return expressions.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public OtherwiseBuilder thenValueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return createThenBuilder().then(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that evaluates a boolean expression to return one of the two specified
|
||||
* return expressions.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public OtherwiseBuilder thenValueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return createThenBuilder().then(fieldReference);
|
||||
}
|
||||
|
||||
private ThenBuilder createThenBuilder() {
|
||||
|
||||
if (usesFieldRef()) {
|
||||
return Cond.newBuilder().when(fieldReference);
|
||||
}
|
||||
|
||||
return usesCriteriaDefinition() ? Cond.newBuilder().when(criteriaDefinition) : Cond.newBuilder().when(expression);
|
||||
}
|
||||
|
||||
private boolean usesFieldRef() {
|
||||
return this.fieldReference != null;
|
||||
}
|
||||
|
||||
private boolean usesCriteriaDefinition() {
|
||||
return this.criteriaDefinition != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $ifNull} operator. Replacement values can be either {@link Field
|
||||
* field references}, {@link AggregationExpression expressions}, values of simple MongoDB types or values that can be
|
||||
* converted to a simple MongoDB type.
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/ifNull/">https://docs.mongodb.com/manual/reference/operator/aggregation/ifNull/</a>
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static class IfNull implements AggregationExpression {
|
||||
|
||||
private final Object condition;
|
||||
private final Object value;
|
||||
|
||||
private IfNull(Object condition, Object value) {
|
||||
|
||||
this.condition = condition;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link IfNull}.
|
||||
*
|
||||
* @param fieldReference the field to check for a {@literal null} value, field reference must not be {@literal null}
|
||||
* .
|
||||
* @return
|
||||
*/
|
||||
public static ThenBuilder ifNull(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new IfNullOperatorBuilder().ifNull(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link IfNull}.
|
||||
*
|
||||
* @param expression the expression to check for a {@literal null} value, field reference must not be
|
||||
* {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ThenBuilder ifNull(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new IfNullOperatorBuilder().ifNull(expression);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
List<Object> list = new ArrayList<Object>();
|
||||
|
||||
if (condition instanceof Field) {
|
||||
list.add(context.getReference((Field) condition).toString());
|
||||
} else if (condition instanceof AggregationExpression) {
|
||||
list.add(((AggregationExpression) condition).toDocument(context));
|
||||
} else {
|
||||
list.add(condition);
|
||||
}
|
||||
|
||||
list.add(resolve(value, context));
|
||||
|
||||
return new Document("$ifNull", list);
|
||||
}
|
||||
|
||||
private Object resolve(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof Field) {
|
||||
return context.getReference((Field) value).toString();
|
||||
} else if (value instanceof AggregationExpression) {
|
||||
return ((AggregationExpression) value).toDocument(context);
|
||||
} else if (value instanceof Document) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return context.getMappedObject(new Document("$set", value)).get("$set");
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface IfNullBuilder {
|
||||
|
||||
/**
|
||||
* @param fieldReference the field to check for a {@literal null} value, field reference must not be
|
||||
* {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder ifNull(String fieldReference);
|
||||
|
||||
/**
|
||||
* @param expression the expression to check for a {@literal null} value, field name must not be {@literal null}
|
||||
* or empty.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder ifNull(AggregationExpression expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface ThenBuilder {
|
||||
|
||||
/**
|
||||
* @param value the value to be used if the {@code $ifNull} condition evaluates {@literal true}. Can be a
|
||||
* {@link Document}, a value that is supported by MongoDB or a value that can be converted to a MongoDB
|
||||
* representation but must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
IfNull then(Object value);
|
||||
|
||||
/**
|
||||
* @param fieldReference the field holding the replacement value, must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
IfNull thenValueOf(String fieldReference);
|
||||
|
||||
/**
|
||||
* @param expression the expression yielding to the replacement value, must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
IfNull thenValueOf(AggregationExpression expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for fluent {@link IfNull} creation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
static final class IfNullOperatorBuilder implements IfNullBuilder, ThenBuilder {
|
||||
|
||||
private Object condition;
|
||||
|
||||
private IfNullOperatorBuilder() {}
|
||||
|
||||
/**
|
||||
* Creates a new builder for {@link IfNull}.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public static IfNullOperatorBuilder newBuilder() {
|
||||
return new IfNullOperatorBuilder();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.IfNull.IfNullBuilder#ifNull(java.lang.String)
|
||||
*/
|
||||
public ThenBuilder ifNull(String fieldReference) {
|
||||
|
||||
Assert.hasText(fieldReference, "FieldReference name must not be null or empty!");
|
||||
this.condition = Fields.field(fieldReference);
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.IfNull.IfNullBuilder#ifNull(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
|
||||
*/
|
||||
@Override
|
||||
public ThenBuilder ifNull(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "AggregationExpression name must not be null or empty!");
|
||||
this.condition = expression;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.IfNull.ThenBuilder#then(java.lang.Object)
|
||||
*/
|
||||
public IfNull then(Object value) {
|
||||
return new IfNull(condition, value);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.IfNull.ThenBuilder#thenValueOf(java.lang.String)
|
||||
*/
|
||||
public IfNull thenValueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new IfNull(condition, Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.IfNull.ThenBuilder#thenValueOf(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
|
||||
*/
|
||||
public IfNull thenValueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new IfNull(condition, expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $switch}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Switch extends AbstractAggregationExpression {
|
||||
|
||||
private Switch(java.util.Map<String, Object> values) {
|
||||
super(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$switch";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Switch}.
|
||||
*
|
||||
* @param conditions must not be {@literal null}.
|
||||
*/
|
||||
public static Switch switchCases(CaseOperator... conditions) {
|
||||
|
||||
Assert.notNull(conditions, "Conditions must not be null!");
|
||||
return switchCases(Arrays.asList(conditions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Switch}.
|
||||
*
|
||||
* @param conditions must not be {@literal null}.
|
||||
*/
|
||||
public static Switch switchCases(List<CaseOperator> conditions) {
|
||||
|
||||
Assert.notNull(conditions, "Conditions must not be null!");
|
||||
return new Switch(Collections.<String, Object> singletonMap("branches", new ArrayList<CaseOperator>(conditions)));
|
||||
}
|
||||
|
||||
public Switch defaultTo(Object value) {
|
||||
return new Switch(append("default", value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework case document inside a {@code $switch}-operation.
|
||||
*/
|
||||
public static class CaseOperator implements AggregationExpression {
|
||||
|
||||
private final AggregationExpression when;
|
||||
private final Object then;
|
||||
|
||||
private CaseOperator(AggregationExpression when, Object then) {
|
||||
|
||||
this.when = when;
|
||||
this.then = then;
|
||||
}
|
||||
|
||||
public static ThenBuilder when(final AggregationExpression condition) {
|
||||
|
||||
Assert.notNull(condition, "Condition must not be null!");
|
||||
|
||||
return new ThenBuilder() {
|
||||
|
||||
@Override
|
||||
public CaseOperator then(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new CaseOperator(condition, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document dbo = new Document("case", when.toDocument(context));
|
||||
|
||||
if (then instanceof AggregationExpression) {
|
||||
dbo.put("then", ((AggregationExpression) then).toDocument(context));
|
||||
} else if (then instanceof Field) {
|
||||
dbo.put("then", context.getReference((Field) then).toString());
|
||||
} else {
|
||||
dbo.put("then", then);
|
||||
}
|
||||
|
||||
return dbo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface ThenBuilder {
|
||||
|
||||
/**
|
||||
* Set the then {@literal value}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
CaseOperator then(Object value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $cond} operator. A {@link Cond} allows nested conditions
|
||||
* {@code if-then[if-then-else]-else} using {@link Field}, {@link CriteriaDefinition}, {@link AggregationExpression}
|
||||
* or a {@link Document custom} condition. Replacement values can be either {@link Field field references},
|
||||
* {@link AggregationExpression expressions}, values of simple MongoDB types or values that can be converted to a
|
||||
* simple MongoDB type.
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/cond/">https://docs.mongodb.com/manual/reference/operator/aggregation/cond/</a>
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Cond implements AggregationExpression {
|
||||
|
||||
private final Object condition;
|
||||
private final Object thenValue;
|
||||
private final Object otherwiseValue;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Cond} for a given {@link Field} and {@code then}/{@code otherwise} values.
|
||||
*
|
||||
* @param condition must not be {@literal null}.
|
||||
* @param thenValue must not be {@literal null}.
|
||||
* @param otherwiseValue must not be {@literal null}.
|
||||
*/
|
||||
private Cond(Field condition, Object thenValue, Object otherwiseValue) {
|
||||
this((Object) condition, thenValue, otherwiseValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Cond} for a given {@link CriteriaDefinition} and {@code then}/{@code otherwise} values.
|
||||
*
|
||||
* @param condition must not be {@literal null}.
|
||||
* @param thenValue must not be {@literal null}.
|
||||
* @param otherwiseValue must not be {@literal null}.
|
||||
*/
|
||||
private Cond(CriteriaDefinition condition, Object thenValue, Object otherwiseValue) {
|
||||
this((Object) condition, thenValue, otherwiseValue);
|
||||
}
|
||||
|
||||
private Cond(Object condition, Object thenValue, Object otherwiseValue) {
|
||||
|
||||
Assert.notNull(condition, "Condition must not be null!");
|
||||
Assert.notNull(thenValue, "Then value must not be null!");
|
||||
Assert.notNull(otherwiseValue, "Otherwise value must not be null!");
|
||||
|
||||
assertNotBuilder(condition, "Condition");
|
||||
assertNotBuilder(thenValue, "Then value");
|
||||
assertNotBuilder(otherwiseValue, "Otherwise value");
|
||||
|
||||
this.condition = condition;
|
||||
this.thenValue = thenValue;
|
||||
this.otherwiseValue = otherwiseValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document condObject = new Document();
|
||||
|
||||
condObject.append("if", resolveCriteria(context, condition));
|
||||
condObject.append("then", resolveValue(context, thenValue));
|
||||
condObject.append("else", resolveValue(context, otherwiseValue));
|
||||
|
||||
return new Document("$cond", condObject);
|
||||
}
|
||||
|
||||
private Object resolveValue(AggregationOperationContext context, Object value) {
|
||||
|
||||
if (value instanceof Document || value instanceof Field) {
|
||||
return resolve(context, value);
|
||||
}
|
||||
|
||||
if (value instanceof AggregationExpression) {
|
||||
return ((AggregationExpression) value).toDocument(context);
|
||||
}
|
||||
|
||||
return context.getMappedObject(new Document("$set", value)).get("$set");
|
||||
}
|
||||
|
||||
private Object resolveCriteria(AggregationOperationContext context, Object value) {
|
||||
|
||||
if (value instanceof Document || value instanceof Field) {
|
||||
return resolve(context, value);
|
||||
}
|
||||
|
||||
if (value instanceof AggregationExpression) {
|
||||
return ((AggregationExpression) value).toDocument(context);
|
||||
}
|
||||
|
||||
if (value instanceof CriteriaDefinition) {
|
||||
|
||||
Document mappedObject = context.getMappedObject(((CriteriaDefinition) value).getCriteriaObject());
|
||||
List<Object> clauses = new ArrayList<Object>();
|
||||
|
||||
clauses.addAll(getClauses(context, mappedObject));
|
||||
|
||||
return clauses.size() == 1 ? clauses.get(0) : clauses;
|
||||
}
|
||||
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
String.format("Invalid value in condition. Supported: Document, Field references, Criteria, got: %s", value));
|
||||
}
|
||||
|
||||
private List<Object> getClauses(AggregationOperationContext context, Document mappedObject) {
|
||||
|
||||
List<Object> clauses = new ArrayList<Object>();
|
||||
|
||||
for (String key : mappedObject.keySet()) {
|
||||
|
||||
Object predicate = mappedObject.get(key);
|
||||
clauses.addAll(getClauses(context, key, predicate));
|
||||
}
|
||||
|
||||
return clauses;
|
||||
}
|
||||
|
||||
private List<Object> getClauses(AggregationOperationContext context, String key, Object predicate) {
|
||||
|
||||
List<Object> clauses = new ArrayList<Object>();
|
||||
|
||||
if (predicate instanceof List) {
|
||||
|
||||
List<Object> args = new ArrayList<Object>();
|
||||
for (Object clause : (List<?>) predicate) {
|
||||
if (clause instanceof Document) {
|
||||
args.addAll(getClauses(context, (Document) clause));
|
||||
}
|
||||
}
|
||||
|
||||
clauses.add(new Document(key, args));
|
||||
|
||||
} else if (predicate instanceof Document) {
|
||||
|
||||
Document nested = (Document) predicate;
|
||||
|
||||
for (String s : nested.keySet()) {
|
||||
|
||||
if (!isKeyword(s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Object> args = new ArrayList<Object>();
|
||||
args.add("$" + key);
|
||||
args.add(nested.get(s));
|
||||
clauses.add(new Document(s, args));
|
||||
}
|
||||
|
||||
} else if (!isKeyword(key)) {
|
||||
|
||||
List<Object> args = new ArrayList<Object>();
|
||||
args.add("$" + key);
|
||||
args.add(predicate);
|
||||
clauses.add(new Document("$eq", args));
|
||||
}
|
||||
|
||||
return clauses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link String} is a MongoDB keyword.
|
||||
*
|
||||
* @param candidate
|
||||
* @return
|
||||
*/
|
||||
private boolean isKeyword(String candidate) {
|
||||
return candidate.startsWith("$");
|
||||
}
|
||||
|
||||
private Object resolve(AggregationOperationContext context, Object value) {
|
||||
|
||||
if (value instanceof Document) {
|
||||
return context.getMappedObject((Document) value);
|
||||
}
|
||||
|
||||
return context.getReference((Field) value).toString();
|
||||
}
|
||||
|
||||
private void assertNotBuilder(Object toCheck, String name) {
|
||||
Assert.isTrue(!ClassUtils.isAssignableValue(ConditionalExpressionBuilder.class, toCheck),
|
||||
String.format("%s must not be of type %s", name, ConditionalExpressionBuilder.class.getSimpleName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builder that allows fluent creation of {@link Cond}.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public static WhenBuilder newBuilder() {
|
||||
return ConditionalExpressionBuilder.newBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start creating new {@link Cond} by providing the boolean expression used in {@code if}.
|
||||
*
|
||||
* @param booleanExpression must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public static ThenBuilder when(Document booleanExpression) {
|
||||
return ConditionalExpressionBuilder.newBuilder().when(booleanExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start creating new {@link Cond} by providing the {@link AggregationExpression} used in {@code if}.
|
||||
*
|
||||
* @param expression expression that yields in a boolean result, must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public static ThenBuilder when(AggregationExpression expression) {
|
||||
return ConditionalExpressionBuilder.newBuilder().when(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start creating new {@link Cond} by providing the field reference used in {@code if}.
|
||||
*
|
||||
* @param booleanField name of a field holding a boolean value, must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public static ThenBuilder when(String booleanField) {
|
||||
return ConditionalExpressionBuilder.newBuilder().when(booleanField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start creating new {@link Cond} by providing the {@link CriteriaDefinition} used in {@code if}.
|
||||
*
|
||||
* @param criteria criteria to evaluate, must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
public static ThenBuilder when(CriteriaDefinition criteria) {
|
||||
return ConditionalExpressionBuilder.newBuilder().when(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface WhenBuilder {
|
||||
|
||||
/**
|
||||
* @param booleanExpression expression that yields in a boolean result, must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder when(Document booleanExpression);
|
||||
|
||||
/**
|
||||
* @param expression expression that yields in a boolean result, must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder when(AggregationExpression expression);
|
||||
|
||||
/**
|
||||
* @param booleanField name of a field holding a boolean value, must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder when(String booleanField);
|
||||
|
||||
/**
|
||||
* @param criteria criteria to evaluate, must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder when(CriteriaDefinition criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface ThenBuilder {
|
||||
|
||||
/**
|
||||
* @param value the value to be used if the condition evaluates {@literal true}. Can be a {@link Document}, a
|
||||
* value that is supported by MongoDB or a value that can be converted to a MongoDB representation but
|
||||
* must not be {@literal null}.
|
||||
* @return the {@link OtherwiseBuilder}
|
||||
*/
|
||||
OtherwiseBuilder then(Object value);
|
||||
|
||||
/**
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return the {@link OtherwiseBuilder}
|
||||
*/
|
||||
OtherwiseBuilder thenValueOf(String fieldReference);
|
||||
|
||||
/**
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return the {@link OtherwiseBuilder}
|
||||
*/
|
||||
OtherwiseBuilder thenValueOf(AggregationExpression expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface OtherwiseBuilder {
|
||||
|
||||
/**
|
||||
* @param value the value to be used if the condition evaluates {@literal false}. Can be a {@link Document}, a
|
||||
* value that is supported by MongoDB or a value that can be converted to a MongoDB representation but
|
||||
* must not be {@literal null}.
|
||||
* @return the {@link Cond}
|
||||
*/
|
||||
Cond otherwise(Object value);
|
||||
|
||||
/**
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return the {@link Cond}
|
||||
*/
|
||||
Cond otherwiseValueOf(String fieldReference);
|
||||
|
||||
/**
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return the {@link Cond}
|
||||
*/
|
||||
Cond otherwiseValueOf(AggregationExpression expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for fluent {@link Cond} creation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
static class ConditionalExpressionBuilder implements WhenBuilder, ThenBuilder, OtherwiseBuilder {
|
||||
|
||||
private Object condition;
|
||||
private Object thenValue;
|
||||
|
||||
private ConditionalExpressionBuilder() {}
|
||||
|
||||
/**
|
||||
* Creates a new builder for {@link Cond}.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public static ConditionalExpressionBuilder newBuilder() {
|
||||
return new ConditionalExpressionBuilder();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.WhenBuilder#when(org.bson.Document)
|
||||
*/
|
||||
@Override
|
||||
public ConditionalExpressionBuilder when(Document booleanExpression) {
|
||||
|
||||
Assert.notNull(booleanExpression, "'Boolean expression' must not be null!");
|
||||
|
||||
this.condition = booleanExpression;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.WhenBuilder#when(org.springframework.data.mongodb.core.query.CriteriaDefinition)
|
||||
*/
|
||||
@Override
|
||||
public ThenBuilder when(CriteriaDefinition criteria) {
|
||||
|
||||
Assert.notNull(criteria, "Criteria must not be null!");
|
||||
this.condition = criteria;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.WhenBuilder#when(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
|
||||
*/
|
||||
@Override
|
||||
public ThenBuilder when(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "AggregationExpression field must not be null!");
|
||||
this.condition = expression;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.WhenBuilder#when(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ThenBuilder when(String booleanField) {
|
||||
|
||||
Assert.hasText(booleanField, "Boolean field name must not be null or empty!");
|
||||
this.condition = Fields.field(booleanField);
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.ThenBuilder#then(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public OtherwiseBuilder then(Object thenValue) {
|
||||
|
||||
Assert.notNull(thenValue, "Then-value must not be null!");
|
||||
this.thenValue = thenValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.ThenBuilder#thenValueOf(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public OtherwiseBuilder thenValueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
this.thenValue = Fields.field(fieldReference);
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.ThenBuilder#thenValueOf(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
|
||||
*/
|
||||
@Override
|
||||
public OtherwiseBuilder thenValueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "AggregationExpression must not be null!");
|
||||
this.thenValue = expression;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.OtherwiseBuilder#otherwise(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Cond otherwise(Object otherwiseValue) {
|
||||
|
||||
Assert.notNull(otherwiseValue, "Value must not be null!");
|
||||
return new Cond(condition, thenValue, otherwiseValue);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.OtherwiseBuilder#otherwiseValueOf(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Cond otherwiseValueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Cond(condition, thenValue, Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.OtherwiseBuilder#otherwiseValueOf(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
|
||||
*/
|
||||
@Override
|
||||
public Cond otherwiseValueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "AggregationExpression must not be null!");
|
||||
return new Cond(condition, thenValue, expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $count}-operation. <br />
|
||||
* We recommend to use the static factory method {@link Aggregation#count()} instead of creating instances of this class
|
||||
* directly.
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/count/#pipe._S_count">https://docs.mongodb.com/manual/reference/operator/aggregation/count/</a>
|
||||
* @author Mark Paluch
|
||||
* @since 1.10
|
||||
*/
|
||||
public class CountOperation implements FieldsExposingAggregationOperation {
|
||||
|
||||
private final String fieldName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CountOperation} given the {@link fieldName} field name.
|
||||
*
|
||||
* @param asFieldName must not be {@literal null} or empty.
|
||||
*/
|
||||
public CountOperation(String fieldName) {
|
||||
|
||||
Assert.hasText(fieldName, "Field name must not be null or empty!");
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
return new Document("$count", fieldName);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields()
|
||||
*/
|
||||
@Override
|
||||
public ExposedFields getFields() {
|
||||
return ExposedFields.from(new ExposedField(fieldName, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link CountOperation}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static class CountOperationBuilder {
|
||||
|
||||
/**
|
||||
* Returns the finally to be applied {@link CountOperation} with the given alias.
|
||||
*
|
||||
* @param fieldName must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public CountOperation as(String fieldName) {
|
||||
return new CountOperation(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Gateway to {@literal data type} expressions.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
* @soundtrack Clawfinger - Catch Me
|
||||
*/
|
||||
public class DataTypeOperators {
|
||||
|
||||
/**
|
||||
* Return the BSON data type of the given {@literal field}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Type typeOf(String fieldReference) {
|
||||
return Type.typeOf(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $type}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Type extends AbstractAggregationExpression {
|
||||
|
||||
private Type(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$type";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Type}.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Type typeOf(String field) {
|
||||
|
||||
Assert.notNull(field, "Field must not be null!");
|
||||
return new Type(Fields.field(field));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,837 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.ArithmeticOperators.ArithmeticOperatorFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Gateway to {@literal Date} aggregation operations.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public class DateOperators {
|
||||
|
||||
/**
|
||||
* Take the date referenced by given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static DateOperatorFactory dateOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new DateOperatorFactory(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the date resulting from the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static DateOperatorFactory dateOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new DateOperatorFactory(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class DateOperatorFactory {
|
||||
|
||||
private final String fieldReference;
|
||||
private final AggregationExpression expression;
|
||||
|
||||
/**
|
||||
* Creates new {@link ArithmeticOperatorFactory} for given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
*/
|
||||
public DateOperatorFactory(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
this.fieldReference = fieldReference;
|
||||
this.expression = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link ArithmeticOperatorFactory} for given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
*/
|
||||
public DateOperatorFactory(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
this.fieldReference = null;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the day of the year for a date as a number between 1 and
|
||||
* 366.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public DayOfYear dayOfYear() {
|
||||
return usesFieldRef() ? DayOfYear.dayOfYear(fieldReference) : DayOfYear.dayOfYear(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the day of the month for a date as a number between 1 and
|
||||
* 31.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public DayOfMonth dayOfMonth() {
|
||||
return usesFieldRef() ? DayOfMonth.dayOfMonth(fieldReference) : DayOfMonth.dayOfMonth(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the day of the week for a date as a number between 1
|
||||
* (Sunday) and 7 (Saturday).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public DayOfWeek dayOfWeek() {
|
||||
return usesFieldRef() ? DayOfWeek.dayOfWeek(fieldReference) : DayOfWeek.dayOfWeek(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the year portion of a date.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Year year() {
|
||||
return usesFieldRef() ? Year.yearOf(fieldReference) : Year.yearOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the month of a date as a number between 1 and 12.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Month month() {
|
||||
return usesFieldRef() ? Month.monthOf(fieldReference) : Month.monthOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the week of the year for a date as a number between 0 and
|
||||
* 53.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Week week() {
|
||||
return usesFieldRef() ? Week.weekOf(fieldReference) : Week.weekOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the hour portion of a date as a number between 0 and 23.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Hour hour() {
|
||||
return usesFieldRef() ? Hour.hourOf(fieldReference) : Hour.hourOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the minute portion of a date as a number between 0 and 59.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Minute minute() {
|
||||
return usesFieldRef() ? Minute.minuteOf(fieldReference) : Minute.minuteOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the second portion of a date as a number between 0 and 59,
|
||||
* but can be 60 to account for leap seconds.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Second second() {
|
||||
return usesFieldRef() ? Second.secondOf(fieldReference) : Second.secondOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the millisecond portion of a date as an integer between 0
|
||||
* and 999.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Millisecond millisecond() {
|
||||
return usesFieldRef() ? Millisecond.millisecondOf(fieldReference) : Millisecond.millisecondOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that converts a date object to a string according to a user-specified
|
||||
* {@literal format}.
|
||||
*
|
||||
* @param format must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public DateToString toString(String format) {
|
||||
return (usesFieldRef() ? DateToString.dateOf(fieldReference) : DateToString.dateOf(expression)).toString(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the weekday number in ISO 8601 format, ranging from 1 (for
|
||||
* Monday) to 7 (for Sunday).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IsoDayOfWeek isoDayOfWeek() {
|
||||
return usesFieldRef() ? IsoDayOfWeek.isoDayOfWeek(fieldReference) : IsoDayOfWeek.isoDayOfWeek(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the week number in ISO 8601 format, ranging from 1 to 53.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IsoWeek isoWeek() {
|
||||
return usesFieldRef() ? IsoWeek.isoWeekOf(fieldReference) : IsoWeek.isoWeekOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the year number in ISO 8601 format.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IsoWeekYear isoWeekYear() {
|
||||
return usesFieldRef() ? IsoWeekYear.isoWeekYearOf(fieldReference) : IsoWeekYear.isoWeekYearOf(expression);
|
||||
}
|
||||
|
||||
private boolean usesFieldRef() {
|
||||
return fieldReference != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $dayOfYear}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class DayOfYear extends AbstractAggregationExpression {
|
||||
|
||||
private DayOfYear(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$dayOfYear";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link DayOfYear}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static DayOfYear dayOfYear(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new DayOfYear(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link DayOfYear}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static DayOfYear dayOfYear(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new DayOfYear(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $dayOfMonth}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class DayOfMonth extends AbstractAggregationExpression {
|
||||
|
||||
private DayOfMonth(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$dayOfMonth";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link DayOfMonth}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static DayOfMonth dayOfMonth(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new DayOfMonth(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link DayOfMonth}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static DayOfMonth dayOfMonth(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new DayOfMonth(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $dayOfWeek}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class DayOfWeek extends AbstractAggregationExpression {
|
||||
|
||||
private DayOfWeek(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$dayOfWeek";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link DayOfWeek}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static DayOfWeek dayOfWeek(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new DayOfWeek(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link DayOfWeek}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static DayOfWeek dayOfWeek(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new DayOfWeek(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $year}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Year extends AbstractAggregationExpression {
|
||||
|
||||
private Year(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$year";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Year}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Year yearOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Year(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Year}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Year yearOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Year(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $month}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Month extends AbstractAggregationExpression {
|
||||
|
||||
private Month(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$month";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Month}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Month monthOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Month(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Month}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Month monthOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Month(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $week}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Week extends AbstractAggregationExpression {
|
||||
|
||||
private Week(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$week";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Week}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Week weekOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Week(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Week}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Week weekOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Week(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $hour}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Hour extends AbstractAggregationExpression {
|
||||
|
||||
private Hour(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$hour";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Hour}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Hour hourOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Hour(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Hour}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Hour hourOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Hour(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $minute}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Minute extends AbstractAggregationExpression {
|
||||
|
||||
private Minute(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$minute";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Minute}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Minute minuteOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Minute(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Minute}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Minute minuteOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Minute(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $second}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Second extends AbstractAggregationExpression {
|
||||
|
||||
private Second(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$second";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Second}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Second secondOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Second(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Second}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Second secondOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Second(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $millisecond}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Millisecond extends AbstractAggregationExpression {
|
||||
|
||||
private Millisecond(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$millisecond";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Millisecond}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Millisecond millisecondOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Millisecond(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Millisecond}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Millisecond millisecondOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Millisecond(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $dateToString}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class DateToString extends AbstractAggregationExpression {
|
||||
|
||||
private DateToString(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$dateToString";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link FormatBuilder} allowing to define the date format to apply.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static FormatBuilder dateOf(final String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
|
||||
return new FormatBuilder() {
|
||||
|
||||
@Override
|
||||
public DateToString toString(String format) {
|
||||
|
||||
Assert.notNull(format, "Format must not be null!");
|
||||
return new DateToString(argumentMap(Fields.field(fieldReference), format));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link FormatBuilder} allowing to define the date format to apply.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static FormatBuilder dateOf(final AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
|
||||
return new FormatBuilder() {
|
||||
|
||||
@Override
|
||||
public DateToString toString(String format) {
|
||||
|
||||
Assert.notNull(format, "Format must not be null!");
|
||||
return new DateToString(argumentMap(expression, format));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static java.util.Map<String, Object> argumentMap(Object date, String format) {
|
||||
|
||||
java.util.Map<String, Object> args = new LinkedHashMap<String, Object>(2);
|
||||
args.put("format", format);
|
||||
args.put("date", date);
|
||||
return args;
|
||||
}
|
||||
|
||||
public interface FormatBuilder {
|
||||
|
||||
/**
|
||||
* Creates new {@link DateToString} with all previously added arguments appending the given one.
|
||||
*
|
||||
* @param format must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
DateToString toString(String format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $isoDayOfWeek}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class IsoDayOfWeek extends AbstractAggregationExpression {
|
||||
|
||||
private IsoDayOfWeek(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$isoDayOfWeek";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link IsoDayOfWeek}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static IsoDayOfWeek isoDayOfWeek(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new IsoDayOfWeek(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link IsoDayOfWeek}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static IsoDayOfWeek isoDayOfWeek(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new IsoDayOfWeek(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $isoWeek}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class IsoWeek extends AbstractAggregationExpression {
|
||||
|
||||
private IsoWeek(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$isoWeek";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link IsoWeek}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static IsoWeek isoWeekOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new IsoWeek(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link IsoWeek}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static IsoWeek isoWeekOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new IsoWeek(expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $isoWeekYear}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class IsoWeekYear extends AbstractAggregationExpression {
|
||||
|
||||
private IsoWeekYear(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$isoWeekYear";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link IsoWeekYear}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static IsoWeekYear isoWeekYearOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new IsoWeekYear(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Millisecond}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static IsoWeekYear isoWeekYearOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new IsoWeekYear(expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,10 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CompositeIterator;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Value object to capture the fields exposed by an {@link AggregationOperation}.
|
||||
@@ -104,7 +106,7 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
result.add(new ExposedField(field, synthetic));
|
||||
}
|
||||
|
||||
return ExposedFields.from(result);
|
||||
return from(result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,12 +338,36 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to an {@link ExposedField}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
interface FieldReference {
|
||||
|
||||
/**
|
||||
* Returns the raw, unqualified reference, i.e. the field reference without a {@literal $} prefix.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getRaw();
|
||||
|
||||
/**
|
||||
* Returns the reference value for the given field reference. Will return 1 for a synthetic, unaliased field or the
|
||||
* raw rendering of the reference otherwise.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Object getReferenceValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to an {@link ExposedField}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class FieldReference {
|
||||
static class DirectFieldReference implements FieldReference {
|
||||
|
||||
private final ExposedField field;
|
||||
|
||||
@@ -350,17 +376,16 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
*/
|
||||
public FieldReference(ExposedField field) {
|
||||
public DirectFieldReference(ExposedField field) {
|
||||
|
||||
Assert.notNull(field, "ExposedField must not be null!");
|
||||
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw, unqualified reference, i.e. the field reference without a {@literal $} prefix.
|
||||
*
|
||||
* @return
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference#getRaw()
|
||||
*/
|
||||
public String getRaw() {
|
||||
|
||||
@@ -368,11 +393,9 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
return field.synthetic ? target : String.format("%s.%s", Fields.UNDERSCORE_ID, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reference value for the given field reference. Will return 1 for a synthetic, unaliased field or the
|
||||
* raw rendering of the reference otherwise.
|
||||
*
|
||||
* @return
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference#getReferenceValue()
|
||||
*/
|
||||
public Object getReferenceValue() {
|
||||
return field.synthetic && !field.isAliased() ? 1 : toString();
|
||||
@@ -384,6 +407,11 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
if(getRaw().startsWith("$")) {
|
||||
return getRaw();
|
||||
}
|
||||
|
||||
return String.format("$%s", getRaw());
|
||||
}
|
||||
|
||||
@@ -398,11 +426,11 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof FieldReference)) {
|
||||
if (!(obj instanceof DirectFieldReference)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FieldReference that = (FieldReference) obj;
|
||||
DirectFieldReference that = (DirectFieldReference) obj;
|
||||
|
||||
return this.field.equals(that.field);
|
||||
}
|
||||
@@ -416,4 +444,78 @@ public final class ExposedFields implements Iterable<ExposedField> {
|
||||
return field.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link FieldReference} to a {@link Field} used within a nested {@link AggregationExpression}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
static class ExpressionFieldReference implements FieldReference {
|
||||
|
||||
private FieldReference delegate;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FieldReference} for the given {@link ExposedField}.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
*/
|
||||
public ExpressionFieldReference(FieldReference field) {
|
||||
delegate = field;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference#getRaw()
|
||||
*/
|
||||
@Override
|
||||
public String getRaw() {
|
||||
return delegate.getRaw();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference#getReferenceValue()
|
||||
*/
|
||||
@Override
|
||||
public Object getReferenceValue() {
|
||||
return delegate.getReferenceValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
String fieldRef = delegate.toString();
|
||||
|
||||
if (fieldRef.startsWith("$$")) {
|
||||
return fieldRef;
|
||||
}
|
||||
|
||||
if (fieldRef.startsWith("$")) {
|
||||
return "$" + fieldRef;
|
||||
}
|
||||
|
||||
return fieldRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof ExpressionFieldReference)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExpressionFieldReference that = (ExpressionFieldReference) obj;
|
||||
return ObjectUtils.nullSafeEquals(this.delegate, that.delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.DirectFieldReference;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -54,7 +55,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.Document)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(org.bson.Document)
|
||||
*/
|
||||
@Override
|
||||
public Document getMappedObject(Document document) {
|
||||
@@ -112,10 +113,10 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
|
||||
|
||||
if (field != null) {
|
||||
// we return a FieldReference to the given field directly to make sure that we reference the proper alias here.
|
||||
return new FieldReference(new ExposedField(field, exposedField.isSynthetic()));
|
||||
return new DirectFieldReference(new ExposedField(field, exposedField.isSynthetic()));
|
||||
}
|
||||
|
||||
return new FieldReference(exposedField);
|
||||
return new DirectFieldReference(exposedField);
|
||||
}
|
||||
|
||||
if (name.contains(".")) {
|
||||
@@ -126,7 +127,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
|
||||
if (rootField != null) {
|
||||
|
||||
// We have to synthetic to true, in order to render the field-name as is.
|
||||
return new FieldReference(new ExposedField(name, true));
|
||||
return new DirectFieldReference(new ExposedField(name, true));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.BucketOperationSupport.Output;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $facet}-operation. <br />
|
||||
* Facet of {@link AggregationOperation}s to be used in an {@link Aggregation}. Processes multiple
|
||||
* {@link AggregationOperation} pipelines within a single stage on the same set of input documents. Each sub-pipeline
|
||||
* has its own field in the output document where its results are stored as an array of documents.
|
||||
* {@link FacetOperation} enables various aggregations on the same set of input documents, without needing to retrieve
|
||||
* the input documents multiple times. <br />
|
||||
* As of MongoDB 3.4, {@link FacetOperation} cannot be used with nested pipelines containing {@link GeoNearOperation},
|
||||
* {@link OutOperation} and {@link FacetOperation}. <br />
|
||||
* We recommend to use the static factory method {@link Aggregation#facet()} instead of creating instances of this class
|
||||
* directly.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
* @see <a href="https://docs.mongodb.org/manual/reference/aggregation/facet/">MongoDB Aggregation Framework: $facet</a>
|
||||
*/
|
||||
public class FacetOperation implements FieldsExposingAggregationOperation {
|
||||
|
||||
/**
|
||||
* Empty (initial) {@link FacetOperation}.
|
||||
*/
|
||||
public static final FacetOperation EMPTY = new FacetOperation();
|
||||
|
||||
private final Facets facets;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FacetOperation}.
|
||||
*/
|
||||
public FacetOperation() {
|
||||
this(Facets.EMPTY);
|
||||
}
|
||||
|
||||
private FacetOperation(Facets facets) {
|
||||
this.facets = facets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FacetOperationBuilder} to append a new facet using {@literal operations}. <br />
|
||||
* {@link FacetOperationBuilder} takes a pipeline of {@link AggregationOperation} to categorize documents into a
|
||||
* single facet.
|
||||
*
|
||||
* @param operations must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public FacetOperationBuilder and(AggregationOperation... operations) {
|
||||
|
||||
Assert.notNull(operations, "AggregationOperations must not be null!");
|
||||
Assert.notEmpty(operations, "AggregationOperations must not be empty!");
|
||||
|
||||
return new FacetOperationBuilder(facets, Arrays.asList(operations));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
return new Document("$facet", facets.toDocument(context));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields()
|
||||
*/
|
||||
@Override
|
||||
public ExposedFields getFields() {
|
||||
return facets.asExposedFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link FacetOperation} by adding existing and the new pipeline of {@link AggregationOperation} to the
|
||||
* new {@link FacetOperation}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static class FacetOperationBuilder {
|
||||
|
||||
private final Facets current;
|
||||
private final List<AggregationOperation> operations;
|
||||
|
||||
private FacetOperationBuilder(Facets current, List<AggregationOperation> operations) {
|
||||
this.current = current;
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FacetOperation} that contains the configured pipeline of {@link AggregationOperation}
|
||||
* exposed as {@literal fieldName} in the resulting facet document.
|
||||
*
|
||||
* @param fieldName must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public FacetOperation as(String fieldName) {
|
||||
|
||||
Assert.hasText(fieldName, "FieldName must not be null or empty!");
|
||||
|
||||
return new FacetOperation(current.and(fieldName, operations));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates multiple {@link Facet}s
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
private static class Facets {
|
||||
|
||||
private static final Facets EMPTY = new Facets(Collections.<Facet> emptyList());
|
||||
|
||||
private List<Facet> facets;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Facets} given {@link List} of {@link Facet}.
|
||||
*
|
||||
* @param facets
|
||||
*/
|
||||
private Facets(List<Facet> facets) {
|
||||
this.facets = facets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link ExposedFields} derived from {@link Output}.
|
||||
*/
|
||||
ExposedFields asExposedFields() {
|
||||
|
||||
ExposedFields fields = ExposedFields.from();
|
||||
|
||||
for (Facet facet : facets) {
|
||||
fields = fields.and(facet.getExposedField());
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
protected Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document document = new Document();
|
||||
|
||||
for (Facet facet : facets) {
|
||||
document.put(facet.getExposedField().getName(), facet.toDocuments(context));
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a facet to this {@link Facets}.
|
||||
*
|
||||
* @param fieldName must not be {@literal null}.
|
||||
* @param operations must not be {@literal null}.
|
||||
* @return the new {@link Facets}.
|
||||
*/
|
||||
Facets and(String fieldName, List<AggregationOperation> operations) {
|
||||
|
||||
Assert.hasText(fieldName, "FieldName must not be null or empty!");
|
||||
Assert.notNull(operations, "AggregationOperations must not be null!");
|
||||
|
||||
List<Facet> facets = new ArrayList<Facet>(this.facets.size() + 1);
|
||||
facets.addAll(this.facets);
|
||||
facets.add(new Facet(new ExposedField(fieldName, true), operations));
|
||||
|
||||
return new Facets(facets);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A single facet with a {@link ExposedField} and its {@link AggregationOperation} pipeline.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
private static class Facet {
|
||||
|
||||
private final ExposedField exposedField;
|
||||
private final List<AggregationOperation> operations;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Facet} given {@link ExposedField} and {@link AggregationOperation} pipeline.
|
||||
*
|
||||
* @param exposedField must not be {@literal null}.
|
||||
* @param operations must not be {@literal null}.
|
||||
*/
|
||||
Facet(ExposedField exposedField, List<AggregationOperation> operations) {
|
||||
|
||||
Assert.notNull(exposedField, "ExposedField must not be null!");
|
||||
Assert.notNull(operations, "AggregationOperations must not be null!");
|
||||
|
||||
this.exposedField = exposedField;
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
ExposedField getExposedField() {
|
||||
return exposedField;
|
||||
}
|
||||
|
||||
protected List<Document> toDocuments(AggregationOperationContext context) {
|
||||
return AggregationOperationRenderer.toDocument(operations, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -185,6 +186,14 @@ public final class Fields implements Iterable<Field> {
|
||||
return fields.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public List<Field> asList() {
|
||||
return Collections.unmodifiableList(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object to encapsulate a field in an aggregation operation.
|
||||
*
|
||||
@@ -192,6 +201,7 @@ public final class Fields implements Iterable<Field> {
|
||||
*/
|
||||
static class AggregationField implements Field {
|
||||
|
||||
private final String raw;
|
||||
private final String name;
|
||||
private final String target;
|
||||
|
||||
@@ -216,6 +226,7 @@ public final class Fields implements Iterable<Field> {
|
||||
*/
|
||||
public AggregationField(String name, String target) {
|
||||
|
||||
raw = name;
|
||||
String nameToSet = cleanUp(name);
|
||||
String targetToSet = cleanUp(target);
|
||||
|
||||
@@ -257,6 +268,11 @@ public final class Fields implements Iterable<Field> {
|
||||
* @see org.springframework.data.mongodb.core.aggregation.Field#getAlias()
|
||||
*/
|
||||
public String getTarget() {
|
||||
|
||||
if (isLocalVar()) {
|
||||
return this.getRaw();
|
||||
}
|
||||
|
||||
return StringUtils.hasText(this.target) ? this.target : this.name;
|
||||
}
|
||||
|
||||
@@ -269,6 +285,22 @@ public final class Fields implements Iterable<Field> {
|
||||
return !getName().equals(getTarget());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} in case the field name starts with {@code $$}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public boolean isLocalVar() {
|
||||
return raw.startsWith("$$") && !raw.startsWith("$$$");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public String getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
|
||||
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
|
||||
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
|
||||
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $graphLookup}-operation. <br />
|
||||
* Performs a recursive search on a collection, with options for restricting the search by recursion depth and query
|
||||
* filter. <br />
|
||||
* We recommend to use the static factory method {@link Aggregation#graphLookup(String)} instead of creating instances
|
||||
* of this class directly.
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.org/manual/reference/aggregation/graphLookup/">https://docs.mongodb.org/manual/reference/aggregation/graphLookup/</a>
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public class GraphLookupOperation implements InheritsFieldsAggregationOperation {
|
||||
|
||||
private static final Set<Class<?>> ALLOWED_START_TYPES = new HashSet<Class<?>>(
|
||||
Arrays.<Class<?>> asList(AggregationExpression.class, String.class, Field.class, Document.class));
|
||||
|
||||
private final String from;
|
||||
private final List<Object> startWith;
|
||||
private final Field connectFrom;
|
||||
private final Field connectTo;
|
||||
private final Field as;
|
||||
private final Long maxDepth;
|
||||
private final Field depthField;
|
||||
private final CriteriaDefinition restrictSearchWithMatch;
|
||||
|
||||
private GraphLookupOperation(String from, List<Object> startWith, Field connectFrom, Field connectTo, Field as,
|
||||
Long maxDepth, Field depthField, CriteriaDefinition restrictSearchWithMatch) {
|
||||
|
||||
this.from = from;
|
||||
this.startWith = startWith;
|
||||
this.connectFrom = connectFrom;
|
||||
this.connectTo = connectTo;
|
||||
this.as = as;
|
||||
this.maxDepth = maxDepth;
|
||||
this.depthField = depthField;
|
||||
this.restrictSearchWithMatch = restrictSearchWithMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FromBuilder} to build {@link GraphLookupOperation}.
|
||||
*
|
||||
* @return a new {@link FromBuilder}.
|
||||
*/
|
||||
public static FromBuilder builder() {
|
||||
return new GraphLookupOperationFromBuilder();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
Document graphLookup = new Document();
|
||||
|
||||
graphLookup.put("from", from);
|
||||
|
||||
List<Object> mappedStartWith = new ArrayList<Object>(startWith.size());
|
||||
|
||||
for (Object startWithElement : startWith) {
|
||||
|
||||
if (startWithElement instanceof AggregationExpression) {
|
||||
mappedStartWith.add(((AggregationExpression) startWithElement).toDocument(context));
|
||||
} else if (startWithElement instanceof Field) {
|
||||
mappedStartWith.add(context.getReference((Field) startWithElement).toString());
|
||||
} else {
|
||||
mappedStartWith.add(startWithElement);
|
||||
}
|
||||
}
|
||||
|
||||
graphLookup.put("startWith", mappedStartWith.size() == 1 ? mappedStartWith.iterator().next() : mappedStartWith);
|
||||
|
||||
graphLookup.put("connectFromField", connectFrom.getName());
|
||||
graphLookup.put("connectToField", connectTo.getName());
|
||||
graphLookup.put("as", as.getName());
|
||||
|
||||
if (maxDepth != null) {
|
||||
graphLookup.put("maxDepth", maxDepth);
|
||||
}
|
||||
|
||||
if (depthField != null) {
|
||||
graphLookup.put("depthField", depthField.getName());
|
||||
}
|
||||
|
||||
if (restrictSearchWithMatch != null) {
|
||||
graphLookup.put("restrictSearchWithMatch", context.getMappedObject(restrictSearchWithMatch.getCriteriaObject()));
|
||||
}
|
||||
|
||||
return new Document("$graphLookup", graphLookup);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields()
|
||||
*/
|
||||
@Override
|
||||
public ExposedFields getFields() {
|
||||
return ExposedFields.from(new ExposedField(as, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface FromBuilder {
|
||||
|
||||
/**
|
||||
* Set the {@literal collectionName} to apply the {@code $graphLookup} to.
|
||||
*
|
||||
* @param collectionName must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
StartWithBuilder from(String collectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public interface StartWithBuilder {
|
||||
|
||||
/**
|
||||
* Set the startWith {@literal fieldReferences} to apply the {@code $graphLookup} to.
|
||||
*
|
||||
* @param fieldReferences must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
ConnectFromBuilder startWith(String... fieldReferences);
|
||||
|
||||
/**
|
||||
* Set the startWith {@literal expressions} to apply the {@code $graphLookup} to.
|
||||
*
|
||||
* @param expressions must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
ConnectFromBuilder startWith(AggregationExpression... expressions);
|
||||
|
||||
/**
|
||||
* Set the startWith as either {@literal fieldReferences}, {@link Fields}, {@link Document} or
|
||||
* {@link AggregationExpression} to apply the {@code $graphLookup} to.
|
||||
*
|
||||
* @param expressions must not be {@literal null}.
|
||||
* @return
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
ConnectFromBuilder startWith(Object... expressions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface ConnectFromBuilder {
|
||||
|
||||
/**
|
||||
* Set the connectFrom {@literal fieldName} to apply the {@code $graphLookup} to.
|
||||
*
|
||||
* @param fieldName must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
ConnectToBuilder connectFrom(String fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface ConnectToBuilder {
|
||||
|
||||
/**
|
||||
* Set the connectTo {@literal fieldName} to apply the {@code $graphLookup} to.
|
||||
*
|
||||
* @param fieldName must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
GraphLookupOperationBuilder connectTo(String fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder to build the initial {@link GraphLookupOperationBuilder} that configures the initial mandatory set of
|
||||
* {@link GraphLookupOperation} properties.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
static final class GraphLookupOperationFromBuilder
|
||||
implements FromBuilder, StartWithBuilder, ConnectFromBuilder, ConnectToBuilder {
|
||||
|
||||
private String from;
|
||||
private List<? extends Object> startWith;
|
||||
private String connectFrom;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.GraphLookupOperation.FromBuilder#from(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public StartWithBuilder from(String collectionName) {
|
||||
|
||||
Assert.hasText(collectionName, "CollectionName must not be null or empty!");
|
||||
|
||||
this.from = collectionName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.GraphLookupOperation.StartWithBuilder#startWith(java.lang.String[])
|
||||
*/
|
||||
@Override
|
||||
public ConnectFromBuilder startWith(String... fieldReferences) {
|
||||
|
||||
Assert.notNull(fieldReferences, "FieldReferences must not be null!");
|
||||
Assert.noNullElements(fieldReferences, "FieldReferences must not contain null elements!");
|
||||
|
||||
List<Object> fields = new ArrayList<Object>(fieldReferences.length);
|
||||
|
||||
for (String fieldReference : fieldReferences) {
|
||||
fields.add(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
this.startWith = fields;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.GraphLookupOperation.StartWithBuilder#startWith(org.springframework.data.mongodb.core.aggregation.AggregationExpression[])
|
||||
*/
|
||||
@Override
|
||||
public ConnectFromBuilder startWith(AggregationExpression... expressions) {
|
||||
|
||||
Assert.notNull(expressions, "AggregationExpressions must not be null!");
|
||||
Assert.noNullElements(expressions, "AggregationExpressions must not contain null elements!");
|
||||
|
||||
this.startWith = Arrays.asList(expressions);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectFromBuilder startWith(Object... expressions) {
|
||||
|
||||
Assert.notNull(expressions, "Expressions must not be null!");
|
||||
Assert.noNullElements(expressions, "Expressions must not contain null elements!");
|
||||
|
||||
this.startWith = verifyAndPotentiallyTransformStartsWithTypes(expressions);
|
||||
return this;
|
||||
}
|
||||
|
||||
private List<Object> verifyAndPotentiallyTransformStartsWithTypes(Object... expressions) {
|
||||
|
||||
List<Object> expressionsToUse = new ArrayList<Object>(expressions.length);
|
||||
|
||||
for (Object expression : expressions) {
|
||||
|
||||
assertStartWithType(expression);
|
||||
|
||||
if (expression instanceof String) {
|
||||
expressionsToUse.add(Fields.field((String) expression));
|
||||
} else {
|
||||
expressionsToUse.add(expression);
|
||||
}
|
||||
|
||||
}
|
||||
return expressionsToUse;
|
||||
}
|
||||
|
||||
private void assertStartWithType(Object expression) {
|
||||
|
||||
for (Class<?> type : ALLOWED_START_TYPES) {
|
||||
|
||||
if (ClassUtils.isAssignable(type, expression.getClass())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Expression must be any of %s but was %s", ALLOWED_START_TYPES, expression.getClass()));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.GraphLookupOperation.ConnectFromBuilder#connectFrom(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ConnectToBuilder connectFrom(String fieldName) {
|
||||
|
||||
Assert.hasText(fieldName, "ConnectFrom must not be null or empty!");
|
||||
|
||||
this.connectFrom = fieldName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.GraphLookupOperation.ConnectToBuilder#connectTo(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public GraphLookupOperationBuilder connectTo(String fieldName) {
|
||||
|
||||
Assert.hasText(fieldName, "ConnectTo must not be null or empty!");
|
||||
|
||||
return new GraphLookupOperationBuilder(from, startWith, connectFrom, fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public static final class GraphLookupOperationBuilder {
|
||||
|
||||
private final String from;
|
||||
private final List<Object> startWith;
|
||||
private final Field connectFrom;
|
||||
private final Field connectTo;
|
||||
private Long maxDepth;
|
||||
private Field depthField;
|
||||
private CriteriaDefinition restrictSearchWithMatch;
|
||||
|
||||
protected GraphLookupOperationBuilder(String from, List<? extends Object> startWith, String connectFrom,
|
||||
String connectTo) {
|
||||
|
||||
this.from = from;
|
||||
this.startWith = new ArrayList<Object>(startWith);
|
||||
this.connectFrom = Fields.field(connectFrom);
|
||||
this.connectTo = Fields.field(connectTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally limit the number of recursions.
|
||||
*
|
||||
* @param numberOfRecursions must be greater or equal to zero.
|
||||
* @return
|
||||
*/
|
||||
public GraphLookupOperationBuilder maxDepth(long numberOfRecursions) {
|
||||
|
||||
Assert.isTrue(numberOfRecursions >= 0, "Max depth must be >= 0!");
|
||||
|
||||
this.maxDepth = numberOfRecursions;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally add a depth field {@literal fieldName} to each traversed document in the search path.
|
||||
*
|
||||
* @param fieldName must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public GraphLookupOperationBuilder depthField(String fieldName) {
|
||||
|
||||
Assert.hasText(fieldName, "Depth field name must not be null or empty!");
|
||||
|
||||
this.depthField = Fields.field(fieldName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally add a query specifying conditions to the recursive search.
|
||||
*
|
||||
* @param criteriaDefinition must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public GraphLookupOperationBuilder restrict(CriteriaDefinition criteriaDefinition) {
|
||||
|
||||
Assert.notNull(criteriaDefinition, "CriteriaDefinition must not be null!");
|
||||
|
||||
this.restrictSearchWithMatch = criteriaDefinition;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the array field added to each output document and return the final {@link GraphLookupOperation}.
|
||||
* Contains the documents traversed in the {@literal $graphLookup} stage to reach the document.
|
||||
*
|
||||
* @param fieldName must not be {@literal null} or empty.
|
||||
* @return the final {@link GraphLookupOperation}.
|
||||
*/
|
||||
public GraphLookupOperation as(String fieldName) {
|
||||
|
||||
Assert.hasText(fieldName, "As field name must not be null or empty!");
|
||||
|
||||
return new GraphLookupOperation(from, startWith, connectFrom, connectTo, Fields.field(fieldName), maxDepth,
|
||||
depthField, restrictSearchWithMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,12 +33,13 @@ import org.springframework.util.StringUtils;
|
||||
* We recommend to use the static factory method {@link Aggregation#group(Fields)} instead of creating instances of this
|
||||
* class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/group/#stage._S_group
|
||||
* @author Sebastian Herold
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Gustavo de Geus
|
||||
* @author Christoph Strobl
|
||||
* @since 1.3
|
||||
* @see <a href="https://docs.mongodb.org/manual/reference/aggregation/group/">MongoDB Aggregation Framework: $group</a>
|
||||
*/
|
||||
public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
|
||||
@@ -311,6 +312,51 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
return newBuilder(GroupOps.MAX, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $stdDevSamp}-expression that for the given
|
||||
* field-reference.
|
||||
*
|
||||
* @param reference must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public GroupOperationBuilder stdDevSamp(String reference) {
|
||||
return newBuilder(GroupOps.STD_DEV_SAMP, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $stdDevSamp}-expression that for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public GroupOperationBuilder stdDevSamp(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.STD_DEV_SAMP, null, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $stdDevPop}-expression that for the given field-reference.
|
||||
*
|
||||
* @param reference must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public GroupOperationBuilder stdDevPop(String reference) {
|
||||
return newBuilder(GroupOps.STD_DEV_POP, reference, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an {@link GroupOperationBuilder} for an {@code $stdDevPop}-expression that for the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expr must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public GroupOperationBuilder stdDevPop(AggregationExpression expr) {
|
||||
return newBuilder(GroupOps.STD_DEV_POP, null, expr);
|
||||
}
|
||||
|
||||
private GroupOperationBuilder newBuilder(Keyword keyword, String reference, Object value) {
|
||||
return new GroupOperationBuilder(this, new Operation(keyword, null, reference, value));
|
||||
}
|
||||
@@ -375,21 +421,18 @@ public class GroupOperation implements FieldsExposingAggregationOperation {
|
||||
|
||||
private static enum GroupOps implements Keyword {
|
||||
|
||||
SUM, LAST, FIRST, PUSH, AVG, MIN, MAX, ADD_TO_SET, COUNT;
|
||||
SUM("$sum"), LAST("$last"), FIRST("$first"), PUSH("$push"), AVG("$avg"), MIN("$min"), MAX("$max"), ADD_TO_SET("$addToSet"), STD_DEV_POP("$stdDevPop"), STD_DEV_SAMP("$stdDevSamp");
|
||||
|
||||
private String mongoOperator;
|
||||
|
||||
GroupOps(String mongoOperator) {
|
||||
this.mongoOperator = mongoOperator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
String[] parts = name().split("_");
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (String part : parts) {
|
||||
String lowerCase = part.toLowerCase(Locale.US);
|
||||
builder.append(builder.length() == 0 ? lowerCase : StringUtils.capitalize(lowerCase));
|
||||
}
|
||||
|
||||
return "$" + builder.toString();
|
||||
return mongoOperator;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Encapsulates the aggregation framework {@code $ifNull} operator. Replacement values can be either {@link Field field
|
||||
* references}, values of simple MongoDB types or values that can be converted to a simple MongoDB type.
|
||||
*
|
||||
* @see http://docs.mongodb.com/manual/reference/operator/aggregation/ifNull/
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public class IfNullOperator implements AggregationExpression {
|
||||
|
||||
private final Field field;
|
||||
private final Object value;
|
||||
|
||||
/**
|
||||
* Creates a new {@link IfNullOperator} for the given {@link Field} and replacement {@code value}.
|
||||
*
|
||||
* @param field must not be {@literal null}.
|
||||
* @param value must not be {@literal null}.
|
||||
*/
|
||||
public IfNullOperator(Field field, Object value) {
|
||||
|
||||
Assert.notNull(field, "Field must not be null!");
|
||||
Assert.notNull(value, "'Replacement-value' must not be null!");
|
||||
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
|
||||
*/
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
|
||||
List<Object> list = new ArrayList<Object>();
|
||||
|
||||
list.add(context.getReference(field).toString());
|
||||
list.add(resolve(value, context));
|
||||
|
||||
return new Document("$ifNull", list);
|
||||
}
|
||||
|
||||
private Object resolve(Object value, AggregationOperationContext context) {
|
||||
|
||||
if (value instanceof Field) {
|
||||
return context.getReference((Field) value).toString();
|
||||
} else if (value instanceof Document) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return context.getMappedObject(new Document("$set", value)).get("$set");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builder that allows fluent creation of {@link IfNullOperator}.
|
||||
*
|
||||
* @return a new {@link IfNullBuilder}.
|
||||
*/
|
||||
public static IfNullBuilder newBuilder() {
|
||||
return IfNullOperatorBuilder.newBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.10
|
||||
*/
|
||||
public static interface IfNullBuilder {
|
||||
|
||||
/**
|
||||
* @param field the field to check for a {@literal null} value, field reference must not be {@literal null}.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder ifNull(Field field);
|
||||
|
||||
/**
|
||||
* @param field the field to check for a {@literal null} value, field name must not be {@literal null} or empty.
|
||||
* @return the {@link ThenBuilder}
|
||||
*/
|
||||
ThenBuilder ifNull(String field);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.10
|
||||
*/
|
||||
public static interface ThenBuilder {
|
||||
|
||||
/**
|
||||
* @param field the field holding the replacement value, must not be {@literal null}.
|
||||
* @return the {@link IfNullOperator}
|
||||
*/
|
||||
IfNullOperator thenReplaceWith(Field field);
|
||||
|
||||
/**
|
||||
* @param value the value to be used if the {@code $ifNull }condition evaluates {@literal true}. Can be a
|
||||
* {@link Document}, a value that is supported by MongoDB or a value that can be converted to a MongoDB
|
||||
* representation but must not be {@literal null}.
|
||||
* @return the {@link IfNullOperator}
|
||||
*/
|
||||
IfNullOperator thenReplaceWith(Object value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for fluent {@link IfNullOperator} creation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.10
|
||||
*/
|
||||
public static final class IfNullOperatorBuilder implements IfNullBuilder, ThenBuilder {
|
||||
|
||||
private Field field;
|
||||
|
||||
private IfNullOperatorBuilder() {}
|
||||
|
||||
/**
|
||||
* Creates a new builder for {@link IfNullOperator}.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public static IfNullOperatorBuilder newBuilder() {
|
||||
return new IfNullOperatorBuilder();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.IfNullOperator.IfNullBuilder#ifNull(org.springframework.data.mongodb.core.aggregation.Field)
|
||||
*/
|
||||
public ThenBuilder ifNull(Field field) {
|
||||
|
||||
Assert.notNull(field, "Field must not be null!");
|
||||
|
||||
this.field = field;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.IfNullOperator.IfNullBuilder#ifNull(java.lang.String)
|
||||
*/
|
||||
public ThenBuilder ifNull(String name) {
|
||||
|
||||
Assert.hasText(name, "Field name must not be null or empty!");
|
||||
|
||||
this.field = Fields.field(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.IfNullOperator.ThenReplaceBuilder#thenReplaceWith(org.springframework.data.mongodb.core.aggregation.Field)
|
||||
*/
|
||||
@Override
|
||||
public IfNullOperator thenReplaceWith(Field replacementField) {
|
||||
|
||||
Assert.notNull(replacementField, "Replacement field must not be null!");
|
||||
|
||||
return new IfNullOperator(this.field, replacementField);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.IfNullOperator.ThenReplaceBuilder#thenReplaceWith(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public IfNullOperator thenReplaceWith(Object value) {
|
||||
|
||||
Assert.notNull(value, "'Replacement-value' must not be null!");
|
||||
|
||||
return new IfNullOperator(this.field, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,17 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ExposedFieldsAggregationOperationContext} that inherits fields from its parent
|
||||
* {@link AggregationOperationContext}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.9
|
||||
*/
|
||||
class InheritingExposedFieldsAggregationOperationContext extends ExposedFieldsAggregationOperationContext {
|
||||
|
||||
@@ -40,7 +39,7 @@ class InheritingExposedFieldsAggregationOperationContext extends ExposedFieldsAg
|
||||
AggregationOperationContext previousContext) {
|
||||
|
||||
super(exposedFields, previousContext);
|
||||
Assert.notNull(previousContext, "PreviousContext must not be null!");
|
||||
|
||||
this.previousContext = previousContext;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,12 +23,12 @@ import org.springframework.util.Assert;
|
||||
* <p>
|
||||
* We recommend to use the static factory method {@link Aggregation#limit(long)} instead of creating instances of this
|
||||
* class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/limit/
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.3
|
||||
* @see <a href="https://docs.mongodb.org/manual/reference/aggregation/limit/">MongoDB Aggregation Framework: $limit</a>
|
||||
*/
|
||||
public class LimitOperation implements AggregationOperation {
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Gateway to {@literal literal} aggregation operations.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public class LiteralOperators {
|
||||
|
||||
/**
|
||||
* Take the value referenced by given {@literal value}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static LiteralOperatorFactory valueOf(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new LiteralOperatorFactory(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class LiteralOperatorFactory {
|
||||
|
||||
private final Object value;
|
||||
|
||||
/**
|
||||
* Creates new {@link LiteralOperatorFactory} for given {@literal value}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
*/
|
||||
public LiteralOperatorFactory(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Literal} that returns the associated value without parsing.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Literal asLiteral() {
|
||||
return Literal.asLiteral(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $literal}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class Literal extends AbstractAggregationExpression {
|
||||
|
||||
private Literal(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$literal";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link Literal}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Literal asLiteral(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Literal(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,8 +27,8 @@ import org.springframework.util.Assert;
|
||||
* @author Alessio Fachechi
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/lookup/#stage._S_lookup
|
||||
* @since 1.9
|
||||
* @see <a href="https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/">MongoDB Aggregation Framework: $lookup</a>
|
||||
*/
|
||||
public class LookupOperation implements FieldsExposingAggregationOperation, InheritsFieldsAggregationOperation {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,11 +26,11 @@ import org.springframework.util.Assert;
|
||||
* {@link Aggregation#match(org.springframework.data.mongodb.core.query.Criteria)} instead of creating instances of this
|
||||
* class directly.
|
||||
*
|
||||
* @see http://docs.mongodb.org/manual/reference/aggregation/match/
|
||||
* @author Sebastian Herold
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.3
|
||||
* @see <a href="https://docs.mongodb.com/manual/reference/operator/aggregation/match/">MongoDB Aggregation Framework: $match</a>
|
||||
*/
|
||||
public class MatchOperation implements AggregationOperation {
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2016. the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
|
||||
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExpressionFieldReference;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link AggregationOperationContext} that delegates {@link FieldReference} resolution and mapping to a parent one, but
|
||||
* assures {@link FieldReference} get converted into {@link ExpressionFieldReference} using {@code $$} to ref an inner
|
||||
* variable.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
class NestedDelegatingExpressionAggregationOperationContext implements AggregationOperationContext {
|
||||
|
||||
private final AggregationOperationContext delegate;
|
||||
|
||||
/**
|
||||
* Creates new {@link NestedDelegatingExpressionAggregationOperationContext}.
|
||||
*
|
||||
* @param referenceContext must not be {@literal null}.
|
||||
*/
|
||||
public NestedDelegatingExpressionAggregationOperationContext(AggregationOperationContext referenceContext) {
|
||||
|
||||
Assert.notNull(referenceContext, "Reference context must not be null!");
|
||||
this.delegate = referenceContext;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(org.bson.Document)
|
||||
*/
|
||||
@Override
|
||||
public Document getMappedObject(Document document) {
|
||||
return delegate.getMappedObject(document);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(org.springframework.data.mongodb.core.aggregation.Field)
|
||||
*/
|
||||
@Override
|
||||
public FieldReference getReference(Field field) {
|
||||
return new ExpressionFieldReference(delegate.getReference(field));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getReference(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public FieldReference getReference(String name) {
|
||||
return new ExpressionFieldReference(delegate.getReference(name));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user