Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

v3: Typed JSON arrays use native-list handling for filters and null values

未关闭
#2,843 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
20/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
postgresql, typescript
领域
databases

调研方向

The payload names DataModelValidator.validateField, BaseCrudDialect's array dispatch, ZodSchemaFactory, BaseOperationHandler.processScalarFieldUpdateData, ResultProcessor and the FieldFilter conditional type; read those to separate custom JSON arrays from native SQL lists. Run the repro script against a disposable PostgreSQL database to confirm the four failures: the equality filter, the JsonNull filter, null reads, and the DbNull/JsonNull updates. Done means the equality filter returns the row, null and [] stay distinct, and both sentinel updates succeed while native-list behavior is unchanged.

由索引模型根据 Issue 内容生成。

描述

Description and expected behavior

Custom-type arrays are stored as JSON, but several paths appear to handle them as native SQL/scalar lists. On 3.9.4, even equality filtering on a non-nullable Entry[] @json field fails. Nullable declarations, null reads/writes, and filter typings have related inconsistencies.

Expected:

  • A JSON-array equality filter should compare the JSON value and return the matching row.
  • Nullable custom JSON arrays should preserve null versus [], and accept the appropriate DbNull/JsonNull operations and filter types.
  • Native SQL-list restrictions should remain unchanged.

Minimal reproduction

Create a fresh ESM project (package.json containing {"private":true,"type":"module"}), then install:

pnpm add @zenstackhq/[email protected] @zenstackhq/[email protected] @zenstackhq/[email protected] @zenstackhq/[email protected] [email protected] [email protected] [email protected]

Set DATABASE_URL to an empty disposable PostgreSQL database. The script creates an Example table there. Save the following files, then run:

pnpm exec zen generate --schema schema.zmodel
pnpm exec tsx repro.ts
schema.zmodel
datasource db {
  provider = "postgresql"
}

type Entry {
  label String
  @@strict
}

model Example {
  id Int @id
  entries Entry[] @json
}
repro.ts

The first query uses the unmodified generated schema. Because the language currently rejects Entry[]?, the later nullable-runtime probes override only the generated field's optional metadata. This explicitly isolates runtime behavior from the language rejection; it is not required to reproduce the first equality-filter failure. tsx runs the script despite the separate TypeScript error described below.

import { ZenStackClient, DbNull, JsonNull } from '@zenstackhq/orm';
import { PostgresDialect } from '@zenstackhq/orm/dialects/postgres';
import { Pool } from 'pg';
import { schema } from './schema';

const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 1 });
const db = new ZenStackClient(schema, {
  dialect: new PostgresDialect({ pool }),
  validateInput: true,
});
async function show(name: string, run: () => Promise<unknown>) {
  try { console.log(name, JSON.stringify(await run())); }
  catch (error) { console.log(name, (error as Error).message); }
}
try {
  await pool.query('CREATE TABLE "Example" (id integer PRIMARY KEY, entries jsonb)');
  await db.example.create({ data: { id: 1, entries: [{ label: 'x' }] } });
  await show('equals array', () => db.example.findMany({ where: { entries: { equals: [{ label: 'x' }] } } }));

  // The language currently rejects Entry[]?. Override only optional metadata
  // to isolate the runtime behavior of a nullable custom JSON array.
  const optionalSchema = {
    ...schema,
    models: {
      ...schema.models,
      Example: {
        ...schema.models.Example,
        fields: {
          ...schema.models.Example.fields,
          entries: { ...schema.models.Example.fields.entries, optional: true as const },
        },
      },
    },
  };
  const nullableDb = new ZenStackClient(optionalSchema, {
    dialect: new PostgresDialect({ pool }),
    validateInput: true,
  });
  await show('equals JsonNull', () => nullableDb.example.findMany({ where: { entries: { equals: JsonNull } } }));
  await pool.query('INSERT INTO "Example" (id, entries) VALUES (2, NULL), (3, \'null\'::jsonb)');
  await show('read SQL/JSON null', () => nullableDb.example.findMany({ where: { id: { in: [2, 3] } }, orderBy: { id: 'asc' } }));
  await show('update DbNull', () => nullableDb.example.update({ where: { id: 1 }, data: { entries: DbNull } }));
  await show('update JsonNull', () => nullableDb.example.update({ where: { id: 1 }, data: { entries: JsonNull } }));
} finally {
  await pool.end();
}
Actual output
equals array Invariant failed: Array filter value must be an array
equals JsonNull Invalid findMany args for model "Example": Validation error: Invalid input: expected array, received JsonNullClass at "where.entries.equals"
read SQL/JSON null [{"id":2,"entries":[]},{"id":3,"entries":[]}]
update DbNull Invalid array update operation: __brand
update JsonNull Invalid array update operation: __brand

The first query should return [{"id":1,"entries":[{"label":"x"}]}]. The two null rows should have entries: null. Both null-sentinel updates should succeed for the nullable field.

Language rejection

Changing the field to entries Entry[]? @json and running zen generate fails with:

Optional lists are not supported. Use either `Type[]` or `Type?`

If rejecting nullable top-level custom JSON arrays is intentional, clarification would help; the non-nullable equality-filter failure above reproduces independently.

Filter typing

With TypeScript 6.0.3 (strict, skipLibCheck, moduleResolution: bundler), the nullableDb.example.findMany call with entries: { equals: JsonNull } also fails typecheck:

TS2740: Type 'JsonNullClass' is missing the following properties from type 'unknown[]': length, pop, push, concat, and 29 more.

Environment

  • ZenStack: 3.9.4, stock npm packages, no patches
  • PostgreSQL: 16.15
  • Node.js: 22.14.0
  • Package manager: pnpm 11.25.0
  • pg: 8.21.0; Zod: 4.5.4; tsx: 4.19.0
  • Direct ZenStackClient with validateInput: true; no plugins

Additional context

Related: #2411 addressed nullable custom-object JSON typings; this reproduction concerns custom-type arrays and also includes runtime failures.

The relevant 3.9.4 paths appear to be DataModelValidator.validateField, array dispatch in BaseCrudDialect and ZodSchemaFactory, BaseOperationHandler.processScalarFieldUpdateData, ResultProcessor, and the FieldFilter conditional type. They need to distinguish custom JSON arrays from native SQL lists. These observations are grouped here because they share that distinction; they can be split if preferred.

主要语言
TypeScript
星标
2.9k
派生
157
平均合并
11 小时 42 分钟
30 天内合并 PR
20

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

zenstackhq/zenstack 的其他 Issue

查看 zenstackhq/zenstack 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。