【问题标题】:how can i use the Postgres DateRange type with TypeOrm我如何将 Postgres DateRange 类型与 TypeOrm 一起使用
【发布时间】:2020-02-23 13:46:09
【问题描述】:

我尝试使用 Nest.js 框架实现基本的酒店预订系统。 我使用 TypeOrm 和 Postgres 数据库。

我有一个预订实体(酒店房间预订) 并且 Booking 应该有一个 DateRange(从入住到退房日期)。

我找不到如何将 DateRange 对象类型与 TypeOrm 一起使用。

@Entity({ name: 'booking' })
export class Booking{
    @PrimaryGeneratedColumn()
    id: number;

    @Column({ 
        type: 'daterange', // I expect to find DateRange type here
    })
    date_range: any;
}

有什么想法吗?

【问题讨论】:

    标签: postgresql date-range typeorm


    【解决方案1】:

    daterange 类型读取为字符串,写入为字符串。您需要使用/解析postgres range type 的正确字符串表示。

    为了使解析更容易,您可以在表上添加一个约束以仅允许包含范围。将此装饰器添加到类中:

    @Check('booking_range_valid', 'NOT isempty(range) AND lower_inc(range) AND NOT upper_inc(range)')
    

    您需要编写自己的转换器,将 Postgres 日期范围值转换为区间表示。如果你使用 Luxon Interval,你可以使用:

    // Just a small helper to make transformers work with find operators
    export const fixTransformer = (transformer: ValueTransformer) => ({
      to(value: unknown) {
        if (value instanceof FindOperator) {
          return new FindOperator(value.type , transformer.to(value.value),
              value.useParameter, value.multipleParameters);
        } else {
          // eslint-disable-next-line @typescript-eslint/no-unsafe-return
          return transformer.to(value);
        }
      },
      from(value: unknown) {
        // eslint-disable-next-line @typescript-eslint/no-unsafe-return
        return transformer.from(value);
      }
    })
    import {DateTime, Interval} from 'luxon';
    
    // Postgres daterange string representation. [ means that start day is included, ) that end day is not.
    const pattern = /\[(\d{4}-\d{2}-\d{2}),\s*(\d{4}-\d{2}-\d{2})\)/;
    export const  dateRangeIntervalTransformer = fixTransformer({
        to(value: Interval | undefined): string | undefined {
            if (value !== undefined && !value.isValid) {
                throw new Error(`Got an invalid daterange, reason was ${value.invalidReason || '?'}`);
            }
            if (value) {
                if (!value.start.startOf('day').equals(value.start)) {
                    throw new Error('Start of daterange needs to be the start of the day.');
                }
                if (!value.end.startOf('day').equals(value.end)) {
                    throw new Error('End of daterange needs to be the start of the day.');
                }
                return '[' + value.start.toISODate() + ',' + value.end.toISODate() + ')';
            } else {
                return undefined;
            }
        },
        from(value: string | undefined): Interval | undefined {
            if (value) {
                const match = pattern.exec(value);
                if (!match) {
                    throw new Error(`Date range does not match pattern ${pattern.source}: ${value}`);
                }
                return Interval.fromDateTimes(
                    DateTime.fromISO(match[1]).startOf('day'),
                    DateTime.fromISO(match[2]).startOf('day'));
            } else {
                return undefined;
            }
        }
    });
    

    然后在你的实体中使用它:

    @Entity({ name: 'booking' })
    @Check('booking_range_valid', 'NOT isempty(range) AND lower_inc(range) AND NOT upper_inc(range)')
    export class Booking{
        @PrimaryGeneratedColumn()
        id: number;
    
        @Column({ 
            type: 'daterange',
            nullable: false, // < If you allow null, change the converter to handle null values
            transformer: dateRangeIntervalTransformer
        })
        date_range = Interval.after(DateTime.local().startOf('day'), {days: 1}); // < default value
    }
    

    【讨论】:

      猜你喜欢
      • 2019-11-21
      • 1970-01-01
      • 2018-01-23
      • 2021-05-24
      • 1970-01-01
      • 2020-07-18
      • 2014-12-01
      • 2020-08-30
      • 2010-12-04
      相关资源
      最近更新 更多