<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="link.at17.mid.tushare.dao.StockCalendarDao">

    <insert id="insertOrUpdateList" parameterType="list">
        INSERT INTO stock_calendar
            (exchange, "date", is_open, pretrade_date)
        VALUES
        <foreach collection="list" item="item" index="index" separator=",">
            (#{item.exchange}, 
            TO_DATE(#{item.cal_date}, 'YYYYMMDD'),
            (#{item.is_open}::BOOLEAN),
            TO_DATE(#{item.pretrade_date}, 'YYYYMMDD'))
        </foreach>
        ON CONFLICT (exchange, "date")
        DO UPDATE SET
        	exchange = EXCLUDED.exchange,
        	"date" = EXCLUDED."date",
        	is_open = EXCLUDED.is_open,
        	pretrade_date = EXCLUDED.pretrade_date
    </insert>
    
    <select id="getLatest" resultType="link.at17.mid.tushare.data.models.StockCalendar">
        SELECT
            *
        FROM
            stock_calendar
        WHERE 1=1
            <if test="exchange != null">
                AND exchange = #{exchange}
            </if>
        ORDER BY date DESC LIMIT 1
    </select>
    
    <select id="getGreatest" resultType="link.at17.mid.tushare.data.models.StockCalendar">
        SELECT
            *
        FROM
            stock_calendar
        WHERE 1=1
            <if test="exchange != null">
                AND exchange = #{exchange}
            </if>
        ORDER BY date ASC LIMIT 1
    </select>
    
    <sql id="betweenDate">
        <if test="startDate != null and endDate != null">
            AND "date" BETWEEN 
              LEAST(#{startDate}::date, #{endDate}::date) AND GREATEST(#{startDate}::date, #{endDate}::date)
        </if>
        <if test="startDate != null and endDate == null">
            AND "date" &gt;= #{startDate}::date
        </if>
        <if test="startDate == null and endDate != null">
            AND "date" &lt;= #{endDate}::date
        </if>
    </sql>
    
    <select id="countOpenDaysBetween" resultType="java.lang.Long">
        SELECT
            COUNT(DISTINCT "date")
        FROM
            stock_calendar
        WHERE
            is_open = TRUE
            <if test="exchange != null">
                AND exchange = #{exchange}
            </if>
            <include refid="betweenDate"/>
    </select>
    
    <select id="getAllOpenDatesBetween" resultType="java.time.LocalDateTime">
        SELECT
            DISTINCT "date"
        FROM
            stock_calendar
        WHERE
            is_open = TRUE
            <if test="exchange != null">
                AND exchange = #{exchange}
            </if>
            <include refid="betweenDate"/>
        ORDER BY "date" ASC
    </select>
    
    <select id="getOpenDateOffset" resultType="java.time.LocalDateTime">
      <if test="offset lt 0">
        <!-- offset < 0, 往前推 -->
        SELECT "date" FROM stock_calendar
        WHERE
          is_open = TRUE
          AND "date" &lt; #{date}
          <if test="exchange != null">
            AND exchange = #{exchange}
          </if>
        ORDER BY "date" DESC
        LIMIT ABS(#{offset})
      </if>
      <if test="offset gt 0">
        <!-- offset > 0, 往后推 -->
        SELECT "date" FROM stock_calendar
        WHERE 
          is_open = TRUE
          AND "date" > #{date}
          <if test="exchange != null">
              AND exchange = #{exchange}
          </if>
        ORDER BY "date" ASC
        OFFSET #{offset}-1 LIMIT 1
      </if>
      <if test="offset eq 0">
        <!-- offset == 0, 当日 -->
        SELECT "date" FROM stock_calendar
        WHERE
          is_open = TRUE
          AND "date"::date = #{date}::date
          <if test="exchange != null">
              AND exchange = #{exchange}
          </if>
        LIMIT 1
      </if>
    </select>
    
    <select id="getAllOpenDateSence" resultType="java.time.LocalDateTime">
        SELECT DISTINCT
            "date"
        FROM
            stock_calendar
        WHERE
            is_open = TRUE
        <if test="exchange != null">
            AND exchange = #{exchange}
        </if>
        <if test="after != null">
            AND "date" >= #{after}::date
        </if>
        ORDER BY "date" DESC
    </select>
    
    
    <select id="isOpen" resultType="java.lang.Boolean">
        SELECT
            is_open
        FROM
            stock_calendar
        WHERE
            1 = 1
        <if test="date != null">
            AND date::date = #{date}::date
        </if>
        <if test="exchange != null">
            AND exchange = #{exchange}
        </if>
        ORDER BY is_open DESC LIMIT 1
    </select>
    
</mapper>
