Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 60 additions & 32 deletions drizzle-orm/src/pg-core/columns/postgis_extension/utils.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,75 @@
function isHexString(str: string): boolean {
if (!str || str.length === 0) {
return false;
}
return /^(0x)?[\da-f]+(h)?$/i.test(str);
}

function hexToBytes(hex: string): Uint8Array {
const bytes: number[] = [];
for (let c = 0; c < hex.length; c += 2) {
bytes.push(Number.parseInt(hex.slice(c, c + 2), 16));
}
return new Uint8Array(bytes);
const bytes: number[] = [];
for (let c = 0; c < hex.length; c += 2) {
bytes.push(Number.parseInt(hex.slice(c, c + 2), 16));
}
return new Uint8Array(bytes);
}

function bytesToFloat64(bytes: Uint8Array, offset: number): number {
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
for (let i = 0; i < 8; i++) {
view.setUint8(i, bytes[offset + i]!);
}
return view.getFloat64(0, true);
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
for (let i = 0; i < 8; i++) {
view.setUint8(i, bytes[offset + i]!);
}
return view.getFloat64(0, true);
}

export function parseEWKB(hex: string): [number, number] {
const bytes = hexToBytes(hex);
if (isHexString(hex)) {
const bytes = hexToBytes(hex);

let offset = 0;

// Byte order: 1 is little-endian, 0 is big-endian
const byteOrder = bytes[offset];
offset += 1;

const view = new DataView(bytes.buffer);
const geomType = view.getUint32(offset, byteOrder === 1);
offset += 4;

let _srid: number | undefined;
if (geomType & 0x20000000) {
// SRID flag
_srid = view.getUint32(offset, byteOrder === 1);
offset += 4;
}

let offset = 0;
if ((geomType & 0xFFFF) === 1) {
const x = bytesToFloat64(bytes, offset);
offset += 8;
const y = bytesToFloat64(bytes, offset);
offset += 8;

// Byte order: 1 is little-endian, 0 is big-endian
const byteOrder = bytes[offset];
offset += 1;
return [x, y];
}

const view = new DataView(bytes.buffer);
const geomType = view.getUint32(offset, byteOrder === 1);
offset += 4;
throw new Error("Unsupported geometry type");
}

let _srid: number | undefined;
if (geomType & 0x20000000) { // SRID flag
_srid = view.getUint32(offset, byteOrder === 1);
offset += 4;
}
// What was causing https://github.com/drizzle-team/drizzle-orm/issues/2788 was that when using the query builder,
// the expected hex string was actually a GeoJSON string.
// So as a fallback, we can try to parse it as JSON.
// This is not the most efficient way, but it ensures compatibility with the query builder.
if (typeof hex === "string") {
const result = JSON.parse(hex);

if ((geomType & 0xFFFF) === 1) {
const x = bytesToFloat64(bytes, offset);
offset += 8;
const y = bytesToFloat64(bytes, offset);
offset += 8;
if (result.coordinates) {
return result.coordinates;
}
}

return [x, y];
}
if (typeof hex === "object" && (hex as any).coordinates) {
return (hex as any).coordinates;
}

throw new Error('Unsupported geometry type');
throw new Error("Invalid GeoJSON format");
}
157 changes: 79 additions & 78 deletions integration-tests/package.json
Original file line number Diff line number Diff line change
@@ -1,80 +1,81 @@
{
"name": "integration-tests",
"version": "1.0.0",
"description": "",
"type": "module",
"scripts": {
"test:types": "tsc && cd type-tests/join-nodenext && tsc",
"test": "pnpm test:vitest",
"test:vitest": "vitest run --pass-with-no-tests",
"test:esm": "node tests/imports.test.mjs && node tests/imports.test.cjs",
"test:data-api": "sst shell vitest run tests/pg/awsdatapi.test.ts"
},
"keywords": [],
"author": "Drizzle Team",
"license": "Apache-2.0",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20241004.0",
"@libsql/client": "^0.10.0",
"@neondatabase/serverless": "0.10.0",
"@originjs/vite-plugin-commonjs": "^1.0.3",
"@paralleldrive/cuid2": "^2.2.2",
"@types/async-retry": "^1.4.8",
"@types/better-sqlite3": "^7.6.4",
"@types/dockerode": "^3.3.18",
"@types/node": "^20.2.5",
"@types/pg": "^8.10.1",
"@types/sql.js": "^1.4.4",
"@types/uuid": "^9.0.1",
"@types/ws": "^8.5.10",
"@upstash/redis": "^1.34.3",
"@vitest/ui": "^1.6.0",
"ava": "^5.3.0",
"cross-env": "^7.0.3",
"keyv": "^5.2.3",
"import-in-the-middle": "^1.13.1",
"ts-node": "^10.9.2",
"tsx": "^4.14.0",
"vite-tsconfig-paths": "^4.3.2",
"zx": "^8.3.2"
},
"dependencies": {
"@aws-sdk/client-rds-data": "^3.549.0",
"@aws-sdk/credential-providers": "^3.549.0",
"@electric-sql/pglite": "0.2.12",
"@libsql/client": "^0.10.0",
"@miniflare/d1": "^2.14.4",
"@miniflare/shared": "^2.14.4",
"@planetscale/database": "^1.16.0",
"@prisma/client": "5.14.0",
"@tidbcloud/serverless": "^0.1.1",
"@typescript/analyze-trace": "^0.10.0",
"@vercel/postgres": "^0.8.0",
"@xata.io/client": "^0.29.3",
"async-retry": "^1.3.3",
"better-sqlite3": "11.9.1",
"dockerode": "^4.0.6",
"dotenv": "^16.1.4",
"drizzle-prisma-generator": "^0.1.2",
"drizzle-seed": "workspace:../drizzle-seed/dist",
"drizzle-typebox": "workspace:../drizzle-typebox/dist",
"drizzle-valibot": "workspace:../drizzle-valibot/dist",
"drizzle-zod": "workspace:../drizzle-zod/dist",
"gel": "^2.0.0",
"get-port": "^7.0.0",
"mysql2": "^3.14.1",
"pg": "^8.11.0",
"postgres": "^3.3.5",
"prisma": "5.14.0",
"source-map-support": "^0.5.21",
"sql.js": "^1.8.0",
"sqlite3": "^5.1.4",
"sst": "^3.14.24",
"uuid": "^9.0.0",
"uvu": "^0.5.6",
"vitest": "^3.1.3",
"ws": "^8.18.2",
"zod": "^3.20.2"
}
"name": "integration-tests",
"version": "1.0.0",
"description": "",
"type": "module",
"scripts": {
"test:types": "tsc && cd type-tests/join-nodenext && tsc",
"test": "pnpm test:vitest",
"test:vitest": "vitest run --pass-with-no-tests",
"test:esm": "node tests/imports.test.mjs && node tests/imports.test.cjs",
"test:data-api": "sst shell vitest run tests/pg/awsdatapi.test.ts"
},
"keywords": [],
"author": "Drizzle Team",
"license": "Apache-2.0",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20241004.0",
"@libsql/client": "^0.10.0",
"@neondatabase/serverless": "0.10.0",
"@originjs/vite-plugin-commonjs": "^1.0.3",
"@paralleldrive/cuid2": "^2.2.2",
"@types/async-retry": "^1.4.8",
"@types/better-sqlite3": "^7.6.4",
"@types/dockerode": "^3.3.18",
"@types/node": "^20.2.5",
"@types/pg": "^8.10.1",
"@types/sql.js": "^1.4.4",
"@types/uuid": "^9.0.1",
"@types/ws": "^8.5.10",
"@upstash/redis": "^1.34.3",
"@vitest/ui": "^1.6.0",
"ava": "^5.3.0",
"cross-env": "^7.0.3",
"keyv": "^5.2.3",
"import-in-the-middle": "^1.13.1",
"ts-node": "^10.9.2",
"tsx": "^4.14.0",
"vite-tsconfig-paths": "^4.3.2",
"zx": "^8.3.2"
},
"dependencies": {
"@aws-sdk/client-rds-data": "^3.549.0",
"@aws-sdk/credential-providers": "^3.549.0",
"@electric-sql/pglite": "0.2.12",
"@libsql/client": "^0.10.0",
"@miniflare/d1": "^2.14.4",
"@miniflare/shared": "^2.14.4",
"@planetscale/database": "^1.16.0",
"@prisma/client": "5.14.0",
"@tidbcloud/serverless": "^0.1.1",
"@typescript/analyze-trace": "^0.10.0",
"@vercel/postgres": "^0.8.0",
"@xata.io/client": "^0.29.3",
"async-retry": "^1.3.3",
"better-sqlite3": "11.9.1",
"dockerode": "^4.0.6",
"dotenv": "^16.1.4",
"drizzle-orm": "workspace:../drizzle-orm/dist",
"drizzle-prisma-generator": "^0.1.2",
"drizzle-seed": "workspace:../drizzle-seed/dist",
"drizzle-typebox": "workspace:../drizzle-typebox/dist",
"drizzle-valibot": "workspace:../drizzle-valibot/dist",
"drizzle-zod": "workspace:../drizzle-zod/dist",
"gel": "^2.0.0",
"get-port": "^7.0.0",
"mysql2": "^3.14.1",
"pg": "^8.11.0",
"postgres": "^3.3.5",
"prisma": "5.14.0",
"source-map-support": "^0.5.21",
"sql.js": "^1.8.0",
"sqlite3": "^5.1.4",
"sst": "^3.14.24",
"uuid": "^9.0.0",
"uvu": "^0.5.6",
"vitest": "^3.1.3",
"ws": "^8.18.2",
"zod": "^3.20.2"
}
}
Loading