Drizzle | PostgreSQL 中的点数据类型
This guide assumes familiarity with:

PostgreSQL 有一种特殊的数据类型用于存储几何数据,称为 point。它用于表示二维空间中的一个点。点数据类型表示为一对 (x, y) 坐标。该点需要先接收经度,然后接收纬度。

import { sql } from 'drizzle-orm';

const db = drizzle(...);

await db.execute(
  sql`select point(-90.9, 18.7)`,
);
[ 
  { 
    point: '(-90.9,18.7)' 
  }
]

在 Drizzle 中创建具有 point 数据类型的表的方法:

import { pgTable, point, serial, text } from 'drizzle-orm/pg-core';

export const stores = pgTable('stores', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  location: point('location', { mode: 'xy' }).notNull(),
});

以下是如何在 Drizzle 中将点数据插入表中:

// mode: 'xy'
await db.insert(stores).values({
  name: 'Test',
  location: { x: -90.9, y: 18.7 },
});

// mode: 'tuple'
await db.insert(stores).values({
  name: 'Test',
  location: [-90.9, 18.7],
});

// sql raw
await db.insert(stores).values({
  name: 'Test',
  location: sql`point(-90.9, 18.7)`,
});

要计算对象之间的距离,你可以使用 <-> 运算符。以下是如何在 Drizzle 中按坐标查询最近位置:

import { getTableColumns, sql } from 'drizzle-orm';
import { stores } from './schema';

const point = {
  x: -73.935_242,
  y: 40.730_61,
};

const sqlDistance = sql`location <-> point(${point.x}, ${point.y})`;

await db
  .select({
    ...getTableColumns(stores),
    distance: sql`round((${sqlDistance})::numeric, 2)`,
  })
  .from(stores)
  .orderBy(sqlDistance)
  .limit(1);
select *, round((location <-> point(-73.935242, 40.73061))::numeric, 2)
from stores order by location <-> point(-73.935242, 40.73061)
limit 1;

要筛选行以仅包含 point 类型 location 位于由两个对角点定义的指定矩形边界内的行,你可以使用 <@ 运算符。它会检查第一个对象是否包含在第二个对象中或之上:

const point = {
  x1: -88,
  x2: -73,
  y1: 40,
  y2: 43,
};

await db
  .select()
  .from(stores)
  .where(
    sql`${stores.location} <@ box(point(${point.x1}, ${point.y1}), point(${point.x2}, ${point.y2}))`
  );
select * from stores where location <@ box(point(-88, 40), point(-73, 43));