001/*
002 * (C) Copyright 2014-2020 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.storage.dbs;
020
021import java.io.Serializable;
022import java.util.Collection;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026import java.util.stream.Stream;
027
028import org.nuxeo.ecm.core.api.PartialList;
029import org.nuxeo.ecm.core.api.ScrollResult;
030import org.nuxeo.ecm.core.api.lock.LockManager;
031import org.nuxeo.ecm.core.query.sql.model.OrderByClause;
032import org.nuxeo.ecm.core.storage.State;
033import org.nuxeo.ecm.core.storage.State.StateDiff;
034import org.nuxeo.ecm.core.storage.dbs.DBSTransactionState.ChangeTokenUpdater;
035
036/**
037 * Interface for a connection to a {@link DBSRepository}. The connection maintains state when it is transactional.
038 *
039 * @since 11.1 (introduced in 5.9.4 as DBSRepository)
040 */
041public interface DBSConnection extends AutoCloseable, LockManager {
042
043    /**
044     * Closes this connection.
045     */
046    @Override
047    void close();
048
049    /**
050     * Gets the root id.
051     *
052     * @return the root id.
053     */
054    String getRootId();
055
056    /**
057     * Generates a new id for a document.
058     *
059     * @return the new id
060     */
061    String generateNewId();
062
063    /**
064     * Reads the state of a document.
065     *
066     * @param id the document id
067     * @return the document state, or {@code null} if not found
068     */
069    State readState(String id);
070
071    /**
072     * Reads the partial state of a document.
073     *
074     * @param id the document id
075     * @param keys the keys to read
076     * @return the document partial state, or {@code null} if not found
077     * @since 9.10
078     */
079    default State readPartialState(String id, Collection<String> keys) {
080        // overrides should optimize to only return the required keys and nothing more
081        return readState(id);
082    }
083
084    /**
085     * Reads the states of several documents.
086     * <p>
087     * The returned states may be in a different order than the ids.
088     *
089     * @param ids the document ids
090     * @return the document states, an element by be {@code null} if not found
091     */
092    List<State> readStates(List<String> ids);
093
094    /**
095     * Creates a document.
096     *
097     * @param state the document state
098     */
099    void createState(State state);
100
101    /**
102     * Creates documents.
103     *
104     * @param states the document states
105     */
106    default void createStates(List<State> states) {
107        states.forEach(this::createState);
108    }
109
110    /**
111     * Updates a document.
112     *
113     * @param id the document id
114     * @param diff the diff to apply
115     * @param changeTokenUpdater how to get and update the change token (may be {@code null})
116     */
117    void updateState(String id, StateDiff diff, ChangeTokenUpdater changeTokenUpdater);
118
119    /**
120     * Deletes a set of document.
121     *
122     * @param ids the document ids
123     */
124    void deleteStates(Set<String> ids);
125
126    /**
127     * Reads the state of a child document.
128     *
129     * @param parentId the parent document id
130     * @param name the name of the child
131     * @param ignored a set of document ids that should not be considered
132     * @return the state of the child document, or {@code null} if not found
133     */
134    State readChildState(String parentId, String name, Set<String> ignored);
135
136    /**
137     * Checks if a document has a child with the given name
138     *
139     * @param parentId the parent document id
140     * @param name the name of the child
141     * @param ignored a set of document ids that should not be considered
142     * @return {@code true} if the child exists, {@code false} if not
143     */
144    boolean hasChild(String parentId, String name, Set<String> ignored);
145
146    /**
147     * Queries the repository for documents having key = value.
148     *
149     * @param key the key
150     * @param value the value
151     * @param ignored a set of document ids that should not be considered
152     * @return the document states matching the query
153     */
154    List<State> queryKeyValue(String key, Object value, Set<String> ignored);
155
156    /**
157     * Queries the repository for documents having key1 = value1 and key2 = value2.
158     *
159     * @param key1 the first key
160     * @param value1 the first value
161     * @param key2 the second key
162     * @param value2 the second value
163     * @param ignored a set of document ids that should not be considered
164     * @return the document states matching the query
165     */
166    List<State> queryKeyValue(String key1, Object value1, String key2, Object value2, Set<String> ignored);
167
168    /**
169     * Queries the repository for documents having key1 = value1 and key2 ${operator} value2.
170     *
171     * @param key1 the first key
172     * @param value1 the first value
173     * @param key2 the second key
174     * @param operator the operator to apply between key2 and value2
175     * @param value2 the second value
176     * @param ignored a set of document ids that should not be considered
177     * @return the document states matching the query
178     * @since 11.1
179     */
180    List<State> queryKeyValueWithOperator(String key1, Object value1, String key2, DBSQueryOperator operator,
181            Object value2, Set<String> ignored);
182
183    /**
184     * Returns a stream of descendants from a given root document, in no particular order. This does not include
185     * information about the root document itself.
186     * <p>
187     * THE STREAM MUST BE CLOSED WHEN DONE to release resources.
188     *
189     * @param id the root document id
190     * @param keys what to collect about the descendants in addition to their ids
191     * @return a stream of {@link State}s; THE STREAM MUST BE CLOSED WHEN DONE
192     * @since 9.3
193     */
194    Stream<State> getDescendants(String id, Set<String> keys);
195
196    /**
197     * Returns a stream of descendants from a given root document, in no particular order. This does not include
198     * information about the root document itself.
199     * <p>
200     * THE STREAM MUST BE CLOSED WHEN DONE to release resources.
201     *
202     * @param id the root document id
203     * @param keys what to collect about the descendants in addition to their ids
204     * @param limit the maximum number of descendants to return
205     * @return a stream of {@link State}s; THE STREAM MUST BE CLOSED WHEN DONE
206     * @since 9.10
207     */
208    default Stream<State> getDescendants(String id, Set<String> keys, int limit) {
209        // limit unused by default, override for a more efficient implementation
210        return getDescendants(id, keys);
211    }
212
213    /**
214     * Queries the repository to check if there are documents having key = value.
215     *
216     * @param key the key
217     * @param value the value
218     * @param ignored a set of document ids that should not be considered
219     * @return {@code true} if the query matches at least one document, {@code false} if the query matches nothing
220     */
221    boolean queryKeyValuePresence(String key, String value, Set<String> ignored);
222
223    /**
224     * Queries the repository for documents matching a NXQL query, and returns a projection of the documents.
225     *
226     * @param evaluator the map-based evaluator for the query
227     * @param orderByClause an ORDER BY clause
228     * @param distinctDocuments {@code true} if the projection should return a maximum of one row per document
229     * @param limit the limit on the number of documents to return
230     * @param offset the offset in the list of documents to return
231     * @param countUpTo if {@code -1}, count the total size without offset/limit.<br>
232     *            If {@code 0}, don't count the total size, set it to {@code -1} .<br>
233     *            If {@code n}, count the total number if there are less than n documents otherwise set the total size
234     *            to {@code -2}.
235     * @return a partial list of maps containing the NXQL projections requested, and the total size according to
236     *         countUpTo
237     */
238    PartialList<Map<String, Serializable>> queryAndFetch(DBSExpressionEvaluator evaluator, OrderByClause orderByClause,
239            boolean distinctDocuments, int limit, int offset, int countUpTo);
240
241    /**
242     * Executes the given query and returns the first batch of results containing id of documents, next batch must be
243     * requested within the {@code keepAliveSeconds} delay.
244     *
245     * @since 8.4
246     */
247    ScrollResult<String> scroll(DBSExpressionEvaluator evaluator, int batchSize, int keepAliveSeconds);
248
249    /**
250     * Get the next batch of results containing id of documents, the {@code scrollId} is part of the previous
251     * {@link ScrollResult} response.
252     *
253     * @since 8.4
254     */
255    ScrollResult<String> scroll(String scrollId);
256
257    /**
258     * Starts a new transaction.
259     *
260     * @since 8.10
261     * @see DBSRepository#supportsTransactions
262     */
263    void begin();
264
265    /**
266     * Commits the current transaction.
267     *
268     * @since 8.10
269     * @see DBSRepository#supportsTransactions
270     */
271    void commit();
272
273    /**
274     * Rolls back the current transaction.
275     *
276     * @since 8.10
277     * @see DBSRepository#supportsTransactions
278     */
279    void rollback();
280
281    /**
282     * Abstracts queries with operators.
283     *
284     * @since 11.1
285     */
286    enum DBSQueryOperator {
287        NOT_IN, IN;
288    }
289
290}