@prisma/orm-postgres 8.0.0-rc.11-dev.38 → 8.0.0-rc.11-dev.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contract-builder.d.mts +35 -2
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +30 -1
- package/dist/contract-builder.mjs.map +1 -1
- package/dist/target__operation-types.d.mts +1 -0
- package/dist/target__operation-types.mjs +2 -0
- package/package.json +9 -9
- package/skills/prisma-8/SKILL.md +1 -1
- package/skills/prisma-8/references/contract.md +10 -0
- package/skills/prisma-8/references/queries-postgres.md +38 -0
- package/dist/adapter__operation-types.d.mts +0 -1
- package/dist/adapter__operation-types.mjs +0 -2
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { PG_ENUM_CODEC_ID } from "@prisma/orm-target-postgres/target/codec-ids";
|
|
2
2
|
import postgresPackRef from "@prisma/orm-target-postgres/target/pack";
|
|
3
3
|
import { PostgresNativeEnum, RlsPolicyOperation } from "@prisma/orm-target-postgres/target/types";
|
|
4
|
-
import { CheckNode, ComposedAuthoringHelpers, ComposedAuthoringHelpers as ComposedAuthoringHelpers$1, ContractDefinition, ContractInput, ContractInput as ContractInput$1, ContractModelBuilder, EnumMember, EnumTypeHandle, EnumTypeHandle as EnumTypeHandle$1, FieldNode, ForeignKeyNode, IndexNode, MergeEnums, ModelLike, ModelNode, PrimaryKeyNode, RelationNode, ScalarFieldBuilder, ScalarFieldBuilder as ScalarFieldBuilder$1, UniqueConstraintNode, autoincrement, buildBoundContract, buildSqlContractFromDefinition, check, field, member, model, now, rel, sql } from "@prisma/orm-family-sql/contract-ts/contract-builder";
|
|
4
|
+
import { CheckNode, ColumnRef, ComposedAuthoringHelpers, ComposedAuthoringHelpers as ComposedAuthoringHelpers$1, ContractDefinition, ContractInput, ContractInput as ContractInput$1, ContractModelBuilder, EnumMember, EnumTypeHandle, EnumTypeHandle as EnumTypeHandle$1, FieldNode, ForeignKeyNode, IndexConstraint, IndexNode, MergeEnums, ModelLike, ModelNode, PrimaryKeyNode, RelationNode, ScalarFieldBuilder, ScalarFieldBuilder as ScalarFieldBuilder$1, UniqueConstraintNode, autoincrement, buildBoundContract, buildSqlContractFromDefinition, check, field, member, model, now, rel, sql } from "@prisma/orm-family-sql/contract-ts/contract-builder";
|
|
5
5
|
import sqlFamilyPack from "@prisma/orm-family-sql/family/pack";
|
|
6
6
|
import "@prisma/orm-framework/contract/types";
|
|
7
7
|
import "@prisma/orm-framework/components/authoring";
|
|
8
8
|
import { ColumnTypeDescriptor } from "@prisma/orm-framework/components/codec";
|
|
9
9
|
import { ExtensionPackRef } from "@prisma/orm-framework/components/components";
|
|
10
10
|
import { SqlNamespaceBase, SqlNamespaceInput, StorageTypeInstance } from "@prisma/orm-family-sql/contract/types";
|
|
11
|
+
import { FullTextSearchLanguage } from "@prisma/orm-target-postgres/target/operation-types";
|
|
11
12
|
//#region ../../../3-extensions/postgres/dist/contract-builder.d.mts
|
|
12
13
|
//#region src/contract/rls.d.ts
|
|
13
14
|
/**
|
|
@@ -474,6 +475,38 @@ declare const enumType: BoundEnumType<{
|
|
|
474
475
|
}, "traits" | "output" | "input">;
|
|
475
476
|
}>;
|
|
476
477
|
//#endregion
|
|
478
|
+
//#region src/contract/full-text-index.d.ts
|
|
479
|
+
type FullTextIndexOptionsBase = {
|
|
480
|
+
readonly language?: FullTextSearchLanguage;
|
|
481
|
+
/** The SQL predicate restricting rows included in a partial index. */
|
|
482
|
+
readonly where?: string;
|
|
483
|
+
};
|
|
484
|
+
/**
|
|
485
|
+
* The wire-named form. `Name` stays literal so the model's `sql()` stage sees the
|
|
486
|
+
* index's name and refuses a duplicate, exactly as it does for `constraints.index`.
|
|
487
|
+
*/
|
|
488
|
+
type FullTextIndexNameOptions<Name extends string = string> = FullTextIndexOptionsBase & {
|
|
489
|
+
readonly name: Name;
|
|
490
|
+
readonly map?: never;
|
|
491
|
+
};
|
|
492
|
+
/** The exact-named form: `map` is adopted verbatim and carries no wire name. */
|
|
493
|
+
type FullTextIndexMapOptions = FullTextIndexOptionsBase & {
|
|
494
|
+
readonly map: string;
|
|
495
|
+
readonly name?: never;
|
|
496
|
+
};
|
|
497
|
+
/**
|
|
498
|
+
* A GIN index over the `to_tsvector` expression `fullTextMatches`,
|
|
499
|
+
* `fullTextRank` and `fullTextHeadline` lower to — the TypeScript twin of
|
|
500
|
+
* `@@fullTextIndex`. Pass it to a model's `sql({ indexes: [...] })`.
|
|
501
|
+
*
|
|
502
|
+
* The expression is rendered at lowering, once the column's storage name is
|
|
503
|
+
* known, so a `.column()` override or a column naming convention is honoured
|
|
504
|
+
* rather than guessed. Pass the same `language` here and to the operation: a
|
|
505
|
+
* mismatch is not an error, the query simply stops using the index.
|
|
506
|
+
*/
|
|
507
|
+
declare function fullTextIndex<Name extends string>(column: ColumnRef, options: FullTextIndexNameOptions<Name>): IndexConstraint<never, Name>;
|
|
508
|
+
declare function fullTextIndex(column: ColumnRef, options: FullTextIndexMapOptions): IndexConstraint<never, undefined>;
|
|
509
|
+
//#endregion
|
|
477
510
|
//#region src/contract/native-enum.d.ts
|
|
478
511
|
/**
|
|
479
512
|
* Handle returned by {@link nativeEnum}. Mirrors PSL's two distinct strings for
|
|
@@ -554,5 +587,5 @@ declare const pg: {
|
|
|
554
587
|
readonly enum: typeof pgEnumColumn;
|
|
555
588
|
};
|
|
556
589
|
//#endregion
|
|
557
|
-
export { type CheckNode, type ComposedAuthoringHelpers, type ContractDefinition, type ContractInput, type ContractModelBuilder, type EnumMember, type EnumTypeHandle, type FieldNode, type ForeignKeyNode, type IndexNode, type ModelNode, type NativeEnumHandle, type PrimaryKeyNode, type RelationNode, type RlsEnablementHandle, type RlsEntityHandle, type RlsPolicyHandle, type RlsRoleHandle, type RlsTargetModel, type RlsUsingPolicyDescriptor, type RlsUsingWithCheckPolicyDescriptor, type RlsWithCheckPolicyDescriptor, type ScalarFieldBuilder, type UniqueConstraintNode, autoincrement, buildSqlContractFromDefinition, check, defineContract, enumType, field, member, model, nativeEnum, now, pg, policyAll, policyDelete, policyInsert, policySelect, policyUpdate, rel, rlsEnabled, role, sql };
|
|
590
|
+
export { type CheckNode, type ComposedAuthoringHelpers, type ContractDefinition, type ContractInput, type ContractModelBuilder, type EnumMember, type EnumTypeHandle, type FieldNode, type ForeignKeyNode, type IndexNode, type ModelNode, type NativeEnumHandle, type PrimaryKeyNode, type RelationNode, type RlsEnablementHandle, type RlsEntityHandle, type RlsPolicyHandle, type RlsRoleHandle, type RlsTargetModel, type RlsUsingPolicyDescriptor, type RlsUsingWithCheckPolicyDescriptor, type RlsWithCheckPolicyDescriptor, type ScalarFieldBuilder, type UniqueConstraintNode, autoincrement, buildSqlContractFromDefinition, check, defineContract, enumType, field, fullTextIndex, member, model, nativeEnum, now, pg, policyAll, policyDelete, policyInsert, policySelect, policyUpdate, rel, rlsEnabled, role, sql };
|
|
558
591
|
//# sourceMappingURL=contract-builder.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-builder.d.mts","names":[],"sources":["../../../../3-extensions/postgres/dist/contract-builder.d.mts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"contract-builder.d.mts","names":[],"sources":["../../../../3-extensions/postgres/dist/contract-builder.d.mts"],"mappings":"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"}
|
|
@@ -5,6 +5,8 @@ import { PostgresNativeEnum, postgresCreateNamespace } from "@prisma/orm-target-
|
|
|
5
5
|
import { ifDefined } from "@prisma/orm-framework/utils/defined";
|
|
6
6
|
import { autoincrement, bindEnumType, buildBoundContract, buildSqlContractFromDefinition, check, field, member, model, now, rel, sql } from "@prisma/orm-family-sql/contract-ts/contract-builder";
|
|
7
7
|
import sqlFamilyPack from "@prisma/orm-family-sql/family/pack";
|
|
8
|
+
import { DEFAULT_FULL_TEXT_SEARCH_LANGUAGE, isFullTextIndexableCodec, renderFullTextIndexExpression } from "@prisma/orm-target-postgres/target/sql-utils";
|
|
9
|
+
import { invariant } from "@prisma/orm-framework/utils/assertions";
|
|
8
10
|
import { pgEnumDescriptor } from "@prisma/orm-target-postgres/target/codecs";
|
|
9
11
|
import { InternalError } from "@prisma/orm-framework/utils/internal-error";
|
|
10
12
|
import { POLICY_OPERATION_PREDICATES } from "@prisma/orm-target-postgres/target/rls-canonicalize";
|
|
@@ -29,6 +31,33 @@ function defineContract(definition, factory) {
|
|
|
29
31
|
* set, which is why the binding happens here, per target.
|
|
30
32
|
*/
|
|
31
33
|
const enumType = bindEnumType();
|
|
34
|
+
function fullTextIndex(column, options) {
|
|
35
|
+
const language = options.language ?? DEFAULT_FULL_TEXT_SEARCH_LANGUAGE;
|
|
36
|
+
return {
|
|
37
|
+
kind: "index",
|
|
38
|
+
expression: {
|
|
39
|
+
fields: [column],
|
|
40
|
+
render: (columns) => {
|
|
41
|
+
const resolved = columns[0];
|
|
42
|
+
invariant(resolved !== void 0, `fullTextIndex resolved no column for field "${column.fieldName}"`);
|
|
43
|
+
if (!isFullTextIndexableCodec(resolved.codecId)) throw postgresError("CONTRACT.INDEX_INVALID", `fullTextIndex indexes a text column, but "${column.fieldName}" is stored as \`${resolved.codecId}\`.`, {
|
|
44
|
+
why: "to_tsvector takes text; Postgres rejects the CREATE INDEX for any other column type.",
|
|
45
|
+
fix: "Index a text, varchar, char or enum column, or drop the index.",
|
|
46
|
+
meta: {
|
|
47
|
+
helper: "fullTextIndex",
|
|
48
|
+
fieldName: column.fieldName,
|
|
49
|
+
codecId: resolved.codecId
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return renderFullTextIndexExpression(language, resolved.name);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
type: "gin",
|
|
56
|
+
...options.where !== void 0 ? { where: options.where } : {},
|
|
57
|
+
...options.name !== void 0 ? { name: options.name } : {},
|
|
58
|
+
...options.map !== void 0 ? { map: options.map } : {}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
32
61
|
function buildNativeEnumHandle(name, typeName, members) {
|
|
33
62
|
if (typeName.trim().length === 0) throw postgresError("CONTRACT.ENUM_INVALID", `nativeEnum("${name}"): the Postgres type name must be a non-empty string.`, {
|
|
34
63
|
fix: "Pass a non-empty Postgres type name to .map(typeName).",
|
|
@@ -227,6 +256,6 @@ function policyAll(model, descriptor) {
|
|
|
227
256
|
return buildPolicyHandle("all", model, descriptor);
|
|
228
257
|
}
|
|
229
258
|
//#endregion
|
|
230
|
-
export { autoincrement, buildSqlContractFromDefinition, check, defineContract, enumType, field, member, model, nativeEnum, now, pg, policyAll, policyDelete, policyInsert, policySelect, policyUpdate, rel, rlsEnabled, role, sql };
|
|
259
|
+
export { autoincrement, buildSqlContractFromDefinition, check, defineContract, enumType, field, fullTextIndex, member, model, nativeEnum, now, pg, policyAll, policyDelete, policyInsert, policySelect, policyUpdate, rel, rlsEnabled, role, sql };
|
|
231
260
|
|
|
232
261
|
//# sourceMappingURL=contract-builder.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-builder.mjs","names":[],"sources":["../../../../3-extensions/postgres/dist/contract-builder.mjs"],"sourcesContent":["import { t as postgresError } from \"./errors-DfWK9xep.mjs\";\nimport { PG_ENUM_CODEC_ID } from \"@internal/target-postgres/codec-ids\";\nimport postgresPackRef from \"@internal/target-postgres/pack\";\nimport { PostgresNativeEnum, postgresCreateNamespace } from \"@internal/target-postgres/types\";\nimport { ifDefined } from \"@internal/utils/defined\";\nimport { autoincrement, bindEnumType, buildBoundContract, buildSqlContractFromDefinition, check, field, member, model, now, rel, sql } from \"@internal/sql-contract-ts/contract-builder\";\nimport sqlFamilyPack from \"@internal/family-sql/pack\";\nimport { pgEnumDescriptor } from \"@internal/target-postgres/codecs\";\nimport { InternalError } from \"@internal/utils/internal-error\";\nimport { POLICY_OPERATION_PREDICATES } from \"@internal/target-postgres/rls-canonicalize\";\n//#region src/contract/define-contract.ts\nfunction defineContract(definition, factory) {\n\tconst bound = {\n\t\t...definition,\n\t\tcreateNamespace: postgresCreateNamespace\n\t};\n\tif (factory !== void 0) return buildBoundContract(sqlFamilyPack, postgresPackRef, bound, factory);\n\treturn buildBoundContract(sqlFamilyPack, postgresPackRef, bound);\n}\n//#endregion\n//#region src/contract/enum-type.ts\n/**\n* The `enumType` authors call when building a Postgres contract (re-exported\n* from `@internal/postgres/contract-builder`).\n*\n* `bindEnumType` is the core, codec-agnostic `enumType` factory; calling it with\n* the Postgres pack's codec typemap fixes which member-value type each codec\n* permits, so `member()` values are checked against the column's codec at\n* authoring time: `pg/text@1` requires `string`, `pg/int4@1` requires `number`,\n* and a mismatch is a compile error. The core `enumType` can't know the codec\n* set, which is why the binding happens here, per target.\n*/\nconst enumType = bindEnumType();\n//#endregion\n//#region src/contract/native-enum.ts\nfunction buildNativeEnumHandle(name, typeName, members) {\n\tif (typeName.trim().length === 0) throw postgresError(\"CONTRACT.ENUM_INVALID\", `nativeEnum(\"${name}\"): the Postgres type name must be a non-empty string.`, {\n\t\tfix: \"Pass a non-empty Postgres type name to .map(typeName).\",\n\t\tmeta: {\n\t\t\tenumName: name,\n\t\t\treason: \"empty type name\"\n\t\t}\n\t});\n\treturn {\n\t\tentityKind: \"native_enum\",\n\t\tname,\n\t\ttypeName,\n\t\tmembers,\n\t\tentity: new PostgresNativeEnum({\n\t\t\ttypeName,\n\t\t\tmembers\n\t\t}),\n\t\tmap: (mappedTypeName) => buildNativeEnumHandle(name, mappedTypeName, members)\n\t};\n}\n/**\n* Declares a native Postgres enum type for use with {@link pg}'s `.enum()`\n* column helper. Mirrors PSL's `native_enum <Name> { … }` lowering\n* (`lowerNativeEnumFromBlock`): validates a non-empty, duplicate-free member\n* list and builds the same {@link PostgresNativeEnum} entity. Its value-set is\n* derived generically at contract-build time — the same\n* `deriveValueSetFromEntity` fold PSL's native enums go through — once\n* `pg.enum(handle)` lands the entity in the field's owning namespace.\n*\n* The first argument is the entity `name` (the `entries.native_enum` /\n* `entries.valueSet` key). The Postgres type name defaults to `name`; use\n* `.map(typeName)` to override it (PSL's `@@map`).\n*\n* A handle referenced by columns in N different namespaces materialises N\n* native enum types (one per namespace) — by design: a Postgres type lives in\n* exactly one schema, and PSL can't share a type across schemas either.\n*\n* @example\n* ```ts\n* // name === Postgres type name\n* const Role = nativeEnum('Role', 'user', 'admin');\n* // entity name `AalLevel`, Postgres type `aal_level` (Supabase's auth.aal_level)\n* const AalLevel = nativeEnum('AalLevel', 'aal1', 'aal2', 'aal3').map('aal_level');\n* model('Session', { fields: { aal: field.column(pg.enum(AalLevel)).optional() } });\n* ```\n*/\nfunction nativeEnum(name, ...members) {\n\tif (name.trim().length === 0) throw postgresError(\"CONTRACT.ENUM_INVALID\", \"nativeEnum(): name must be a non-empty string.\", {\n\t\tfix: \"Pass a non-empty entity name as the first argument to nativeEnum().\",\n\t\tmeta: {\n\t\t\tenumName: name,\n\t\t\treason: \"empty name\"\n\t\t}\n\t});\n\tif (members.length === 0) throw postgresError(\"CONTRACT.ENUM_INVALID\", `nativeEnum(\"${name}\"): must have at least one member.`, {\n\t\twhy: \"Postgres rejects CREATE TYPE ... AS ENUM () with no labels.\",\n\t\tfix: \"Declare at least one member value after the name.\",\n\t\tmeta: {\n\t\t\tenumName: name,\n\t\t\treason: \"zero members\"\n\t\t}\n\t});\n\tconst seenValues = /* @__PURE__ */ new Set();\n\tfor (const value of members) {\n\t\tif (seenValues.has(value)) throw postgresError(\"CONTRACT.ENUM_INVALID\", `nativeEnum(\"${name}\"): duplicate member value \"${value}\". Member values must be unique.`, {\n\t\t\tfix: \"Remove the duplicate member value.\",\n\t\t\tmeta: {\n\t\t\t\tenumName: name,\n\t\t\t\tmember: value,\n\t\t\t\treason: \"duplicate member value\"\n\t\t\t}\n\t\t});\n\t\tseenValues.add(value);\n\t}\n\treturn buildNativeEnumHandle(name, name, members);\n}\n/**\n* Builds the deferred column descriptor for `handle`: the bare Postgres type\n* name and `typeParams` come from `pgEnumDescriptor.columnFromEntity` (the same\n* authoring hook the PSL `pg.enum(Ref)` type constructor resolves through),\n* carrying `handle.entity` as the descriptor's `entityRef` keyed by the entity\n* `name` (not the Postgres type name — they differ when `.map()` was used).\n* Schema qualification and the storage `valueSet` ref are NOT computed here — a\n* `field.column(pg.enum(handle))` call runs before the enclosing `model(...)`\n* associates a namespace, so `buildSqlContractFromDefinition` resolves both\n* once the field's namespace is known.\n*/\nfunction pgEnumColumn(handle) {\n\tconst resolved = pgEnumDescriptor.columnFromEntity(handle.entity);\n\tif (resolved === void 0) throw new InternalError(`pg.enum(\"${handle.name}\"): handle.entity is not a PostgresNativeEnum. This is an authoring-surface bug — nativeEnum() must always produce one.`);\n\treturn {\n\t\tcodecId: PG_ENUM_CODEC_ID,\n\t\tnativeType: resolved.nativeType,\n\t\ttypeParams: resolved.typeParams,\n\t\tentityRef: {\n\t\t\tentityKind: handle.entityKind,\n\t\t\tentityName: handle.name,\n\t\t\tentity: handle.entity\n\t\t}\n\t};\n}\n/** Postgres-specific TS type-constructor namespace, mirroring the PSL `pg.` prefix. */\nconst pg = { enum: pgEnumColumn };\n//#endregion\n//#region src/contract/rls.ts\nfunction assertNonEmptyName(helper, name) {\n\tif (name.trim().length === 0) throw postgresError(\"CONTRACT.POLICY_INVALID\", `${helper}: name must be a non-empty string.`, {\n\t\tfix: \"Pass a non-empty policy name.\",\n\t\tmeta: {\n\t\t\tpolicyName: name,\n\t\t\treason: \"empty name\"\n\t\t}\n\t});\n}\n/** The user-facing helper name per operation, for runtime error messages. */\nconst HELPER_NAMES = {\n\tselect: \"policySelect\",\n\tinsert: \"policyInsert\",\n\tupdate: \"policyUpdate\",\n\tdelete: \"policyDelete\",\n\tall: \"policyAll\"\n};\nfunction buildPolicyHandle(operation, model, descriptor) {\n\tconst helper = HELPER_NAMES[operation];\n\tconst support = POLICY_OPERATION_PREDICATES[operation];\n\tassertNonEmptyName(`${helper}(\"${descriptor.name}\")`, descriptor.name);\n\tconst supported = support.using && support.withCheck ? \"`using` and `withCheck`\" : support.using ? \"`using` only\" : \"`withCheck` only\";\n\tconst rejectPredicate = (predicate) => {\n\t\tthrow postgresError(\"CONTRACT.POLICY_INVALID\", `${helper}: policy \"${descriptor.name}\" does not take a \\`${predicate}\\` predicate; the ${operation.toUpperCase()} operation uses ${supported}.`, {\n\t\t\tfix: `Use only the predicates the ${operation.toUpperCase()} operation supports: ${supported}.`,\n\t\t\tmeta: {\n\t\t\t\tpolicyName: descriptor.name,\n\t\t\t\treason: `unsupported \\`${predicate}\\` predicate`\n\t\t\t}\n\t\t});\n\t};\n\tif (descriptor.using !== void 0 && !support.using) rejectPredicate(\"using\");\n\tif (descriptor.withCheck !== void 0 && !support.withCheck) rejectPredicate(\"withCheck\");\n\tif (descriptor.using === void 0 && descriptor.withCheck === void 0) throw postgresError(\"CONTRACT.POLICY_INVALID\", `${helper}: policy \"${descriptor.name}\" requires at least one predicate; the ${operation.toUpperCase()} operation uses ${supported}.`, {\n\t\tfix: `Provide at least one predicate: ${supported}.`,\n\t\tmeta: {\n\t\t\tpolicyName: descriptor.name,\n\t\t\treason: \"no predicate given\"\n\t\t}\n\t});\n\treturn Object.freeze({\n\t\tentityKind: \"policy\",\n\t\toperation,\n\t\tname: descriptor.name,\n\t\trefs: Object.freeze({ target: model }),\n\t\troles: Object.freeze([...descriptor.roles]),\n\t\t...ifDefined(\"using\", descriptor.using),\n\t\t...ifDefined(\"withCheck\", descriptor.withCheck)\n\t});\n}\n/**\n* Declares a Postgres role by name, mirroring PSL's bare role identifiers.\n* Returns an inert handle: referenced in a policy's `roles` it contributes\n* the bare name; placed in the `entities` list it declares the role\n* (`entries.role`), making it subject to the existence verify.\n*/\nfunction role(name) {\n\tassertNonEmptyName(`role(\"${name}\")`, name);\n\treturn Object.freeze({\n\t\tentityKind: \"role\",\n\t\tname\n\t});\n}\n/**\n* Marks a model's table RLS-controlled, mirroring PSL's `@@rls`. The\n* enablement marker (never the policy set) drives `ENABLE`/`DISABLE ROW\n* LEVEL SECURITY` planning.\n*/\nfunction rlsEnabled(model) {\n\treturn Object.freeze({\n\t\tentityKind: \"rls\",\n\t\trefs: Object.freeze({ target: model })\n\t});\n}\n/** Authors a `FOR SELECT` policy (PSL `policy_select`): row visibility via `using`. */\nfunction policySelect(model, descriptor) {\n\treturn buildPolicyHandle(\"select\", model, descriptor);\n}\n/** Authors a `FOR INSERT` policy (PSL `policy_insert`): new-row validation via `withCheck`. */\nfunction policyInsert(model, descriptor) {\n\treturn buildPolicyHandle(\"insert\", model, descriptor);\n}\n/** Authors a `FOR UPDATE` policy (PSL `policy_update`): takes `using` and `withCheck`. */\nfunction policyUpdate(model, descriptor) {\n\treturn buildPolicyHandle(\"update\", model, descriptor);\n}\n/** Authors a `FOR DELETE` policy (PSL `policy_delete`): row eligibility via `using`. */\nfunction policyDelete(model, descriptor) {\n\treturn buildPolicyHandle(\"delete\", model, descriptor);\n}\n/** Authors a `FOR ALL` policy (PSL `policy_all`): takes `using` and `withCheck`. */\nfunction policyAll(model, descriptor) {\n\treturn buildPolicyHandle(\"all\", model, descriptor);\n}\n//#endregion\nexport { autoincrement, buildSqlContractFromDefinition, check, defineContract, enumType, field, member, model, nativeEnum, now, pg, policyAll, policyDelete, policyInsert, policySelect, policyUpdate, rel, rlsEnabled, role, sql };\n\n//# sourceMappingURL=contract-builder.mjs.map"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"contract-builder.mjs","names":[],"sources":["../../../../3-extensions/postgres/dist/contract-builder.mjs"],"sourcesContent":["import { t as postgresError } from \"./errors-DfWK9xep.mjs\";\nimport { PG_ENUM_CODEC_ID } from \"@internal/target-postgres/codec-ids\";\nimport postgresPackRef from \"@internal/target-postgres/pack\";\nimport { PostgresNativeEnum, postgresCreateNamespace } from \"@internal/target-postgres/types\";\nimport { ifDefined } from \"@internal/utils/defined\";\nimport { autoincrement, bindEnumType, buildBoundContract, buildSqlContractFromDefinition, check, field, member, model, now, rel, sql } from \"@internal/sql-contract-ts/contract-builder\";\nimport sqlFamilyPack from \"@internal/family-sql/pack\";\nimport { DEFAULT_FULL_TEXT_SEARCH_LANGUAGE, isFullTextIndexableCodec, renderFullTextIndexExpression } from \"@internal/target-postgres/sql-utils\";\nimport { invariant } from \"@internal/utils/assertions\";\nimport { pgEnumDescriptor } from \"@internal/target-postgres/codecs\";\nimport { InternalError } from \"@internal/utils/internal-error\";\nimport { POLICY_OPERATION_PREDICATES } from \"@internal/target-postgres/rls-canonicalize\";\n//#region src/contract/define-contract.ts\nfunction defineContract(definition, factory) {\n\tconst bound = {\n\t\t...definition,\n\t\tcreateNamespace: postgresCreateNamespace\n\t};\n\tif (factory !== void 0) return buildBoundContract(sqlFamilyPack, postgresPackRef, bound, factory);\n\treturn buildBoundContract(sqlFamilyPack, postgresPackRef, bound);\n}\n//#endregion\n//#region src/contract/enum-type.ts\n/**\n* The `enumType` authors call when building a Postgres contract (re-exported\n* from `@internal/postgres/contract-builder`).\n*\n* `bindEnumType` is the core, codec-agnostic `enumType` factory; calling it with\n* the Postgres pack's codec typemap fixes which member-value type each codec\n* permits, so `member()` values are checked against the column's codec at\n* authoring time: `pg/text@1` requires `string`, `pg/int4@1` requires `number`,\n* and a mismatch is a compile error. The core `enumType` can't know the codec\n* set, which is why the binding happens here, per target.\n*/\nconst enumType = bindEnumType();\n//#endregion\n//#region src/contract/full-text-index.ts\nfunction fullTextIndex(column, options) {\n\tconst language = options.language ?? DEFAULT_FULL_TEXT_SEARCH_LANGUAGE;\n\treturn {\n\t\tkind: \"index\",\n\t\texpression: {\n\t\t\tfields: [column],\n\t\t\trender: (columns) => {\n\t\t\t\tconst resolved = columns[0];\n\t\t\t\tinvariant(resolved !== void 0, `fullTextIndex resolved no column for field \"${column.fieldName}\"`);\n\t\t\t\tif (!isFullTextIndexableCodec(resolved.codecId)) throw postgresError(\"CONTRACT.INDEX_INVALID\", `fullTextIndex indexes a text column, but \"${column.fieldName}\" is stored as \\`${resolved.codecId}\\`.`, {\n\t\t\t\t\twhy: \"to_tsvector takes text; Postgres rejects the CREATE INDEX for any other column type.\",\n\t\t\t\t\tfix: \"Index a text, varchar, char or enum column, or drop the index.\",\n\t\t\t\t\tmeta: {\n\t\t\t\t\t\thelper: \"fullTextIndex\",\n\t\t\t\t\t\tfieldName: column.fieldName,\n\t\t\t\t\t\tcodecId: resolved.codecId\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn renderFullTextIndexExpression(language, resolved.name);\n\t\t\t}\n\t\t},\n\t\ttype: \"gin\",\n\t\t...options.where !== void 0 ? { where: options.where } : {},\n\t\t...options.name !== void 0 ? { name: options.name } : {},\n\t\t...options.map !== void 0 ? { map: options.map } : {}\n\t};\n}\n//#endregion\n//#region src/contract/native-enum.ts\nfunction buildNativeEnumHandle(name, typeName, members) {\n\tif (typeName.trim().length === 0) throw postgresError(\"CONTRACT.ENUM_INVALID\", `nativeEnum(\"${name}\"): the Postgres type name must be a non-empty string.`, {\n\t\tfix: \"Pass a non-empty Postgres type name to .map(typeName).\",\n\t\tmeta: {\n\t\t\tenumName: name,\n\t\t\treason: \"empty type name\"\n\t\t}\n\t});\n\treturn {\n\t\tentityKind: \"native_enum\",\n\t\tname,\n\t\ttypeName,\n\t\tmembers,\n\t\tentity: new PostgresNativeEnum({\n\t\t\ttypeName,\n\t\t\tmembers\n\t\t}),\n\t\tmap: (mappedTypeName) => buildNativeEnumHandle(name, mappedTypeName, members)\n\t};\n}\n/**\n* Declares a native Postgres enum type for use with {@link pg}'s `.enum()`\n* column helper. Mirrors PSL's `native_enum <Name> { … }` lowering\n* (`lowerNativeEnumFromBlock`): validates a non-empty, duplicate-free member\n* list and builds the same {@link PostgresNativeEnum} entity. Its value-set is\n* derived generically at contract-build time — the same\n* `deriveValueSetFromEntity` fold PSL's native enums go through — once\n* `pg.enum(handle)` lands the entity in the field's owning namespace.\n*\n* The first argument is the entity `name` (the `entries.native_enum` /\n* `entries.valueSet` key). The Postgres type name defaults to `name`; use\n* `.map(typeName)` to override it (PSL's `@@map`).\n*\n* A handle referenced by columns in N different namespaces materialises N\n* native enum types (one per namespace) — by design: a Postgres type lives in\n* exactly one schema, and PSL can't share a type across schemas either.\n*\n* @example\n* ```ts\n* // name === Postgres type name\n* const Role = nativeEnum('Role', 'user', 'admin');\n* // entity name `AalLevel`, Postgres type `aal_level` (Supabase's auth.aal_level)\n* const AalLevel = nativeEnum('AalLevel', 'aal1', 'aal2', 'aal3').map('aal_level');\n* model('Session', { fields: { aal: field.column(pg.enum(AalLevel)).optional() } });\n* ```\n*/\nfunction nativeEnum(name, ...members) {\n\tif (name.trim().length === 0) throw postgresError(\"CONTRACT.ENUM_INVALID\", \"nativeEnum(): name must be a non-empty string.\", {\n\t\tfix: \"Pass a non-empty entity name as the first argument to nativeEnum().\",\n\t\tmeta: {\n\t\t\tenumName: name,\n\t\t\treason: \"empty name\"\n\t\t}\n\t});\n\tif (members.length === 0) throw postgresError(\"CONTRACT.ENUM_INVALID\", `nativeEnum(\"${name}\"): must have at least one member.`, {\n\t\twhy: \"Postgres rejects CREATE TYPE ... AS ENUM () with no labels.\",\n\t\tfix: \"Declare at least one member value after the name.\",\n\t\tmeta: {\n\t\t\tenumName: name,\n\t\t\treason: \"zero members\"\n\t\t}\n\t});\n\tconst seenValues = /* @__PURE__ */ new Set();\n\tfor (const value of members) {\n\t\tif (seenValues.has(value)) throw postgresError(\"CONTRACT.ENUM_INVALID\", `nativeEnum(\"${name}\"): duplicate member value \"${value}\". Member values must be unique.`, {\n\t\t\tfix: \"Remove the duplicate member value.\",\n\t\t\tmeta: {\n\t\t\t\tenumName: name,\n\t\t\t\tmember: value,\n\t\t\t\treason: \"duplicate member value\"\n\t\t\t}\n\t\t});\n\t\tseenValues.add(value);\n\t}\n\treturn buildNativeEnumHandle(name, name, members);\n}\n/**\n* Builds the deferred column descriptor for `handle`: the bare Postgres type\n* name and `typeParams` come from `pgEnumDescriptor.columnFromEntity` (the same\n* authoring hook the PSL `pg.enum(Ref)` type constructor resolves through),\n* carrying `handle.entity` as the descriptor's `entityRef` keyed by the entity\n* `name` (not the Postgres type name — they differ when `.map()` was used).\n* Schema qualification and the storage `valueSet` ref are NOT computed here — a\n* `field.column(pg.enum(handle))` call runs before the enclosing `model(...)`\n* associates a namespace, so `buildSqlContractFromDefinition` resolves both\n* once the field's namespace is known.\n*/\nfunction pgEnumColumn(handle) {\n\tconst resolved = pgEnumDescriptor.columnFromEntity(handle.entity);\n\tif (resolved === void 0) throw new InternalError(`pg.enum(\"${handle.name}\"): handle.entity is not a PostgresNativeEnum. This is an authoring-surface bug — nativeEnum() must always produce one.`);\n\treturn {\n\t\tcodecId: PG_ENUM_CODEC_ID,\n\t\tnativeType: resolved.nativeType,\n\t\ttypeParams: resolved.typeParams,\n\t\tentityRef: {\n\t\t\tentityKind: handle.entityKind,\n\t\t\tentityName: handle.name,\n\t\t\tentity: handle.entity\n\t\t}\n\t};\n}\n/** Postgres-specific TS type-constructor namespace, mirroring the PSL `pg.` prefix. */\nconst pg = { enum: pgEnumColumn };\n//#endregion\n//#region src/contract/rls.ts\nfunction assertNonEmptyName(helper, name) {\n\tif (name.trim().length === 0) throw postgresError(\"CONTRACT.POLICY_INVALID\", `${helper}: name must be a non-empty string.`, {\n\t\tfix: \"Pass a non-empty policy name.\",\n\t\tmeta: {\n\t\t\tpolicyName: name,\n\t\t\treason: \"empty name\"\n\t\t}\n\t});\n}\n/** The user-facing helper name per operation, for runtime error messages. */\nconst HELPER_NAMES = {\n\tselect: \"policySelect\",\n\tinsert: \"policyInsert\",\n\tupdate: \"policyUpdate\",\n\tdelete: \"policyDelete\",\n\tall: \"policyAll\"\n};\nfunction buildPolicyHandle(operation, model, descriptor) {\n\tconst helper = HELPER_NAMES[operation];\n\tconst support = POLICY_OPERATION_PREDICATES[operation];\n\tassertNonEmptyName(`${helper}(\"${descriptor.name}\")`, descriptor.name);\n\tconst supported = support.using && support.withCheck ? \"`using` and `withCheck`\" : support.using ? \"`using` only\" : \"`withCheck` only\";\n\tconst rejectPredicate = (predicate) => {\n\t\tthrow postgresError(\"CONTRACT.POLICY_INVALID\", `${helper}: policy \"${descriptor.name}\" does not take a \\`${predicate}\\` predicate; the ${operation.toUpperCase()} operation uses ${supported}.`, {\n\t\t\tfix: `Use only the predicates the ${operation.toUpperCase()} operation supports: ${supported}.`,\n\t\t\tmeta: {\n\t\t\t\tpolicyName: descriptor.name,\n\t\t\t\treason: `unsupported \\`${predicate}\\` predicate`\n\t\t\t}\n\t\t});\n\t};\n\tif (descriptor.using !== void 0 && !support.using) rejectPredicate(\"using\");\n\tif (descriptor.withCheck !== void 0 && !support.withCheck) rejectPredicate(\"withCheck\");\n\tif (descriptor.using === void 0 && descriptor.withCheck === void 0) throw postgresError(\"CONTRACT.POLICY_INVALID\", `${helper}: policy \"${descriptor.name}\" requires at least one predicate; the ${operation.toUpperCase()} operation uses ${supported}.`, {\n\t\tfix: `Provide at least one predicate: ${supported}.`,\n\t\tmeta: {\n\t\t\tpolicyName: descriptor.name,\n\t\t\treason: \"no predicate given\"\n\t\t}\n\t});\n\treturn Object.freeze({\n\t\tentityKind: \"policy\",\n\t\toperation,\n\t\tname: descriptor.name,\n\t\trefs: Object.freeze({ target: model }),\n\t\troles: Object.freeze([...descriptor.roles]),\n\t\t...ifDefined(\"using\", descriptor.using),\n\t\t...ifDefined(\"withCheck\", descriptor.withCheck)\n\t});\n}\n/**\n* Declares a Postgres role by name, mirroring PSL's bare role identifiers.\n* Returns an inert handle: referenced in a policy's `roles` it contributes\n* the bare name; placed in the `entities` list it declares the role\n* (`entries.role`), making it subject to the existence verify.\n*/\nfunction role(name) {\n\tassertNonEmptyName(`role(\"${name}\")`, name);\n\treturn Object.freeze({\n\t\tentityKind: \"role\",\n\t\tname\n\t});\n}\n/**\n* Marks a model's table RLS-controlled, mirroring PSL's `@@rls`. The\n* enablement marker (never the policy set) drives `ENABLE`/`DISABLE ROW\n* LEVEL SECURITY` planning.\n*/\nfunction rlsEnabled(model) {\n\treturn Object.freeze({\n\t\tentityKind: \"rls\",\n\t\trefs: Object.freeze({ target: model })\n\t});\n}\n/** Authors a `FOR SELECT` policy (PSL `policy_select`): row visibility via `using`. */\nfunction policySelect(model, descriptor) {\n\treturn buildPolicyHandle(\"select\", model, descriptor);\n}\n/** Authors a `FOR INSERT` policy (PSL `policy_insert`): new-row validation via `withCheck`. */\nfunction policyInsert(model, descriptor) {\n\treturn buildPolicyHandle(\"insert\", model, descriptor);\n}\n/** Authors a `FOR UPDATE` policy (PSL `policy_update`): takes `using` and `withCheck`. */\nfunction policyUpdate(model, descriptor) {\n\treturn buildPolicyHandle(\"update\", model, descriptor);\n}\n/** Authors a `FOR DELETE` policy (PSL `policy_delete`): row eligibility via `using`. */\nfunction policyDelete(model, descriptor) {\n\treturn buildPolicyHandle(\"delete\", model, descriptor);\n}\n/** Authors a `FOR ALL` policy (PSL `policy_all`): takes `using` and `withCheck`. */\nfunction policyAll(model, descriptor) {\n\treturn buildPolicyHandle(\"all\", model, descriptor);\n}\n//#endregion\nexport { autoincrement, buildSqlContractFromDefinition, check, defineContract, enumType, field, fullTextIndex, member, model, nativeEnum, now, pg, policyAll, policyDelete, policyInsert, policySelect, policyUpdate, rel, rlsEnabled, role, sql };\n\n//# sourceMappingURL=contract-builder.mjs.map"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "@prisma/orm-target-postgres/target/operation-types";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/orm-postgres",
|
|
3
|
-
"version": "8.0.0-rc.11-dev.
|
|
3
|
+
"version": "8.0.0-rc.11-dev.40",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -10,19 +10,19 @@
|
|
|
10
10
|
"skills"
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@prisma/orm-family-sql": "8.0.0-rc.11-dev.
|
|
14
|
-
"@prisma/orm-framework": "8.0.0-rc.11-dev.
|
|
15
|
-
"@prisma/orm-target-postgres": "8.0.0-rc.11-dev.
|
|
16
|
-
"@prisma/orm-toolchain": "8.0.0-rc.11-dev.
|
|
13
|
+
"@prisma/orm-family-sql": "8.0.0-rc.11-dev.40",
|
|
14
|
+
"@prisma/orm-framework": "8.0.0-rc.11-dev.40",
|
|
15
|
+
"@prisma/orm-target-postgres": "8.0.0-rc.11-dev.40",
|
|
16
|
+
"@prisma/orm-toolchain": "8.0.0-rc.11-dev.40",
|
|
17
17
|
"@types/node": "26.1.2",
|
|
18
18
|
"@types/pg": "8.20.4",
|
|
19
19
|
"pathe": "^2.0.3",
|
|
20
20
|
"pg": "8.22.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@internal/postgres": "8.0.0-rc.11-dev.
|
|
24
|
-
"@repo/tsconfig": "8.0.0-rc.11-dev.
|
|
25
|
-
"@repo/tsdown": "8.0.0-rc.11-dev.
|
|
23
|
+
"@internal/postgres": "8.0.0-rc.11-dev.40",
|
|
24
|
+
"@repo/tsconfig": "8.0.0-rc.11-dev.40",
|
|
25
|
+
"@repo/tsdown": "8.0.0-rc.11-dev.40",
|
|
26
26
|
"tsdown": "0.22.14",
|
|
27
27
|
"typescript": "5.9.3"
|
|
28
28
|
},
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
"./adapter/adapter": "./dist/adapter__adapter.mjs",
|
|
40
40
|
"./adapter/column-types": "./dist/adapter__column-types.mjs",
|
|
41
41
|
"./adapter/control": "./dist/adapter__control.mjs",
|
|
42
|
-
"./adapter/operation-types": "./dist/adapter__operation-types.mjs",
|
|
43
42
|
"./adapter/runtime": "./dist/adapter__runtime.mjs",
|
|
44
43
|
"./adapter/sql-renderer": "./dist/adapter__sql-renderer.mjs",
|
|
45
44
|
"./adapter/types": "./dist/adapter__types.mjs",
|
|
@@ -141,6 +140,7 @@
|
|
|
141
140
|
"./target/migration": "./dist/target__migration.mjs",
|
|
142
141
|
"./target/native-type-normalizer": "./dist/target__native-type-normalizer.mjs",
|
|
143
142
|
"./target/op-factory-call": "./dist/target__op-factory-call.mjs",
|
|
143
|
+
"./target/operation-types": "./dist/target__operation-types.mjs",
|
|
144
144
|
"./target/pack": "./dist/target__pack.mjs",
|
|
145
145
|
"./target/planner": "./dist/target__planner.mjs",
|
|
146
146
|
"./target/planner-ddl-builders": "./dist/target__planner-ddl-builders.mjs",
|
package/skills/prisma-8/SKILL.md
CHANGED
|
@@ -126,6 +126,16 @@ Then run `pnpm prisma contract emit` (or rely on the Vite plugin — see `refere
|
|
|
126
126
|
|
|
127
127
|
`name:` declares a wire-named index (physical name `<name>_<8-hex hash>`, renames plan as `ALTER INDEX … RENAME`); `map:` adopts an exact physical name verbatim (for infer-captured objects — combining it with a SQL body warns, because drift detection byte-compares the authored text against Postgres's reprint). An `expression:` requires `name:` or `map:`. The TS builder mirrors this via `constraints.index([cols.x], {...})` / `constraints.index({ expression, ... })` — see `packages/2-sql/2-authoring/contract-ts/README.md`.
|
|
128
128
|
|
|
129
|
+
**Full-text search indexes (PostgreSQL).** Do not hand-write the `to_tsvector` expression — Postgres only uses the index when it is the same `to_tsvector` over the same configuration literal and the same column as the query. Declare `@@fullTextIndex`, which renders the same expression `fullTextMatches` / `fullTextRank` / `fullTextHeadline` lower to (see `references/queries-postgres.md`):
|
|
130
|
+
|
|
131
|
+
```prisma
|
|
132
|
+
@@fullTextIndex([text], name: "message_text_search")
|
|
133
|
+
@@fullTextIndex([summary], language: "german", name: "message_summary_search_de")
|
|
134
|
+
@@fullTextIndex([text], where: "archived_at IS NULL", name: "message_text_search_live")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The TS builder has the same helper: `fullTextIndex(cols.text, { name: 'message_text_search' })`, from `@prisma/orm-postgres/contract-builder`, inside the model's `sql({ indexes: [...] })`. It takes exactly one field, an optional `language` (default `english`, from the same allowlist the operations accept), an optional `where:` for a partial index, and `name:` xor `map:` like any expression index. It is repeatable, so a model may index several columns. Give the index and the operation the same `language` — a mismatch is silent, costing the index and falling back to a sequential scan. It lowers to a GIN index over `to_tsvector('<language>', "<column>")` — the column name resolved through `@map` — so `@@index(expression: …)` remains only for expressions this attribute does not cover.
|
|
138
|
+
|
|
129
139
|
PSL alias surface for repeated types lives in a top-level `types {}` block:
|
|
130
140
|
|
|
131
141
|
```prisma
|
|
@@ -62,6 +62,44 @@ db.orm.public.User.where({ kind: 'admin' });
|
|
|
62
62
|
|
|
63
63
|
Operators on the field proxy include `.eq`, `.neq`, `.lt`, `.lte`, `.gt`, `.gte`, `.like`, `.ilike`, `.in([...])`, `.isNull()`, `.isNotNull()`. Extensions add target-specific operators on extension-typed columns (`pgvector`'s `.cosineDistance(...)`, `postgis`'s `.within(...)` / `.intersectsBbox(...)` / `.distanceSphere(...)`).
|
|
64
64
|
|
|
65
|
+
**Full-text search** is built into the Postgres target, on any text column: `.fullTextMatches(q)` is the predicate, `.fullTextRank(q)` scores a row so you can order by relevance, and `.fullTextHeadline(q)` returns the text with `<b>` around the matches. The search string is a bound parameter lowered to `websearch_to_tsquery`, so `"an exact phrase"` and `-excluded` work the way a user expects from a search box. Each takes an options object as its second argument. `language` defaults to `'english'` and only accepts the configurations a stock PostgreSQL server ships with (`'simple'`, `'german'`, `'french'`, …); `fullTextRank` also takes `normalization` (the `ts_rank` bitmask, 0 to 63) and `coverDensity` (for `ts_rank_cd`); `fullTextHeadline` also takes `startSel`, `stopSel`, `maxWords`, `minWords` and `highlightAll`. Every one of them is written into the SQL as a literal, so anything invalid throws `RUNTIME.ARGUMENT_INVALID` when the query is built.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// ORM: filter by the query, order by relevance.
|
|
69
|
+
const hits = await db.orm.public.Message
|
|
70
|
+
.select('id', 'text')
|
|
71
|
+
.where((m) => m.text.fullTextMatches(query))
|
|
72
|
+
.orderBy((m) => m.text.fullTextRank(query).desc())
|
|
73
|
+
.limit(20)
|
|
74
|
+
.all();
|
|
75
|
+
|
|
76
|
+
// SQL builder: the same predicate, plus a snippet with your own markers.
|
|
77
|
+
const snippets = db.sql.public.message
|
|
78
|
+
.select('id')
|
|
79
|
+
.select('snippet', (f, fns) =>
|
|
80
|
+
fns.fullTextHeadline(f.text, query, { startSel: '<mark>', stopSel: '</mark>', maxWords: 20 }),
|
|
81
|
+
)
|
|
82
|
+
.where((f, fns) => fns.fullTextMatches(f.text, query))
|
|
83
|
+
.build();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Without an index Postgres recomputes `to_tsvector` for every row, and it only uses one whose expression is the same `to_tsvector` over the same configuration literal and the same column. `@@fullTextIndex` renders that expression for you — pass it the field and, if you use one, the same language:
|
|
87
|
+
|
|
88
|
+
```prisma
|
|
89
|
+
@@fullTextIndex([text], name: "message_text_search")
|
|
90
|
+
@@fullTextIndex([text], where: "archived_at IS NULL", name: "message_text_search_live")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Give the index and the operation the same `language`: a mismatch raises no error, the query silently falls back to a sequential scan.
|
|
94
|
+
|
|
95
|
+
In a TypeScript contract, the same helper from `@prisma/orm-postgres/contract-builder`:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
model('Message', { fields: { id, text } }).sql(({ cols }) => ({
|
|
99
|
+
indexes: [fullTextIndex(cols.text, { name: 'message_text_search' })],
|
|
100
|
+
}));
|
|
101
|
+
```
|
|
102
|
+
|
|
65
103
|
**There is no `.between(a, b)` operator.** Express ranges either as two chained `.where(...)` clauses (the idiomatic form — clauses AND-compose) or with the `and(...)` combinator inside one clause:
|
|
66
104
|
|
|
67
105
|
```typescript
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "@prisma/orm-target-postgres/adapter/operation-types";
|