fix(memory-driver-duckdb): map rows, un-exported bundles for CDN uses vector (vss) check
This commit is contained in:
@@ -10,6 +10,7 @@ words:
|
||||
- Attributify
|
||||
- audioworklet
|
||||
- Ayaka
|
||||
- bigserial
|
||||
- Bitstream
|
||||
- bumpp
|
||||
- catppuccin
|
||||
@@ -97,8 +98,10 @@ words:
|
||||
- shikijs
|
||||
- silero
|
||||
- sizecheck
|
||||
- smallserial
|
||||
- Sniglet
|
||||
- supergroup
|
||||
- superjson
|
||||
- tamagotchi
|
||||
- taze
|
||||
- tresjs
|
||||
|
||||
@@ -11,5 +11,18 @@ export default antfu(
|
||||
'packages/stage-tamagotchi/out/**',
|
||||
'**/drizzle/**',
|
||||
],
|
||||
// rules: {
|
||||
// 'import/order': [
|
||||
// 'error',
|
||||
// {
|
||||
// 'groups': [
|
||||
// ['type'],
|
||||
// ['builtin', 'external'],
|
||||
// ['parent', 'sibling', 'index'],
|
||||
// ],
|
||||
// 'newlines-between': 'always',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
},
|
||||
)
|
||||
|
||||
@@ -57,7 +57,8 @@
|
||||
"date-fns": "^4.1.0",
|
||||
"defu": "^6.1.4",
|
||||
"drizzle-orm": "^0.39.2",
|
||||
"es-toolkit": "^1.32.0"
|
||||
"es-toolkit": "^1.32.0",
|
||||
"superjson": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@unocss/reset": "^65.4.3",
|
||||
|
||||
@@ -1,8 +1,47 @@
|
||||
import { sql } from 'drizzle-orm'
|
||||
import { pgTable, uuid } from 'drizzle-orm/pg-core'
|
||||
import {
|
||||
bigint,
|
||||
// bit,
|
||||
boolean,
|
||||
char,
|
||||
date,
|
||||
decimal,
|
||||
doublePrecision,
|
||||
integer,
|
||||
interval,
|
||||
json,
|
||||
numeric,
|
||||
pgTable,
|
||||
real,
|
||||
smallint,
|
||||
text,
|
||||
time,
|
||||
timestamp,
|
||||
uuid,
|
||||
varchar,
|
||||
vector,
|
||||
} from 'drizzle-orm/pg-core'
|
||||
|
||||
export const users = pgTable('users', () => {
|
||||
return {
|
||||
id: uuid().primaryKey().unique().default(sql`gen_random_uuid()`),
|
||||
}
|
||||
})
|
||||
export const users = pgTable('users', () => ({
|
||||
id: uuid().primaryKey().unique().default(sql`gen_random_uuid()`),
|
||||
int16: smallint().notNull().default(0),
|
||||
int32: integer().notNull().default(0),
|
||||
int64: bigint({ mode: 'number' }).notNull().default(sql`0`),
|
||||
int64BigInt: bigint({ mode: 'bigint' }).notNull().default(sql`0`),
|
||||
decimal: decimal().notNull().default(sql`0`),
|
||||
numeric: numeric().notNull().default(sql`0`),
|
||||
real: real().notNull().default(sql`0`),
|
||||
double: doublePrecision().notNull().default(sql`0`),
|
||||
vector: vector({ dimensions: 4 }).notNull().default(sql`[0,0,0,0]`),
|
||||
// Unimplemented type for cast (INTEGER[] -> BIT) from @duckdb/duckdb-wasm
|
||||
// bit: bit({ dimensions: 4 }).notNull().default(sql`[0,0,0,0]`),
|
||||
bool: boolean().notNull().default(false),
|
||||
char: char().notNull().default(''),
|
||||
varchar: varchar().notNull().default(''),
|
||||
text: text().notNull().default(''),
|
||||
json: json().notNull().default(sql`'{}'`),
|
||||
date: date().notNull().default(sql`'2020-01-01'`),
|
||||
time: time().notNull().default(sql`'00:00:00'`),
|
||||
timestamp: timestamp().notNull().default(sql`'2020-01-01 00:00:00'`),
|
||||
interval: interval().notNull().default(sql`'1 day'`),
|
||||
}))
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE "users" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"int16" smallint DEFAULT 0 NOT NULL,
|
||||
"int32" integer DEFAULT 0 NOT NULL,
|
||||
"int64" bigint DEFAULT 0 NOT NULL,
|
||||
"int64BigInt" bigint DEFAULT 0 NOT NULL,
|
||||
"decimal" numeric DEFAULT 0 NOT NULL,
|
||||
"numeric" numeric DEFAULT 0 NOT NULL,
|
||||
"real" real DEFAULT 0 NOT NULL,
|
||||
"double" double precision DEFAULT 0 NOT NULL,
|
||||
"vector" FLOAT[4] DEFAULT [0,0,0,0] NOT NULL,
|
||||
"bool" boolean DEFAULT false NOT NULL,
|
||||
"char" char DEFAULT '' NOT NULL,
|
||||
"varchar" varchar DEFAULT '' NOT NULL,
|
||||
"text" text DEFAULT '' NOT NULL,
|
||||
"json" json DEFAULT '{}' NOT NULL,
|
||||
"date" date DEFAULT '2020-01-01' NOT NULL,
|
||||
"time" time DEFAULT '00:00:00' NOT NULL,
|
||||
"timestamp" timestamp DEFAULT '2020-01-01 00:00:00' NOT NULL,
|
||||
"interval" interval DEFAULT '0 day' NOT NULL,
|
||||
CONSTRAINT "users_id_unique" UNIQUE("id")
|
||||
);
|
||||
@@ -1,4 +0,0 @@
|
||||
CREATE TABLE "users" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
CONSTRAINT "users_id_unique" UNIQUE("id")
|
||||
);
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"id": "b731cb60-cb64-4cb0-8262-52b1c3fc467e",
|
||||
"id": "5305094b-45db-4a61-a74f-340b2b7da250",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
@@ -14,6 +14,132 @@
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"int16": {
|
||||
"name": "int16",
|
||||
"type": "smallint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"int32": {
|
||||
"name": "int32",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"int64": {
|
||||
"name": "int64",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "0"
|
||||
},
|
||||
"int64BigInt": {
|
||||
"name": "int64BigInt",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "0"
|
||||
},
|
||||
"decimal": {
|
||||
"name": "decimal",
|
||||
"type": "numeric",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "0"
|
||||
},
|
||||
"numeric": {
|
||||
"name": "numeric",
|
||||
"type": "numeric",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "0"
|
||||
},
|
||||
"real": {
|
||||
"name": "real",
|
||||
"type": "real",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "0"
|
||||
},
|
||||
"double": {
|
||||
"name": "double",
|
||||
"type": "double precision",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "0"
|
||||
},
|
||||
"vector": {
|
||||
"name": "vector",
|
||||
"type": "vector(4)",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "[0,0,0,0]"
|
||||
},
|
||||
"bool": {
|
||||
"name": "bool",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"char": {
|
||||
"name": "char",
|
||||
"type": "char",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"varchar": {
|
||||
"name": "varchar",
|
||||
"type": "varchar",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"text": {
|
||||
"name": "text",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"json": {
|
||||
"name": "json",
|
||||
"type": "json",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'{}'"
|
||||
},
|
||||
"date": {
|
||||
"name": "date",
|
||||
"type": "date",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'2020-01-01'"
|
||||
},
|
||||
"time": {
|
||||
"name": "time",
|
||||
"type": "time",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'00:00:00'"
|
||||
},
|
||||
"timestamp": {
|
||||
"name": "timestamp",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'2020-01-01 00:00:00'"
|
||||
},
|
||||
"interval": {
|
||||
"name": "interval",
|
||||
"type": "interval",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'0'"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1739072522344,
|
||||
"tag": "0000_legal_gauntlet",
|
||||
"when": 1739121102268,
|
||||
"tag": "0000_cute_kulan_gath",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import type { DuckDBWasmDrizzleDatabase } from '../../src/drizzle-orm'
|
||||
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { serialize } from 'superjson'
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
|
||||
import { drizzle } from '../../src/drizzle-orm'
|
||||
import * as schema from '../db/schema'
|
||||
import { users } from '../db/schema'
|
||||
import migration from '../drizzle/0000_legal_gauntlet.sql?raw'
|
||||
import migration1 from '../drizzle/0000_cute_kulan_gath.sql?raw'
|
||||
|
||||
const db = ref<DuckDBWasmDrizzleDatabase<typeof schema>>()
|
||||
const results = ref<Record<string, unknown>[]>()
|
||||
@@ -12,21 +16,34 @@ const schemaResults = ref<Record<string, unknown>[]>()
|
||||
const query = ref(`SELECT 1 + 1 AS result`)
|
||||
|
||||
onMounted(async () => {
|
||||
db.value = drizzle('duckdb-wasm://?bundles=worker-url', { schema })
|
||||
await db.value?.execute(migration)
|
||||
db.value = drizzle('duckdb-wasm://?bundles=import-url', { schema })
|
||||
await db.value?.execute('INSTALL vss;')
|
||||
await db.value?.execute('LOAD vss;')
|
||||
|
||||
await db.value?.execute(migration1)
|
||||
|
||||
results.value = await db.value?.execute(query.value)
|
||||
|
||||
await db.value.insert(users).values({ id: '9449af72-faad-4c97-8a45-69f9f1ca1b05' })
|
||||
schemaResults.value = await db.value.select().from(users)
|
||||
await db.value.insert(users).values({
|
||||
id: '9449af72-faad-4c97-8a45-69f9f1ca1b05',
|
||||
decimal: '1.23456',
|
||||
numeric: '1.23456',
|
||||
real: 1.23456,
|
||||
double: 1.23456,
|
||||
interval: '365 day',
|
||||
})
|
||||
|
||||
const usersResults = await db.value.select().from(users)
|
||||
schemaResults.value = usersResults
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
db.value?.$client.then(client => client.close())
|
||||
})
|
||||
|
||||
watch(query, async () => {
|
||||
watch(query, useDebounceFn(async () => {
|
||||
results.value = await db.value?.execute(query.value)
|
||||
})
|
||||
}, 1000))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -39,7 +56,7 @@ watch(query, async () => {
|
||||
Executing
|
||||
</h2>
|
||||
<div>
|
||||
<textarea v-model="query" h-full w-full rounded-lg bg="gray-100 dark:gray-800" p-4 font-mono />
|
||||
<textarea v-model="query" h-full w-full rounded-lg bg="neutral-100 dark:neutral-800" p-4 font-mono />
|
||||
</div>
|
||||
</div>
|
||||
<div flex flex-col gap-2>
|
||||
@@ -47,7 +64,7 @@ watch(query, async () => {
|
||||
Results
|
||||
</h2>
|
||||
<div whitespace-pre-wrap p-4 font-mono>
|
||||
{{ JSON.stringify(results, null, 2) }}
|
||||
{{ JSON.stringify(serialize(results).json, null, 2) }}
|
||||
</div>
|
||||
</div>
|
||||
<div flex flex-col gap-2>
|
||||
@@ -55,7 +72,7 @@ watch(query, async () => {
|
||||
Executing
|
||||
</h2>
|
||||
<div>
|
||||
<pre whitespace-pre-wrap p-4 font-mono bg="gray-100 dark:gray-800">
|
||||
<pre whitespace-pre-wrap rounded-lg p-4 font-mono bg="neutral-100 dark:neutral-800">
|
||||
await db.insert(users).values({ id: '9449af72-faad-4c97-8a45-69f9f1ca1b05' })
|
||||
await db.select().from(users)
|
||||
</pre>
|
||||
@@ -66,7 +83,7 @@ await db.select().from(users)
|
||||
Schema Results
|
||||
</h2>
|
||||
<div whitespace-pre-wrap p-4 font-mono>
|
||||
{{ JSON.stringify(schemaResults, null, 2) }}
|
||||
{{ JSON.stringify(serialize(schemaResults).json, null, 2) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { TZDate } from '@date-fns/tz'
|
||||
import type { Field, StructRow } from 'apache-arrow'
|
||||
|
||||
import type { DataType } from './duckdb-types'
|
||||
import { TZDate } from '@date-fns/tz'
|
||||
import { Struct, TimeUnit, util } from 'apache-arrow'
|
||||
import { TZDateMini } from '@date-fns/tz'
|
||||
import { DataType as ArrowDataType, IntervalUnit, Struct, TimeUnit, util } from 'apache-arrow'
|
||||
import {
|
||||
addDays,
|
||||
addHours,
|
||||
@@ -16,17 +18,19 @@ import {
|
||||
formatDuration as dateFormatDuration,
|
||||
fromUnixTime,
|
||||
setDay,
|
||||
transpose,
|
||||
} from 'date-fns'
|
||||
|
||||
import { trimEnd } from 'es-toolkit'
|
||||
import { isNullOrUndefined, notNullOrUndefined } from './duckdb-common'
|
||||
import {
|
||||
|
||||
isBooleanType,
|
||||
isDatetimeType,
|
||||
isDateType,
|
||||
isDecimalType,
|
||||
isDurationType,
|
||||
isFloatType,
|
||||
isIntegerType,
|
||||
isIntervalType,
|
||||
isListType,
|
||||
isObjectType,
|
||||
@@ -284,7 +288,7 @@ export function formatDate(date: number | Date): string {
|
||||
/**
|
||||
* Format datetime value from Arrow to string.
|
||||
*/
|
||||
export function formatDatetime(date: number | Date, field?: Field): string {
|
||||
export function formatDatetime(date: number | Date, field?: Field): Date | null {
|
||||
// Datetime values from arrow are already converted to a date object
|
||||
// or a timestamp in milliseconds even if the field unit might indicate a
|
||||
// different unit.
|
||||
@@ -297,25 +301,34 @@ export function formatDatetime(date: number | Date, field?: Field): string {
|
||||
)
|
||||
) {
|
||||
console.warn(`Unsupported datetime value: ${date}`)
|
||||
return String(date)
|
||||
return null
|
||||
}
|
||||
|
||||
let datetime: TZDate
|
||||
const timezone = field?.type?.timezone
|
||||
|
||||
// Impact by upstream changes, see:
|
||||
// - How to replace date-fns-tz · Issue #9 - https://github.com/date-fns/tz/issues/9
|
||||
// - Inconsistencies from date-fns-tz · Issue #6 - https://github.com/date-fns/tz/issues/6
|
||||
if (typeof date === 'number') {
|
||||
datetime = new TZDate(date, 'UTC')
|
||||
if (timezone) {
|
||||
datetime = new TZDateMini(date, timezone)
|
||||
}
|
||||
else {
|
||||
datetime = new TZDateMini(date)
|
||||
}
|
||||
}
|
||||
else {
|
||||
datetime = new TZDate(date, 'UTC')
|
||||
if (timezone) {
|
||||
datetime = new TZDateMini(date, timezone)
|
||||
}
|
||||
else {
|
||||
datetime = new TZDateMini(date)
|
||||
}
|
||||
}
|
||||
|
||||
const timezone = field?.type?.timezone
|
||||
if (timezone) {
|
||||
datetime = datetime.withTimeZone(timezone)
|
||||
return dateFormat(datetime, 'yyyy-MM-dd HH:mm:ss OOOO')
|
||||
}
|
||||
// Return the timestamp without timezone information
|
||||
return dateFormat(datetime, 'yyyy-MM-dd HH:mm:ss')
|
||||
return transpose(datetime, Date)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -329,7 +342,7 @@ export function formatDatetime(date: number | Date, field?: Field): string {
|
||||
* https://github.com/apache/arrow/issues/28804
|
||||
* https://github.com/apache/arrow/issues/35745
|
||||
*/
|
||||
export function formatDecimal(value: Uint32Array, field?: Field): string {
|
||||
export function formatDecimal(value: Uint32Array | Int32Array, field?: Field): string {
|
||||
const scale = field?.type?.scale || 0
|
||||
|
||||
// Format Uint32Array to a numerical string and pad it with zeros
|
||||
@@ -382,7 +395,30 @@ export function formatFloat(num: number): string {
|
||||
/**
|
||||
* Formats an interval value from arrow to string.
|
||||
*/
|
||||
export function formatInterval(x: StructRow, field?: Field): string {
|
||||
export function formatInterval(x: StructRow | Int32Array, field?: Field): string {
|
||||
// TODO: still buggy, the return value of interval related fields are always
|
||||
// [0, 0] as Int32Array, should follow the issue to resolve this.
|
||||
if (ArrowDataType.isInterval(field?.type)) {
|
||||
const value = formatDecimal(x as Int32Array, field)
|
||||
const unit = field?.type.unit
|
||||
switch (unit) {
|
||||
case IntervalUnit.MONTH_DAY_NANO:
|
||||
// In Python:
|
||||
// pa.scalar((1, 15, -30), type=pa.month_day_nano_interval())
|
||||
// <pyarrow.MonthDayNanoIntervalScalar: MonthDayNano(months=1, days=15, nanoseconds=-30)>
|
||||
//
|
||||
// see: pyarrow.month_day_nano_interval — Apache Arrow v19.0.0
|
||||
// https://arrow.apache.org/docs/python/generated/pyarrow.month_day_nano_interval.html
|
||||
return `${value} months`
|
||||
case IntervalUnit.DAY_TIME:
|
||||
return `${value} days`
|
||||
case IntervalUnit.YEAR_MONTH:
|
||||
return `${value} years`
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
// Serialization for pandas.Interval is provided by Arrow extensions
|
||||
// https://github.com/pandas-dev/pandas/blob/235d9009b571c21b353ab215e1e675b1924ae55c/
|
||||
// pandas/core/arrays/arrow/extension_types.py#L17
|
||||
@@ -401,8 +437,8 @@ export function formatInterval(x: StructRow, field?: Field): string {
|
||||
const leftBracket = closed === 'both' || closed === 'left' ? '[' : '('
|
||||
const rightBracket = closed === 'both' || closed === 'right' ? ']' : ')'
|
||||
|
||||
const leftInterval = format(interval.left, (field.type as Struct)?.children?.[0])
|
||||
const rightInterval = format(interval.right, (field.type as Struct)?.children?.[1])
|
||||
const leftInterval = mapColumnData(interval.left, (field.type as Struct)?.children?.[0])
|
||||
const rightInterval = mapColumnData(interval.right, (field.type as Struct)?.children?.[1])
|
||||
|
||||
return `${leftBracket + leftInterval}, ${rightInterval + rightBracket}`
|
||||
}
|
||||
@@ -468,31 +504,36 @@ export function formatPeriod(duration: number | bigint, field?: Field): string {
|
||||
* @param field The field metadata from arrow containing metadata about the column.
|
||||
* @returns The formatted JSON string.
|
||||
*/
|
||||
export function formatObject(object: any, field?: Field): string {
|
||||
export function formatObject(object: any, field?: Field): unknown {
|
||||
if (field?.type instanceof Struct) {
|
||||
// This type is used by python dictionary values
|
||||
|
||||
return JSON.stringify(object, (_key, value) => {
|
||||
if (!notNullOrUndefined(value)) {
|
||||
return JSON.parse(
|
||||
JSON.stringify(object, (_key, value) => {
|
||||
if (!notNullOrUndefined(value)) {
|
||||
// Workaround: Arrow JS adds all properties from all cells
|
||||
// as fields. When you convert to string, it will contain lots of fields with
|
||||
// null values. To mitigate this, we filter out null values.
|
||||
return undefined
|
||||
}
|
||||
if (typeof value === 'bigint') {
|
||||
return undefined
|
||||
}
|
||||
if (typeof value === 'bigint') {
|
||||
// JSON.stringify fails to serialize bigint values, therefore we have to
|
||||
// handle them manually.
|
||||
// TODO(lukasmasuch): Would it be better to serialize it to a string to
|
||||
// not lose precision?
|
||||
return Number(value)
|
||||
}
|
||||
return value
|
||||
})
|
||||
return Number(value)
|
||||
}
|
||||
|
||||
return value
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// TODO(lukasmasuch): Investigate if we can unify this with the logic above.
|
||||
return JSON.stringify(object, (_key, value) =>
|
||||
typeof value === 'bigint' ? Number(value) : value)
|
||||
return JSON.parse(
|
||||
JSON.stringify(object, (_key, value) =>
|
||||
typeof value === 'bigint' ? Number(value) : value),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -506,47 +547,61 @@ export function formatObject(object: any, field?: Field): string {
|
||||
* @param field The field metadata from arrow containing metadata about the column.
|
||||
* @returns The formatted cell value.
|
||||
*/
|
||||
export function format(x: DataType, field?: Field): string {
|
||||
export function mapColumnData<T = unknown>(x: DataType, field?: Field): T {
|
||||
if (isNullOrUndefined(x)) {
|
||||
return ''
|
||||
return null as null as unknown as T
|
||||
}
|
||||
|
||||
const isDate = x instanceof Date || Number.isFinite(x)
|
||||
if (isDate && isDateType(field)) {
|
||||
return formatDate(x as Date | number)
|
||||
return formatDate(x as Date | number) as string as T
|
||||
}
|
||||
|
||||
if (typeof x === 'bigint' && isTimeType(field)) {
|
||||
return formatTime(Number(x), field)
|
||||
return formatTime(Number(x), field) as string as T
|
||||
}
|
||||
|
||||
if (isDate && isDatetimeType(field)) {
|
||||
return formatDatetime(x as Date | number, field)
|
||||
return formatDatetime(x as Date | number, field) as Date as T
|
||||
}
|
||||
|
||||
if (isPeriodType(field)) {
|
||||
return formatPeriod(x as bigint, field)
|
||||
// Not supported yet by Postgres and DuckDB
|
||||
throw new Error('Period type is not supported yet')
|
||||
}
|
||||
|
||||
if (isIntervalType(field)) {
|
||||
return formatInterval(x as StructRow, field)
|
||||
return formatInterval(x as StructRow, field) as string as T
|
||||
}
|
||||
|
||||
if (isDurationType(field)) {
|
||||
return formatDuration(x as number | bigint, field)
|
||||
// Not supported yet by Postgres and DuckDB
|
||||
throw new Error('Duration type is not supported yet')
|
||||
}
|
||||
|
||||
if (isDecimalType(field)) {
|
||||
return formatDecimal(x as Uint32Array, field)
|
||||
// 'numeric' in Postgres also applies here
|
||||
return formatDecimal(x as Uint32Array, field) as string as T
|
||||
}
|
||||
|
||||
if (isFloatType(field) && Number.isFinite(x)) {
|
||||
return formatFloat(x as number)
|
||||
return x as number as T
|
||||
}
|
||||
|
||||
if (isIntegerType(field)) {
|
||||
// If int64 or uint64, it should be bigint already,
|
||||
// if int32 or uint32, it should be number already,
|
||||
// therefore we can just return the value as is.
|
||||
return x as number as T
|
||||
}
|
||||
|
||||
if (isObjectType(field) || isListType(field)) {
|
||||
return formatObject(x, field)
|
||||
return formatObject(x, field) as T
|
||||
}
|
||||
|
||||
return String(x)
|
||||
if (isBooleanType(field)) {
|
||||
return Boolean(x) as boolean as T
|
||||
}
|
||||
|
||||
return String(x) as T
|
||||
}
|
||||
|
||||
@@ -239,7 +239,8 @@ export function isIntervalType(type?: Field): boolean {
|
||||
// ArrowDataType.isInterval checks for a different (unsupported) type and not related
|
||||
// to the pandas interval extension type.
|
||||
return (
|
||||
(ArrowDataType.isStruct(type.type)
|
||||
&& type.metadata.get('ARROW:extension:name') === 'interval')
|
||||
((ArrowDataType.isStruct(type.type)
|
||||
&& type.metadata.get('ARROW:extension:name') === 'interval'))
|
||||
|| ArrowDataType.isInterval(type.type)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { DuckDBBundles, Logger } from '@duckdb/duckdb-wasm'
|
||||
import type { DrizzleConfig, RelationalSchemaConfig, TablesRelationalConfig } from 'drizzle-orm'
|
||||
import type { DuckDBWasmClient } from './dialect'
|
||||
import type { DuckDBWasmQueryResultHKT } from './session'
|
||||
import { ConsoleLogger } from '@duckdb/duckdb-wasm'
|
||||
|
||||
import { createTableRelationsHelpers, DefaultLogger, entityKind, extractTablesRelationalConfig, isConfig } from 'drizzle-orm'
|
||||
import { PgDatabase, PgDialect } from 'drizzle-orm/pg-core'
|
||||
@@ -68,11 +69,12 @@ export function drizzle<
|
||||
): DuckDBWasmDrizzleDatabase<TSchema, TClient> {
|
||||
if (typeof params[0] === 'string') {
|
||||
const parsedDSN = new URL(params[0] as string)
|
||||
if (parsedDSN.searchParams.get('bundles') === 'worker-url') {
|
||||
if (parsedDSN.searchParams.get('bundles') === 'import-url') {
|
||||
const logger = parsedDSN.searchParams.get('logger') === 'true' ? new ConsoleLogger() : undefined
|
||||
return construct(new Promise<DuckDBWasmClient>((resolve) => {
|
||||
import('./dialect/duckdb-vite-bundles')
|
||||
.then(res => res.getViteBundles())
|
||||
.then(bundles => connect({ bundles }))
|
||||
.then(bundles => connect({ bundles, logger }))
|
||||
.then(resolve)
|
||||
}), params[1]) as any
|
||||
}
|
||||
@@ -100,7 +102,7 @@ export function drizzle<
|
||||
if (typeof connection === 'object' && connection.url !== undefined) {
|
||||
const { url } = connection
|
||||
const parsedDSN = new URL(url)
|
||||
if (parsedDSN.searchParams.get('bundles') === 'worker-url') {
|
||||
if (parsedDSN.searchParams.get('bundles') === 'import-url') {
|
||||
return construct(new Promise<DuckDBWasmClient>((resolve) => {
|
||||
import('./dialect/duckdb-vite-bundles')
|
||||
.then(res => res.getViteBundles())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export type { ConnectOptionalOptions, ConnectOptions, ConnectRequiredOptions, DuckDBWasmClient } from './dialect'
|
||||
export { connect, format, getBundles } from './dialect'
|
||||
export { connect, getBundles, mapColumnData } from './dialect'
|
||||
export * from './driver'
|
||||
export * from './migrator'
|
||||
export * from './session'
|
||||
export type { AsyncDuckDBConnection, DuckDBBundles, Logger } from '@duckdb/duckdb-wasm'
|
||||
export { AsyncDuckDB, ConsoleLogger, selectBundle, VoidLogger } from '@duckdb/duckdb-wasm'
|
||||
export { AsyncDuckDB, ConsoleLogger, getJsDelivrBundles, selectBundle, VoidLogger } from '@duckdb/duckdb-wasm'
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { DuckDBWasmClient } from './dialect'
|
||||
|
||||
import { entityKind, fillPlaceholders, NoopLogger } from 'drizzle-orm'
|
||||
import { PgPreparedQuery, PgSession, PgTransaction } from 'drizzle-orm/pg-core'
|
||||
import { beginTransaction, format, withSavepoint } from './dialect'
|
||||
import { beginTransaction, mapColumnData, withSavepoint } from './dialect'
|
||||
|
||||
export type Row = Record<string, any>
|
||||
|
||||
@@ -16,7 +16,7 @@ function toJSRepresentedRows<T extends { toArray: () => StructRow[], schema: Sch
|
||||
|
||||
const jsRepresentedRows = rows.map((row) => {
|
||||
results.schema.fields.forEach((field) => {
|
||||
return row[field.name] = format(row[field.name], field)
|
||||
return row[field.name] = mapColumnData(row[field.name], field)
|
||||
})
|
||||
|
||||
return row
|
||||
|
||||
Generated
+11
@@ -155,6 +155,9 @@ importers:
|
||||
es-toolkit:
|
||||
specifier: ^1.32.0
|
||||
version: 1.32.0
|
||||
superjson:
|
||||
specifier: ^2.2.2
|
||||
version: 2.2.2
|
||||
devDependencies:
|
||||
'@unocss/reset':
|
||||
specifier: ^65.4.3
|
||||
@@ -9281,6 +9284,10 @@ packages:
|
||||
resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
superjson@2.2.2:
|
||||
resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
supports-color@7.2.0:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -20435,6 +20442,10 @@ snapshots:
|
||||
dependencies:
|
||||
copy-anything: 3.0.5
|
||||
|
||||
superjson@2.2.2:
|
||||
dependencies:
|
||||
copy-anything: 3.0.5
|
||||
|
||||
supports-color@7.2.0:
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
|
||||
Reference in New Issue
Block a user