001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.beanquery;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021/**
022 * A signed, relative-to-request-time duration value: wire literal {@code [+-]<n>(ms|s|m|h|d)} (a request-time offset
023 * that stays a plain literal on the wire).
024 *
025 * <p>
026 * Pass one to any {@link BeanQuery.Builder}/{@link BeanQuery.GroupBuilder} comparison method ({@code eq}, {@code ne},
027 * {@code gt}, {@code gte}, {@code lt}, {@code lte}, {@code between}) on a {@code TIMESTAMP} or numeric-duration
028 * column to mean "relative to the time the request is evaluated" &mdash; for example {@code -24} {@link Unit#H H}
029 * for "24 hours before now." {@link ValueFormat} renders this to the exact wire literal below; the search parser
030 * reads that literal back out of a hand-written or stored search string (on a {@code BOOLEAN} column it is
031 * {@code BAD_VALUE}; on {@code TEXT}, {@code ID}, {@code ENUM} and {@code VERSION} columns the text is kept
032 * literally), and the query engine resolves it against one request-time instant
033 * captured once per query (not {@code now()}/{@code interval} in generated SQL): a {@code TIMESTAMP} column's
034 * literal becomes {@code instant &plusmn; duration}, a numeric-duration column's becomes a plain signed-milliseconds
035 * number. This type is the shared, stable wire format the builder, parser, and engines meet at.
036 *
037 * <h5 class='section'>Example:</h5>
038 * <p class='bjava'>
039 *    <jc>// matches rows whose lastSeen is within the last 24 hours</jc>
040 *    BeanQuery <jv>q</jv> = BeanQuery.<jsm>create</jsm>()
041 *       .gte(<js>"lastSeen"</js>, RelativeDuration.<jsm>ofHours</jsm>(-24))
042 *       .build();
043 *    <jc>// q.getSearch() == "lastSeen=$gte(\"-24h\")"</jc>
044 * </p>
045 *
046 * @param amount The signed magnitude; negative is in the past, positive is in the future, relative to request time.
047 * @param unit The time unit. Must not be <jk>null</jk>.
048 * @since 10.0.0
049 */
050public record RelativeDuration(long amount, Unit unit) {
051
052   /**
053    * Compact constructor &mdash; validates <c>unit</c> is non-<jk>null</jk>.
054    *
055    * @param amount The signed magnitude.
056    * @param unit The time unit. Must not be <jk>null</jk>.
057    */
058   public RelativeDuration {
059      reqnn("unit", unit);
060   }
061
062   /**
063    * Creates a relative-duration literal.
064    *
065    * @param amount The signed magnitude; negative is in the past, positive is in the future.
066    * @param unit The time unit. Must not be <jk>null</jk>.
067    * @return The new literal.
068    */
069   public static RelativeDuration of(long amount, Unit unit) {
070      return new RelativeDuration(amount, unit);
071   }
072
073   /**
074    * Shorthand for {@code of(amount, Unit.MS)}.
075    *
076    * @param amount The signed magnitude.
077    * @return The new literal.
078    */
079   public static RelativeDuration ofMillis(long amount) {
080      return of(amount, Unit.MS);
081   }
082
083   /**
084    * Shorthand for {@code of(amount, Unit.S)}.
085    *
086    * @param amount The signed magnitude.
087    * @return The new literal.
088    */
089   public static RelativeDuration ofSeconds(long amount) {
090      return of(amount, Unit.S);
091   }
092
093   /**
094    * Shorthand for {@code of(amount, Unit.M)}.
095    *
096    * @param amount The signed magnitude.
097    * @return The new literal.
098    */
099   public static RelativeDuration ofMinutes(long amount) {
100      return of(amount, Unit.M);
101   }
102
103   /**
104    * Shorthand for {@code of(amount, Unit.H)}.
105    *
106    * @param amount The signed magnitude.
107    * @return The new literal.
108    */
109   public static RelativeDuration ofHours(long amount) {
110      return of(amount, Unit.H);
111   }
112
113   /**
114    * Shorthand for {@code of(amount, Unit.D)}.
115    *
116    * @param amount The signed magnitude.
117    * @return The new literal.
118    */
119   public static RelativeDuration ofDays(long amount) {
120      return of(amount, Unit.D);
121   }
122
123   /** The duration unit, with its lowercase wire token (design review ยง3 Gap 2). */
124   public enum Unit {
125
126      /** Milliseconds. */
127      MS("ms"),
128
129      /** Seconds. */
130      S("s"),
131
132      /** Minutes. */
133      M("m"),
134
135      /** Hours. */
136      H("h"),
137
138      /** Days. */
139      D("d");
140
141      private final String token;
142
143      Unit(String token) {
144         this.token = token;
145      }
146
147      /**
148       * The lowercase wire token for this unit (e.g. {@code "h"}).
149       *
150       * @return The wire token.
151       */
152      public String token() {
153         return token;
154      }
155   }
156}