001/*
002 * (C) Copyright 2006-2016 Nuxeo SA (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.query.sql;
020
021import java.time.ZoneOffset;
022import java.time.ZonedDateTime;
023import java.time.format.DateTimeParseException;
024
025import org.nuxeo.common.utils.PeriodAndDuration;
026import org.nuxeo.runtime.api.Framework;
027
028/**
029 * This defines the constants for NXQL queries.
030 *
031 * @author Florent Guillaume
032 */
033public class NXQL {
034
035    /**
036     * Property containing the test value of the current date for {@link #nowPlusPeriodAndDuration}.
037     * <p>
038     * Only for tests, not a public API.
039     *
040     * @since 11.1
041     */
042    public static final String TEST_NXQL_NOW = "test.nxql.now";
043
044    // constant utility class
045    private NXQL() {
046    }
047
048    /** The NXQL query type. */
049    public static final String NXQL = "NXQL";
050
051    public static final String ECM_PREFIX = "ecm:";
052
053    public static final String ECM_UUID = "ecm:uuid";
054
055    public static final String ECM_PATH = "ecm:path";
056
057    public static final String ECM_NAME = "ecm:name";
058
059    public static final String ECM_POS = "ecm:pos";
060
061    public static final String ECM_PARENTID = "ecm:parentId";
062
063    public static final String ECM_MIXINTYPE = "ecm:mixinType";
064
065    public static final String ECM_PRIMARYTYPE = "ecm:primaryType";
066
067    public static final String ECM_ISPROXY = "ecm:isProxy";
068
069    public static final String ECM_ISVERSION = "ecm:isVersion";
070
071    /**
072     * @since 5.7.3
073     */
074    public static final String ECM_ISVERSION_OLD = "ecm:isCheckedInVersion";
075
076    public static final String ECM_LIFECYCLESTATE = "ecm:currentLifeCycleState";
077
078    public static final String ECM_VERSIONLABEL = "ecm:versionLabel";
079
080    public static final String ECM_FULLTEXT = "ecm:fulltext";
081
082    public static final String ECM_FULLTEXT_JOBID = "ecm:fulltextJobId";
083
084    /**
085     * @since 6.0
086     */
087    public static final String ECM_FULLTEXT_SCORE = "ecm:fulltextScore";
088
089    /**
090     * @since 5.4.2
091     */
092    public static final String ECM_LOCK_OWNER = "ecm:lockOwner";
093
094    /**
095     * @since 5.4.2
096     */
097    public static final String ECM_LOCK_CREATED = "ecm:lockCreated";
098
099    /**
100     * @since 5.7
101     */
102    public static final String ECM_TAG = "ecm:tag";
103
104    /**
105     * @since 5.7
106     */
107    public static final String ECM_PROXY_TARGETID = "ecm:proxyTargetId";
108
109    /**
110     * @since 5.7
111     */
112    public static final String ECM_PROXY_VERSIONABLEID = "ecm:proxyVersionableId";
113
114    /**
115     * @since 5.7.3
116     */
117    public static final String ECM_ISCHECKEDIN = "ecm:isCheckedIn";
118
119    /**
120     * @since 5.7.3
121     */
122    public static final String ECM_ISLATESTVERSION = "ecm:isLatestVersion";
123
124    /**
125     * @since 5.7.3
126     */
127    public static final String ECM_ISLATESTMAJORVERSION = "ecm:isLatestMajorVersion";
128
129    /**
130     * @since 5.7.3
131     */
132    public static final String ECM_VERSIONCREATED = "ecm:versionCreated";
133
134    /**
135     * @since 5.7.3
136     */
137    public static final String ECM_VERSIONDESCRIPTION = "ecm:versionDescription";
138
139    /**
140     * @since 5.7.3
141     */
142    public static final String ECM_VERSION_VERSIONABLEID = "ecm:versionVersionableId";
143
144    /**
145     * @since 6.0
146     */
147    public static final String ECM_ANCESTORID = "ecm:ancestorId";
148
149    /**
150     * @since 6.0-HF06, 7.2
151     */
152    public static final String ECM_ACL = "ecm:acl";
153
154    /**
155     * Suffix for ecm:acl, like in {@code ecm:acl/}{@code *}{@code /principal}
156     *
157     * @since 6.0-HF06, 7.2
158     */
159    public static final String ECM_ACL_PRINCIPAL = "principal";
160
161    /**
162     * Suffix for ecm:acl, like in {@code ecm:acl/}{@code *}{@code /permission}
163     *
164     * @since 6.0-HF06, 7.2
165     */
166    public static final String ECM_ACL_PERMISSION = "permission";
167
168    /**
169     * Suffix for ecm:acl, like in {@code ecm:acl/}{@code *}{@code /grant}
170     *
171     * @since 6.0-HF06, 7.2
172     */
173    public static final String ECM_ACL_GRANT = "grant";
174
175    /**
176     * Suffix for ecm:acl, like in {@code ecm:acl/}{@code *}{@code /name}
177     *
178     * @since 6.0-HF06, 7.2
179     */
180    public static final String ECM_ACL_NAME = "name";
181
182    /**
183     * Suffix for ecm:acl, like in {@code ecm:acl/}{@code *}{@code /pos}
184     *
185     * @since 6.0-HF06, 7.2
186     */
187    public static final String ECM_ACL_POS = "pos";
188
189    /**
190     * Suffix for ecm:acl, like in {@code ecm:acl/}{@code *}{@code /creator}
191     *
192     * @since 7.4
193     */
194    public static final String ECM_ACL_CREATOR = "creator";
195
196    /**
197     * Suffix for ecm:acl, like in {@code ecm:acl/}{@code *}{@code /begin}
198     *
199     * @since 7.4
200     */
201    public static final String ECM_ACL_BEGIN = "begin";
202
203    /**
204     * Suffix for ecm:acl, like in {@code ecm:acl/}{@code *}{@code /end}
205     *
206     * @since 7.4
207     */
208    public static final String ECM_ACL_END = "end";
209
210    /**
211     * Suffix for ecm:acl, like in {@code ecm:acl/}{@code *}{@code /status}
212     *
213     * @since 7.4
214     */
215    public static final String ECM_ACL_STATUS = "status";
216
217    /**
218     * @since 10.1
219     */
220    public static final String ECM_ISTRASHED = "ecm:isTrashed";
221
222    /** @since 11.1 */
223    public static final String ECM_ISRECORD = "ecm:isRecord";
224
225    /** @since 11.1 */
226    public static final String ECM_RETAINUNTIL = "ecm:retainUntil";
227
228    /** @since 11.1 */
229    public static final String ECM_HASLEGALHOLD = "ecm:hasLegalHold";
230
231    /**
232     * The function returning the current datetime. It can optionally have as an argument a duration that will be added
233     * to the current datetime, expressed as a ISO 8601 period.
234     * <p>
235     * See {@link PeriodAndDuration#parse} for the exact format.
236     *
237     * @see PeriodAndDuration#parse
238     * @since 11.1
239     */
240    public static final String NOW_FUNCTION = "NOW";
241
242    /**
243     * Escapes a string into a single-quoted string for NXQL.
244     * <p>
245     * Any single quote or backslash characters are escaped with a backslash.
246     *
247     * @param s the string to escape
248     * @return the escaped string
249     * @since 5.7, 5.6.0-HF08
250     */
251    public static String escapeString(String s) {
252        return "'" + escapeStringInner(s) + "'";
253    }
254
255    /**
256     * Escapes a string (assumed to be single quoted) for NXQL.
257     * <p>
258     * Any single quote or backslash characters are escaped with a backslash.
259     *
260     * @param s the string to escape
261     * @return the escaped string, without external quotes
262     * @since 5.7, 5.6.0-HF08
263     */
264    public static String escapeStringInner(String s) {
265        // backslash -> backslash backslash
266        // quote -> backslash quote
267        // newline -> backslash n
268        return s.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'").replaceAll("\n", "\\\\n");
269    }
270
271    /**
272     * Returns the current dateTime to which the period and duration (if present) has been added.
273     *
274     * @param periodAndDurationText the period and duration as text, or {@code null}
275     * @return the current dateTime to which the period and duration has been added
276     * @throws IllegalArgumentException if the period and duration cannot be parsed
277     * @since 11.1
278     */
279    // also used by NxqlQueryConverter
280    public static ZonedDateTime nowPlusPeriodAndDuration(String periodAndDurationText) {
281        ZonedDateTime now;
282        if (Framework.getProperty(TEST_NXQL_NOW) != null) {
283            now = ZonedDateTime.parse(Framework.getProperty(TEST_NXQL_NOW));
284        } else {
285            now = ZonedDateTime.now(ZoneOffset.UTC);
286        }
287        if (periodAndDurationText == null) {
288            return now;
289        } else {
290            PeriodAndDuration pd;
291            try {
292                pd = PeriodAndDuration.parse(periodAndDurationText);
293            } catch (DateTimeParseException e) {
294                throw new IllegalArgumentException("Invalid period: " + periodAndDurationText, e);
295            }
296            return now.plus(pd);
297        }
298    }
299
300}