001/*
002 * (C) Copyright 2014-2017 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.blob.BlobManager;
031import org.nuxeo.ecm.core.model.LockManager;
032import org.nuxeo.ecm.core.model.Repository;
033import org.nuxeo.ecm.core.query.sql.model.OrderByClause;
034import org.nuxeo.ecm.core.storage.FulltextConfiguration;
035import org.nuxeo.ecm.core.storage.State;
036import org.nuxeo.ecm.core.storage.State.StateDiff;
037import org.nuxeo.ecm.core.storage.dbs.DBSTransactionState.ChangeTokenUpdater;
038
039/**
040 * Interface for a {@link Repository} for Document-Based Storage.
041 *
042 * @since 5.9.4
043 */
044public interface DBSRepository extends Repository, LockManager {
045
046    /**
047     * Gets the blob manager.
048     *
049     * @return the blob manager.
050     */
051    BlobManager getBlobManager();
052
053    /**
054     * Gets the fulltext configuration.
055     *
056     * @return the fulltext configuration
057     * @since 7.10-HF04, 8.1
058     */
059    FulltextConfiguration getFulltextConfiguration();
060
061    /**
062     * Checks if fulltext indexing is disabled.
063     *
064     * @return {@code true} if fulltext indexing is disabled, {@code false} if it is enabled
065     * @since 7.1, 6.0-HF02
066     */
067    boolean isFulltextDisabled();
068
069    /**
070     * Checks if database-managed document change tokens are enabled.
071     *
072     * @return {@code true} if the database maintains document change tokens
073     * @since 9.1
074     */
075    boolean isChangeTokenEnabled();
076
077    /**
078     * Gets the root id.
079     *
080     * @return the root id.
081     */
082    String getRootId();
083
084    /**
085     * Generates a new id for a document.
086     *
087     * @return the new id
088     */
089    String generateNewId();
090
091    /**
092     * Reads the state of a document.
093     *
094     * @param id the document id
095     * @return the document state, or {@code null} if not found
096     */
097    State readState(String id);
098
099    /**
100     * Reads the partial state of a document.
101     *
102     * @param id the document id
103     * @param keys the keys to read
104     * @return the document partial state, or {@code null} if not found
105     * @since 9.10
106     */
107    default State readPartialState(String id, Collection<String> keys) {
108        // overrides should optimize to only return the required keys and nothing more
109        return readState(id);
110    }
111
112    /**
113     * Reads the states of several documents.
114     * <p>
115     * The returned states may be in a different order than the ids.
116     *
117     * @param ids the document ids
118     * @return the document states, an element by be {@code null} if not found
119     */
120    List<State> readStates(List<String> ids);
121
122    /**
123     * Creates a document.
124     *
125     * @param state the document state
126     */
127    void createState(State state);
128
129    /**
130     * Creates documents.
131     *
132     * @param states the document states
133     */
134    default void createStates(List<State> states) {
135        states.forEach(this::createState);
136    }
137
138    /**
139     * Updates a document.
140     *
141     * @param id the document id
142     * @param diff the diff to apply
143     * @param changeTokenUpdater how to get and update the change token (may be {@code null})
144     */
145    void updateState(String id, StateDiff diff, ChangeTokenUpdater changeTokenUpdater);
146
147    /**
148     * Deletes a set of document.
149     *
150     * @param ids the document ids
151     */
152    void deleteStates(Set<String> ids);
153
154    /**
155     * Reads the state of a child document.
156     *
157     * @param parentId the parent document id
158     * @param name the name of the child
159     * @param ignored a set of document ids that should not be considered
160     * @return the state of the child document, or {@code null} if not found
161     */
162    State readChildState(String parentId, String name, Set<String> ignored);
163
164    /**
165     * Checks if a document has a child with the given name
166     *
167     * @param parentId the parent document id
168     * @param name the name of the child
169     * @param ignored a set of document ids that should not be considered
170     * @return {@code true} if the child exists, {@code false} if not
171     */
172    boolean hasChild(String parentId, String name, Set<String> ignored);
173
174    /**
175     * Queries the repository for documents having key = value.
176     *
177     * @param key the key
178     * @param value the value
179     * @param ignored a set of document ids that should not be considered
180     * @return the document states matching the query
181     */
182    List<State> queryKeyValue(String key, Object value, Set<String> ignored);
183
184    /**
185     * Queries the repository for documents having key1 = value1 and key2 = value2.
186     *
187     * @param key1 the first key
188     * @param value1 the first value
189     * @param key2 the second key
190     * @param value2 the second value
191     * @param ignored a set of document ids that should not be considered
192     * @return the document states matching the query
193     */
194    List<State> queryKeyValue(String key1, Object value1, String key2, Object value2, Set<String> ignored);
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     * @return a stream of {@link State}s; THE STREAM MUST BE CLOSED WHEN DONE
205     * @since 9.3
206     */
207    Stream<State> getDescendants(String id, Set<String> keys);
208
209    /**
210     * Returns a stream of descendants from a given root document, in no particular order. This does not include
211     * information about the root document itself.
212     * <p>
213     * THE STREAM MUST BE CLOSED WHEN DONE to release resources.
214     *
215     * @param id the root document id
216     * @param keys what to collect about the descendants in addition to their ids
217     * @param limit the maximum number of descendants to return
218     * @return a stream of {@link State}s; THE STREAM MUST BE CLOSED WHEN DONE
219     * @since 9.10
220     */
221    default Stream<State> getDescendants(String id, Set<String> keys, int limit) {
222        // limit unused by default, override for a more efficient implementation
223        return getDescendants(id, keys);
224    }
225
226    /**
227     * Queries the repository to check if there are documents having key = value.
228     *
229     * @param key the key
230     * @param value the value
231     * @param ignored a set of document ids that should not be considered
232     * @return {@code true} if the query matches at least one document, {@code false} if the query matches nothing
233     */
234    boolean queryKeyValuePresence(String key, String value, Set<String> ignored);
235
236    /**
237     * Queries the repository for documents matching a NXQL query, and returns a projection of the documents.
238     *
239     * @param evaluator the map-based evaluator for the query
240     * @param orderByClause an ORDER BY clause
241     * @param distinctDocuments {@code true} if the projection should return a maximum of one row per document
242     * @param limit the limit on the number of documents to return
243     * @param offset the offset in the list of documents to return
244     * @param countUpTo if {@code -1}, count the total size without offset/limit.<br>
245     *            If {@code 0}, don't count the total size, set it to {@code -1} .<br>
246     *            If {@code n}, count the total number if there are less than n documents otherwise set the total size
247     *            to {@code -2}.
248     * @return a partial list of maps containing the NXQL projections requested, and the total size according to
249     *         countUpTo
250     */
251    PartialList<Map<String, Serializable>> queryAndFetch(DBSExpressionEvaluator evaluator, OrderByClause orderByClause,
252            boolean distinctDocuments, int limit, int offset, int countUpTo);
253
254    /**
255     * Gets the lock manager for this repository.
256     *
257     * @return the lock manager
258     * @since 7.4
259     */
260    LockManager getLockManager();
261
262    /**
263     * Executes the given query and returns the first batch of results containing id of documents, next batch must be
264     * requested within the {@code keepAliveSeconds} delay.
265     *
266     * @since 8.4
267     */
268    ScrollResult<String> scroll(DBSExpressionEvaluator evaluator, int batchSize, int keepAliveSeconds);
269
270    /**
271     * Get the next batch of results containing id of documents, the {@code scrollId} is part of the previous
272     * {@link ScrollResult} response.
273     *
274     * @since 8.4
275     */
276    ScrollResult<String> scroll(String scrollId);
277
278    /**
279     * Called when created a transaction.
280     *
281     * @since 8.10
282     */
283    default void begin() {
284
285    }
286
287    /**
288     * Saves and flushes to database.
289     *
290     * @since 8.10
291     */
292    default void commit() {
293
294    }
295
296    /**
297     * Rolls back the save state by applying the undo log.
298     *
299     * @since 8.10
300     */
301    default void rollback() {
302
303    }
304
305}