@prisma/orm-target-postgres 8.0.0-rc.17-dev.3 → 8.0.0-rc.17-dev.5
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/{adapter-RtS8vD8U-CkJSaICZ.mjs → adapter-RtS8vD8U-CCQBsu-H.mjs} +2 -2
- package/dist/{adapter-RtS8vD8U-CkJSaICZ.mjs.map → adapter-RtS8vD8U-CCQBsu-H.mjs.map} +1 -1
- package/dist/adapter.d.mts +1 -1
- package/dist/adapter.mjs +2 -2
- package/dist/adapter__adapter.mjs +2 -2
- package/dist/adapter__control.d.mts +1 -1
- package/dist/adapter__control.mjs +4 -4
- package/dist/adapter__runtime.mjs +3 -3
- package/dist/{authoring-_2G2lsLt-VmVbrMPn.mjs → authoring-CL05jlfX-CKUKjRVV.mjs} +55 -30
- package/dist/authoring-CL05jlfX-CKUKjRVV.mjs.map +1 -0
- package/dist/{contract-free-BMKFjlIG.mjs → contract-free-DjI-gclO.mjs} +3 -3
- package/dist/{contract-free-BMKFjlIG.mjs.map → contract-free-DjI-gclO.mjs.map} +1 -1
- package/dist/{control-1lVvMywk.mjs → control-CDAHFmyX.mjs} +20 -13
- package/dist/control-CDAHFmyX.mjs.map +1 -0
- package/dist/{control-adapter-Co30P4lH-CpxXk5cz.mjs → control-adapter-Co30P4lH-vRdhkEQq.mjs} +2 -2
- package/dist/{control-adapter-Co30P4lH-CpxXk5cz.mjs.map → control-adapter-Co30P4lH-vRdhkEQq.mjs.map} +1 -1
- package/dist/{control-policy-C0KC3-Gw-DseKgAtX.mjs → control-policy-DbDoLxrp-OpWBtviT.mjs} +5 -5
- package/dist/{control-policy-C0KC3-Gw-DseKgAtX.mjs.map → control-policy-DbDoLxrp-OpWBtviT.mjs.map} +1 -1
- package/dist/{ddl-D5hYRCTf-DRSajCVT.mjs → ddl-CFWv3VOT-Ad-I5p22.mjs} +3 -3
- package/dist/{ddl-D5hYRCTf-DRSajCVT.mjs.map → ddl-CFWv3VOT-Ad-I5p22.mjs.map} +1 -1
- package/dist/{descriptor-meta-ARufwwWW-ChZm5Hg5.mjs → descriptor-meta-ARufwwWW-w4_iWp7m.mjs} +2 -2
- package/dist/{descriptor-meta-ARufwwWW-ChZm5Hg5.mjs.map → descriptor-meta-ARufwwWW-w4_iWp7m.mjs.map} +1 -1
- package/dist/{descriptor-meta-WHc6Kv-m-BLzsaP0M.mjs → descriptor-meta-ClvaJRgh-Dlo6A0nL.mjs} +5 -7
- package/dist/descriptor-meta-ClvaJRgh-Dlo6A0nL.mjs.map +1 -0
- package/dist/{diff-database-schema-D9YbaVKX-DZ5wOErP.mjs → diff-database-schema-CByLrBg6-BLLJDUpg.mjs} +20 -5
- package/dist/diff-database-schema-CByLrBg6-BLLJDUpg.mjs.map +1 -0
- package/dist/{full-text-CCqTEQ9y.d.mts → full-text-Dg6-SYSP.d.mts} +2 -2
- package/dist/{full-text-CCqTEQ9y.d.mts.map → full-text-Dg6-SYSP.d.mts.map} +1 -1
- package/dist/{full-text-RAVq4j8W.mjs → full-text-DyeP0p9V.mjs} +2 -2
- package/dist/full-text-DyeP0p9V.mjs.map +1 -0
- package/dist/full-text-index-authoring-Ca6bWXyG.d.mts +7 -0
- package/dist/full-text-index-authoring-Ca6bWXyG.d.mts.map +1 -0
- package/dist/full-text-index-definition-CwWV12H4-DNafWNux.d.mts +53 -0
- package/dist/full-text-index-definition-CwWV12H4-DNafWNux.d.mts.map +1 -0
- package/dist/full-text-index-definition-D-QC3DO2-DXbQitDn.mjs +195 -0
- package/dist/full-text-index-definition-D-QC3DO2-DXbQitDn.mjs.map +1 -0
- package/dist/full-text-parsers-B_aFtL8u-BTbiMXi1.d.mts +61 -0
- package/dist/full-text-parsers-B_aFtL8u-BTbiMXi1.d.mts.map +1 -0
- package/dist/{full-text-parsers-96VfzkHS-C8YGYKhj.mjs → full-text-parsers-DHtcrdrH-DpbFRMEu.mjs} +39 -4
- package/dist/full-text-parsers-DHtcrdrH-DpbFRMEu.mjs.map +1 -0
- package/dist/full-text-search-document-DJd-9K-K-CuV_QLH3.mjs +54 -0
- package/dist/full-text-search-document-DJd-9K-K-CuV_QLH3.mjs.map +1 -0
- package/dist/index-types-Bdy_UGfY-CqEPukzT.mjs +14 -0
- package/dist/index-types-Bdy_UGfY-CqEPukzT.mjs.map +1 -0
- package/dist/{infer-psl-contract-Buc1MJaS-70Kw0cxc.mjs → infer-psl-contract-lnoCopbJ-DRVPVZyI.mjs} +18 -5
- package/dist/infer-psl-contract-lnoCopbJ-DRVPVZyI.mjs.map +1 -0
- package/dist/migration-PTHAY9Cv.mjs.map +1 -1
- package/dist/{op-factory-call-CXlapjuM-BHZNE4Ph.mjs → op-factory-call-BfGiIbUO-BqaxwJhg.mjs} +4 -4
- package/dist/{op-factory-call-CXlapjuM-BHZNE4Ph.mjs.map → op-factory-call-BfGiIbUO-BqaxwJhg.mjs.map} +1 -1
- package/dist/{operation-types-CjJY7prP.d.mts → operation-types-llBeWQxy.d.mts} +54 -11
- package/dist/operation-types-llBeWQxy.d.mts.map +1 -0
- package/dist/{pack-Bq9yq-OS.d.mts → pack-C3Y2SBNH.d.mts} +14 -5
- package/dist/pack-C3Y2SBNH.d.mts.map +1 -0
- package/dist/{planner-DwfHmYme-P1dFkpQ4.mjs → planner-BLGCBKzQ-BFmyE8A2.mjs} +9 -9
- package/dist/{planner-DwfHmYme-P1dFkpQ4.mjs.map → planner-BLGCBKzQ-BFmyE8A2.mjs.map} +1 -1
- package/dist/{planner-produced-postgres-migration-DBUj6Imx-DhpHjroB.mjs → planner-produced-postgres-migration-8cUeUjsL-DwO8p6_t.mjs} +4 -4
- package/dist/{planner-produced-postgres-migration-DBUj6Imx-DhpHjroB.mjs.map → planner-produced-postgres-migration-8cUeUjsL-DwO8p6_t.mjs.map} +1 -1
- package/dist/{planner-sql-checks-DCGV2qdu-eaeFLtn8.mjs → planner-sql-checks-Bt_KuSiH-CdGZDp7M.mjs} +3 -3
- package/dist/{planner-sql-checks-DCGV2qdu-eaeFLtn8.mjs.map → planner-sql-checks-Bt_KuSiH-CdGZDp7M.mjs.map} +1 -1
- package/dist/postgres-codec-traits-BUygtI9N-CB-uwvY1.mjs +11 -0
- package/dist/postgres-codec-traits-BUygtI9N-CB-uwvY1.mjs.map +1 -0
- package/dist/{postgres-contract-view-CL-YTH_3-Diah6i2a.mjs → postgres-contract-view-BpZ_4qOD-BuCMIaSB.mjs} +9 -5
- package/dist/postgres-contract-view-BpZ_4qOD-BuCMIaSB.mjs.map +1 -0
- package/dist/{postgres-migration-DjCmSHjA-D8CPJqkC.mjs → postgres-migration-Deb4XrMA-DO7iGvl2.mjs} +9 -9
- package/dist/{postgres-migration-DjCmSHjA-D8CPJqkC.mjs.map → postgres-migration-Deb4XrMA-DO7iGvl2.mjs.map} +1 -1
- package/dist/{postgres-schema-COkaqci7-C6JpiSha.mjs → postgres-schema-DIaAgaL6-Dmqzjbu5.mjs} +5 -3
- package/dist/postgres-schema-DIaAgaL6-Dmqzjbu5.mjs.map +1 -0
- package/dist/{prisma7-binding-Dm34z6Fq.d.mts → prisma7-binding-C1fIMMTb.d.mts} +14 -5
- package/dist/prisma7-binding-C1fIMMTb.d.mts.map +1 -0
- package/dist/{prisma7-binding-De6fpRdV.mjs → prisma7-binding-DE7hezAQ.mjs} +5 -5
- package/dist/{prisma7-binding-De6fpRdV.mjs.map → prisma7-binding-DE7hezAQ.mjs.map} +1 -1
- package/dist/{render-ops-B5FbJGYf-CnmbaalQ.mjs → render-ops-DjsYroU7-Nqqlj8co.mjs} +3 -3
- package/dist/{render-ops-B5FbJGYf-CnmbaalQ.mjs.map → render-ops-DjsYroU7-Nqqlj8co.mjs.map} +1 -1
- package/dist/{resolve-ddl-schema-DD69Bwve-e-BpAfFa.mjs → resolve-ddl-schema-b746rtzf-Dydnc_gK.mjs} +3 -3
- package/dist/{resolve-ddl-schema-DD69Bwve-e-BpAfFa.mjs.map → resolve-ddl-schema-b746rtzf-Dydnc_gK.mjs.map} +1 -1
- package/dist/{sql-utils-DqFxskY6.d.mts → sql-utils-CGSJ8fH0.d.mts} +7 -16
- package/dist/sql-utils-CGSJ8fH0.d.mts.map +1 -0
- package/dist/target.d.mts +10 -8
- package/dist/target.mjs +22 -21
- package/dist/target__contract-free.mjs +3 -3
- package/dist/target__control.mjs +3 -3
- package/dist/target__diff-database-schema.mjs +1 -1
- package/dist/target__full-text-index-authoring.d.mts +4 -0
- package/dist/target__full-text-index-authoring.mjs +3 -0
- package/dist/target__full-text.d.mts +3 -3
- package/dist/target__full-text.mjs +3 -3
- package/dist/target__issue-planner.mjs +1 -1
- package/dist/target__migration.mjs +2 -2
- package/dist/target__op-factory-call.mjs +1 -1
- package/dist/target__operation-types.d.mts +2 -2
- package/dist/target__pack.d.mts +1 -1
- package/dist/target__pack.mjs +1 -1
- package/dist/target__planner-produced-postgres-migration.mjs +1 -1
- package/dist/target__planner-sql-checks.mjs +1 -1
- package/dist/target__planner.mjs +2 -2
- package/dist/target__prisma7-binding.d.mts +1 -1
- package/dist/target__prisma7-binding.mjs +1 -1
- package/dist/target__render-ops.mjs +1 -1
- package/dist/target__runtime.mjs +100 -26
- package/dist/target__runtime.mjs.map +1 -1
- package/dist/target__schema-ir-annotations.mjs +1 -1
- package/dist/target__sql-utils.d.mts +3 -3
- package/dist/target__sql-utils.mjs +3 -3
- package/dist/target__types.mjs +1 -1
- package/dist/text-search-languages-CO6775ih-DMYr9qsC.d.mts +22 -0
- package/dist/text-search-languages-CO6775ih-DMYr9qsC.d.mts.map +1 -0
- package/package.json +10 -9
- package/dist/authoring-_2G2lsLt-VmVbrMPn.mjs.map +0 -1
- package/dist/control-1lVvMywk.mjs.map +0 -1
- package/dist/descriptor-meta-WHc6Kv-m-BLzsaP0M.mjs.map +0 -1
- package/dist/diff-database-schema-D9YbaVKX-DZ5wOErP.mjs.map +0 -1
- package/dist/full-text-RAVq4j8W.mjs.map +0 -1
- package/dist/full-text-index-expression-Bfp_xWhy-DtbLdkzv.mjs +0 -30
- package/dist/full-text-index-expression-Bfp_xWhy-DtbLdkzv.mjs.map +0 -1
- package/dist/full-text-parsers-96VfzkHS-C8YGYKhj.mjs.map +0 -1
- package/dist/full-text-parsers-DrS_1B-x-BcAnBoQP.d.mts +0 -34
- package/dist/full-text-parsers-DrS_1B-x-BcAnBoQP.d.mts.map +0 -1
- package/dist/infer-psl-contract-Buc1MJaS-70Kw0cxc.mjs.map +0 -1
- package/dist/operation-types-CjJY7prP.d.mts.map +0 -1
- package/dist/pack-Bq9yq-OS.d.mts.map +0 -1
- package/dist/postgres-contract-view-CL-YTH_3-Diah6i2a.mjs.map +0 -1
- package/dist/postgres-schema-COkaqci7-C6JpiSha.mjs.map +0 -1
- package/dist/prisma7-binding-Dm34z6Fq.d.mts.map +0 -1
- package/dist/sql-utils-DqFxskY6.d.mts.map +0 -1
- package/dist/text-search-languages-BzhBMCtK-D26JB2w3.d.mts +0 -12
- package/dist/text-search-languages-BzhBMCtK-D26JB2w3.d.mts.map +0 -1
- package/dist/text-search-languages-RO0HiUDm-CeJ7P8gS.mjs +0 -45
- package/dist/text-search-languages-RO0HiUDm-CeJ7P8gS.mjs.map +0 -1
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { s as postgresError } from "./errors-DYyzTYzE-39CV_aMo.mjs";
|
|
2
|
+
import { type } from "arktype";
|
|
3
|
+
import { invariant } from "@prisma/orm-framework/utils/assertions";
|
|
4
|
+
//#region ../../../3-targets/3-targets/postgres/dist/full-text-index-definition-D-QC3DO2.mjs
|
|
5
|
+
/** The weights Postgres's `setweight` takes, strongest first. Each weight group takes the next one. */
|
|
6
|
+
const FULL_TEXT_WEIGHTS = [
|
|
7
|
+
"A",
|
|
8
|
+
"B",
|
|
9
|
+
"C",
|
|
10
|
+
"D"
|
|
11
|
+
];
|
|
12
|
+
function weightGroupsOf(fields, isField) {
|
|
13
|
+
if (isField(fields)) return [[fields]];
|
|
14
|
+
return fields.map((item) => isField(item) ? [item] : item);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The text-search configurations a stock PostgreSQL server ships with. The language reaches SQL as
|
|
18
|
+
* an inline literal rather than a bound parameter, so only names on this list may be used.
|
|
19
|
+
*/
|
|
20
|
+
const POSTGRES_TEXT_SEARCH_LANGUAGES = [
|
|
21
|
+
"simple",
|
|
22
|
+
"arabic",
|
|
23
|
+
"armenian",
|
|
24
|
+
"basque",
|
|
25
|
+
"catalan",
|
|
26
|
+
"danish",
|
|
27
|
+
"dutch",
|
|
28
|
+
"english",
|
|
29
|
+
"finnish",
|
|
30
|
+
"french",
|
|
31
|
+
"german",
|
|
32
|
+
"greek",
|
|
33
|
+
"hindi",
|
|
34
|
+
"hungarian",
|
|
35
|
+
"indonesian",
|
|
36
|
+
"irish",
|
|
37
|
+
"italian",
|
|
38
|
+
"lithuanian",
|
|
39
|
+
"nepali",
|
|
40
|
+
"norwegian",
|
|
41
|
+
"portuguese",
|
|
42
|
+
"romanian",
|
|
43
|
+
"russian",
|
|
44
|
+
"serbian",
|
|
45
|
+
"spanish",
|
|
46
|
+
"swedish",
|
|
47
|
+
"tamil",
|
|
48
|
+
"turkish",
|
|
49
|
+
"yiddish"
|
|
50
|
+
];
|
|
51
|
+
const DEFAULT_FULL_TEXT_SEARCH_LANGUAGE = "english";
|
|
52
|
+
const KNOWN_LANGUAGES = new Set(POSTGRES_TEXT_SEARCH_LANGUAGES);
|
|
53
|
+
function isFullTextSearchLanguage(language) {
|
|
54
|
+
return KNOWN_LANGUAGES.has(language);
|
|
55
|
+
}
|
|
56
|
+
/** The index type a full-text index is registered under. */
|
|
57
|
+
const FULL_TEXT_INDEX_TYPE = "fullText";
|
|
58
|
+
/** The traits the codec of every column a full-text index covers must carry. */
|
|
59
|
+
const FULL_TEXT_COLUMN_TRAITS = ["textual"];
|
|
60
|
+
/**
|
|
61
|
+
* The rules of a full-text index, stated once: one to four weight groups, none empty, each field
|
|
62
|
+
* once, text columns only, and not unique. Every site that checks a full-text index calls this.
|
|
63
|
+
*/
|
|
64
|
+
function fullTextIndexProblems(candidate) {
|
|
65
|
+
const { weightGroups } = candidate;
|
|
66
|
+
const problems = [];
|
|
67
|
+
if (weightGroups.length === 0) problems.push({ kind: "no-fields" });
|
|
68
|
+
if (weightGroups.length > FULL_TEXT_WEIGHTS.length) problems.push({
|
|
69
|
+
kind: "too-many-groups",
|
|
70
|
+
groupCount: weightGroups.length
|
|
71
|
+
});
|
|
72
|
+
weightGroups.forEach((group, position) => {
|
|
73
|
+
if (group.length === 0) problems.push({
|
|
74
|
+
kind: "empty-group",
|
|
75
|
+
position
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
const seen = /* @__PURE__ */ new Set();
|
|
79
|
+
for (const field of weightGroups.flat()) {
|
|
80
|
+
if (seen.has(field)) problems.push({
|
|
81
|
+
kind: "duplicate-field",
|
|
82
|
+
field
|
|
83
|
+
});
|
|
84
|
+
seen.add(field);
|
|
85
|
+
}
|
|
86
|
+
const { codecs } = candidate;
|
|
87
|
+
if (codecs !== void 0) for (const field of new Set(weightGroups.flat())) {
|
|
88
|
+
const codecId = codecs.codecIdOf(field);
|
|
89
|
+
if (codecId === void 0 || !carriesFullTextTraits(codecs.traitsOf(codecId))) problems.push({
|
|
90
|
+
kind: "not-text",
|
|
91
|
+
field,
|
|
92
|
+
codecId
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (candidate.unique === true) problems.push({ kind: "unique" });
|
|
96
|
+
return problems;
|
|
97
|
+
}
|
|
98
|
+
function carriesFullTextTraits(traits) {
|
|
99
|
+
return traits !== void 0 && FULL_TEXT_COLUMN_TRAITS.every((trait) => traits.includes(trait));
|
|
100
|
+
}
|
|
101
|
+
function describeFullTextIndexProblem(subject, problem, fieldLabel = (field) => field) {
|
|
102
|
+
switch (problem.kind) {
|
|
103
|
+
case "no-fields": return `${subject} needs at least one field.`;
|
|
104
|
+
case "too-many-groups": return `${subject} takes at most ${FULL_TEXT_WEIGHTS.length} weight groups, one for each of the weights ${FULL_TEXT_WEIGHTS.join(", ")}, but was given ${problem.groupCount}.`;
|
|
105
|
+
case "empty-group": return `${subject} has an empty weight group at position ${problem.position + 1}.`;
|
|
106
|
+
case "duplicate-field": return `${subject} names the field "${fieldLabel(problem.field)}" more than once.`;
|
|
107
|
+
case "not-text": return `${subject} indexes text columns, but "${fieldLabel(problem.field)}" is ${problem.codecId === void 0 ? "not a stored scalar field" : `stored as \`${problem.codecId}\``}.`;
|
|
108
|
+
case "unique": return `${subject} is unique, but Postgres builds no unique gin index.`;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** The options of a full-text index: its weight groups, as storage column names, and its language. */
|
|
112
|
+
const fullTextIndexOptions = type({
|
|
113
|
+
"+": "reject",
|
|
114
|
+
weightGroups: type("string > 0").array().array().narrow((weightGroups, ctx) => {
|
|
115
|
+
const [problem] = fullTextIndexProblems({ weightGroups });
|
|
116
|
+
return problem === void 0 || ctx.reject({ message: describeFullTextIndexProblem("a full-text index", problem) });
|
|
117
|
+
}),
|
|
118
|
+
language: type.enumerated(...POSTGRES_TEXT_SEARCH_LANGUAGES)
|
|
119
|
+
});
|
|
120
|
+
/**
|
|
121
|
+
* The registration of the full-text index type. Its options are the index's definition, not
|
|
122
|
+
* storage parameters, and the target turns them into a `gin` index over the rendered search
|
|
123
|
+
* document.
|
|
124
|
+
*/
|
|
125
|
+
const fullTextIndexType = {
|
|
126
|
+
options: fullTextIndexOptions,
|
|
127
|
+
accessMethod: "gin",
|
|
128
|
+
columnTraits: FULL_TEXT_COLUMN_TRAITS
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* The definition a full-text index carries, or `undefined` for an index of any other type. It
|
|
132
|
+
* reads an index {@link assertFullTextIndexes} has accepted, as every loaded contract's has been.
|
|
133
|
+
*/
|
|
134
|
+
function fullTextIndexDefinitionOf(index) {
|
|
135
|
+
if (index.type !== "fullText") return void 0;
|
|
136
|
+
const definition = fullTextIndexOptions(index.options ?? {});
|
|
137
|
+
invariant(!(definition instanceof type.errors), "a full-text index is read only after its contract was checked");
|
|
138
|
+
return definition;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Refuses a table's full-text index the contract cannot carry: invalid options, a broken rule of
|
|
142
|
+
* {@link fullTextIndexProblems}, `columns` that are not the fields of its weight groups, in order,
|
|
143
|
+
* or a foreign key that names it as its backing index. The text-columns rule is checked only when
|
|
144
|
+
* `traitsOf` is given.
|
|
145
|
+
*/
|
|
146
|
+
function assertFullTextIndexes(table, traitsOf) {
|
|
147
|
+
const codecs = traitsOf === void 0 ? void 0 : {
|
|
148
|
+
codecIdOf: (column) => table.columns[column]?.codecId,
|
|
149
|
+
traitsOf
|
|
150
|
+
};
|
|
151
|
+
for (const index of table.indexes) assertFullTextIndex(index, codecs);
|
|
152
|
+
for (const foreignKey of table.foreignKeys) {
|
|
153
|
+
const backing = foreignKey.index;
|
|
154
|
+
if (backing === void 0 || !("name" in backing)) continue;
|
|
155
|
+
const index = table.indexes.find((candidate) => candidate.name === backing.name);
|
|
156
|
+
if (index?.type !== "fullText") continue;
|
|
157
|
+
throw postgresError("CONTRACT.INDEX_INVALID", `The foreign key on columns (${foreignKey.source.columns.join(", ")}) is backed by full-text index "${index.name}".`, {
|
|
158
|
+
why: "A full-text index is a gin index over a search document rendered from its weight groups, not over its columns, so it does not serve the foreign key's lookups.",
|
|
159
|
+
fix: "Re-emit the contract from its source, where a relation cannot name a full-text index as its index.",
|
|
160
|
+
meta: {
|
|
161
|
+
index: index.name,
|
|
162
|
+
columns: foreignKey.source.columns
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function assertFullTextIndex(index, codecs) {
|
|
168
|
+
if (index.type !== "fullText") return;
|
|
169
|
+
const definition = fullTextIndexOptions(index.options ?? {});
|
|
170
|
+
if (definition instanceof type.errors) throw invalidFullTextIndex(index, `Full-text index "${index.name}" has invalid options: ${definition.summary}`, "The options of a full-text index are its definition: its weight groups and its language.");
|
|
171
|
+
const [problem] = fullTextIndexProblems({
|
|
172
|
+
weightGroups: definition.weightGroups,
|
|
173
|
+
unique: index.unique,
|
|
174
|
+
codecs
|
|
175
|
+
});
|
|
176
|
+
if (problem !== void 0) throw invalidFullTextIndex(index, describeFullTextIndexProblem(`Full-text index "${index.name}"`, problem), "A full-text index is a gin index over text columns, in one to four weight groups that name each column once.");
|
|
177
|
+
const fields = definition.weightGroups.flat();
|
|
178
|
+
const columns = index.columns ?? [];
|
|
179
|
+
if (columns.length !== fields.length || columns.some((column, i) => column !== fields[i])) throw invalidFullTextIndex(index, `Full-text index "${index.name}" covers the columns [${columns.join(", ")}], but its weight groups name [${fields.join(", ")}].`, "The columns of a full-text index are the fields of its weight groups, in order. Foreign-key backing and the printer read the columns; the search document is rendered from the groups, so the two must agree.");
|
|
180
|
+
}
|
|
181
|
+
function invalidFullTextIndex(index, message, why) {
|
|
182
|
+
return postgresError("CONTRACT.INDEX_INVALID", message, {
|
|
183
|
+
why,
|
|
184
|
+
fix: "Re-emit the contract from its `@@fullTextIndex` or `fullTextIndex` source rather than editing the index by hand.",
|
|
185
|
+
meta: {
|
|
186
|
+
index: index.name,
|
|
187
|
+
columns: index.columns,
|
|
188
|
+
options: index.options
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
export { assertFullTextIndexes as a, fullTextIndexOptions as c, isFullTextSearchLanguage as d, weightGroupsOf as f, POSTGRES_TEXT_SEARCH_LANGUAGES as i, fullTextIndexProblems as l, FULL_TEXT_INDEX_TYPE as n, describeFullTextIndexProblem as o, FULL_TEXT_WEIGHTS as r, fullTextIndexDefinitionOf as s, DEFAULT_FULL_TEXT_SEARCH_LANGUAGE as t, fullTextIndexType as u };
|
|
194
|
+
|
|
195
|
+
//# sourceMappingURL=full-text-index-definition-D-QC3DO2-DXbQitDn.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"full-text-index-definition-D-QC3DO2-DXbQitDn.mjs","names":[],"sources":["../../../../3-targets/3-targets/postgres/dist/full-text-index-definition-D-QC3DO2.mjs"],"sourcesContent":["import { s as postgresError } from \"./errors-DYyzTYzE.mjs\";\nimport { type } from \"arktype\";\nimport { invariant } from \"@internal/utils/assertions\";\n//#region src/core/full-text-weight-groups.ts\n/** The weights Postgres's `setweight` takes, strongest first. Each weight group takes the next one. */\nconst FULL_TEXT_WEIGHTS = [\n\t\"A\",\n\t\"B\",\n\t\"C\",\n\t\"D\"\n];\nfunction weightGroupsOf(fields, isField) {\n\tif (isField(fields)) return [[fields]];\n\treturn fields.map((item) => isField(item) ? [item] : item);\n}\n//#endregion\n//#region src/core/text-search-languages.ts\n/**\n* The text-search configurations a stock PostgreSQL server ships with. The language reaches SQL as\n* an inline literal rather than a bound parameter, so only names on this list may be used.\n*/\nconst POSTGRES_TEXT_SEARCH_LANGUAGES = [\n\t\"simple\",\n\t\"arabic\",\n\t\"armenian\",\n\t\"basque\",\n\t\"catalan\",\n\t\"danish\",\n\t\"dutch\",\n\t\"english\",\n\t\"finnish\",\n\t\"french\",\n\t\"german\",\n\t\"greek\",\n\t\"hindi\",\n\t\"hungarian\",\n\t\"indonesian\",\n\t\"irish\",\n\t\"italian\",\n\t\"lithuanian\",\n\t\"nepali\",\n\t\"norwegian\",\n\t\"portuguese\",\n\t\"romanian\",\n\t\"russian\",\n\t\"serbian\",\n\t\"spanish\",\n\t\"swedish\",\n\t\"tamil\",\n\t\"turkish\",\n\t\"yiddish\"\n];\nconst DEFAULT_FULL_TEXT_SEARCH_LANGUAGE = \"english\";\nconst KNOWN_LANGUAGES = new Set(POSTGRES_TEXT_SEARCH_LANGUAGES);\nfunction isFullTextSearchLanguage(language) {\n\treturn KNOWN_LANGUAGES.has(language);\n}\n//#endregion\n//#region src/core/full-text-index-definition.ts\n/** The index type a full-text index is registered under. */\nconst FULL_TEXT_INDEX_TYPE = \"fullText\";\n/** The traits the codec of every column a full-text index covers must carry. */\nconst FULL_TEXT_COLUMN_TRAITS = [\"textual\"];\n/**\n* The rules of a full-text index, stated once: one to four weight groups, none empty, each field\n* once, text columns only, and not unique. Every site that checks a full-text index calls this.\n*/\nfunction fullTextIndexProblems(candidate) {\n\tconst { weightGroups } = candidate;\n\tconst problems = [];\n\tif (weightGroups.length === 0) problems.push({ kind: \"no-fields\" });\n\tif (weightGroups.length > FULL_TEXT_WEIGHTS.length) problems.push({\n\t\tkind: \"too-many-groups\",\n\t\tgroupCount: weightGroups.length\n\t});\n\tweightGroups.forEach((group, position) => {\n\t\tif (group.length === 0) problems.push({\n\t\t\tkind: \"empty-group\",\n\t\t\tposition\n\t\t});\n\t});\n\tconst seen = /* @__PURE__ */ new Set();\n\tfor (const field of weightGroups.flat()) {\n\t\tif (seen.has(field)) problems.push({\n\t\t\tkind: \"duplicate-field\",\n\t\t\tfield\n\t\t});\n\t\tseen.add(field);\n\t}\n\tconst { codecs } = candidate;\n\tif (codecs !== void 0) for (const field of new Set(weightGroups.flat())) {\n\t\tconst codecId = codecs.codecIdOf(field);\n\t\tif (codecId === void 0 || !carriesFullTextTraits(codecs.traitsOf(codecId))) problems.push({\n\t\t\tkind: \"not-text\",\n\t\t\tfield,\n\t\t\tcodecId\n\t\t});\n\t}\n\tif (candidate.unique === true) problems.push({ kind: \"unique\" });\n\treturn problems;\n}\nfunction carriesFullTextTraits(traits) {\n\treturn traits !== void 0 && FULL_TEXT_COLUMN_TRAITS.every((trait) => traits.includes(trait));\n}\nfunction describeFullTextIndexProblem(subject, problem, fieldLabel = (field) => field) {\n\tswitch (problem.kind) {\n\t\tcase \"no-fields\": return `${subject} needs at least one field.`;\n\t\tcase \"too-many-groups\": return `${subject} takes at most ${FULL_TEXT_WEIGHTS.length} weight groups, one for each of the weights ${FULL_TEXT_WEIGHTS.join(\", \")}, but was given ${problem.groupCount}.`;\n\t\tcase \"empty-group\": return `${subject} has an empty weight group at position ${problem.position + 1}.`;\n\t\tcase \"duplicate-field\": return `${subject} names the field \"${fieldLabel(problem.field)}\" more than once.`;\n\t\tcase \"not-text\": return `${subject} indexes text columns, but \"${fieldLabel(problem.field)}\" is ${problem.codecId === void 0 ? \"not a stored scalar field\" : `stored as \\`${problem.codecId}\\``}.`;\n\t\tcase \"unique\": return `${subject} is unique, but Postgres builds no unique gin index.`;\n\t}\n}\n/** The options of a full-text index: its weight groups, as storage column names, and its language. */\nconst fullTextIndexOptions = type({\n\t\"+\": \"reject\",\n\tweightGroups: type(\"string > 0\").array().array().narrow((weightGroups, ctx) => {\n\t\tconst [problem] = fullTextIndexProblems({ weightGroups });\n\t\treturn problem === void 0 || ctx.reject({ message: describeFullTextIndexProblem(\"a full-text index\", problem) });\n\t}),\n\tlanguage: type.enumerated(...POSTGRES_TEXT_SEARCH_LANGUAGES)\n});\n/**\n* The registration of the full-text index type. Its options are the index's definition, not\n* storage parameters, and the target turns them into a `gin` index over the rendered search\n* document.\n*/\nconst fullTextIndexType = {\n\toptions: fullTextIndexOptions,\n\taccessMethod: \"gin\",\n\tcolumnTraits: FULL_TEXT_COLUMN_TRAITS\n};\n/**\n* The definition a full-text index carries, or `undefined` for an index of any other type. It\n* reads an index {@link assertFullTextIndexes} has accepted, as every loaded contract's has been.\n*/\nfunction fullTextIndexDefinitionOf(index) {\n\tif (index.type !== \"fullText\") return void 0;\n\tconst definition = fullTextIndexOptions(index.options ?? {});\n\tinvariant(!(definition instanceof type.errors), \"a full-text index is read only after its contract was checked\");\n\treturn definition;\n}\n/**\n* Refuses a table's full-text index the contract cannot carry: invalid options, a broken rule of\n* {@link fullTextIndexProblems}, `columns` that are not the fields of its weight groups, in order,\n* or a foreign key that names it as its backing index. The text-columns rule is checked only when\n* `traitsOf` is given.\n*/\nfunction assertFullTextIndexes(table, traitsOf) {\n\tconst codecs = traitsOf === void 0 ? void 0 : {\n\t\tcodecIdOf: (column) => table.columns[column]?.codecId,\n\t\ttraitsOf\n\t};\n\tfor (const index of table.indexes) assertFullTextIndex(index, codecs);\n\tfor (const foreignKey of table.foreignKeys) {\n\t\tconst backing = foreignKey.index;\n\t\tif (backing === void 0 || !(\"name\" in backing)) continue;\n\t\tconst index = table.indexes.find((candidate) => candidate.name === backing.name);\n\t\tif (index?.type !== \"fullText\") continue;\n\t\tthrow postgresError(\"CONTRACT.INDEX_INVALID\", `The foreign key on columns (${foreignKey.source.columns.join(\", \")}) is backed by full-text index \"${index.name}\".`, {\n\t\t\twhy: \"A full-text index is a gin index over a search document rendered from its weight groups, not over its columns, so it does not serve the foreign key's lookups.\",\n\t\t\tfix: \"Re-emit the contract from its source, where a relation cannot name a full-text index as its index.\",\n\t\t\tmeta: {\n\t\t\t\tindex: index.name,\n\t\t\t\tcolumns: foreignKey.source.columns\n\t\t\t}\n\t\t});\n\t}\n}\nfunction assertFullTextIndex(index, codecs) {\n\tif (index.type !== \"fullText\") return;\n\tconst definition = fullTextIndexOptions(index.options ?? {});\n\tif (definition instanceof type.errors) throw invalidFullTextIndex(index, `Full-text index \"${index.name}\" has invalid options: ${definition.summary}`, \"The options of a full-text index are its definition: its weight groups and its language.\");\n\tconst [problem] = fullTextIndexProblems({\n\t\tweightGroups: definition.weightGroups,\n\t\tunique: index.unique,\n\t\tcodecs\n\t});\n\tif (problem !== void 0) throw invalidFullTextIndex(index, describeFullTextIndexProblem(`Full-text index \"${index.name}\"`, problem), \"A full-text index is a gin index over text columns, in one to four weight groups that name each column once.\");\n\tconst fields = definition.weightGroups.flat();\n\tconst columns = index.columns ?? [];\n\tif (columns.length !== fields.length || columns.some((column, i) => column !== fields[i])) throw invalidFullTextIndex(index, `Full-text index \"${index.name}\" covers the columns [${columns.join(\", \")}], but its weight groups name [${fields.join(\", \")}].`, \"The columns of a full-text index are the fields of its weight groups, in order. Foreign-key backing and the printer read the columns; the search document is rendered from the groups, so the two must agree.\");\n}\nfunction invalidFullTextIndex(index, message, why) {\n\treturn postgresError(\"CONTRACT.INDEX_INVALID\", message, {\n\t\twhy,\n\t\tfix: \"Re-emit the contract from its `@@fullTextIndex` or `fullTextIndex` source rather than editing the index by hand.\",\n\t\tmeta: {\n\t\t\tindex: index.name,\n\t\t\tcolumns: index.columns,\n\t\t\toptions: index.options\n\t\t}\n\t});\n}\n//#endregion\nexport { fullTextIndexOptions as a, DEFAULT_FULL_TEXT_SEARCH_LANGUAGE as c, FULL_TEXT_WEIGHTS as d, weightGroupsOf as f, fullTextIndexDefinitionOf as i, POSTGRES_TEXT_SEARCH_LANGUAGES as l, assertFullTextIndexes as n, fullTextIndexProblems as o, describeFullTextIndexProblem as r, fullTextIndexType as s, FULL_TEXT_INDEX_TYPE as t, isFullTextSearchLanguage as u };\n\n//# sourceMappingURL=full-text-index-definition-D-QC3DO2.mjs.map"],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { j as PG_TSQUERY_CODEC_ID } from "./codec-ids-jWpRZjZo-BKIzyx-J.mjs";
|
|
2
|
+
import { i as FullTextWeightGroups, r as FullTextSearchLanguage } from "./text-search-languages-CO6775ih-DMYr9qsC.mjs";
|
|
3
|
+
import { t as ExtractedCodecTypes } from "./codec-type-map-DueQFJ3a-DKLtMn3R.mjs";
|
|
4
|
+
import { Expression, TraitExpression } from "@prisma/orm-family-sql/relational-core/expression";
|
|
5
|
+
//#region ../../../3-targets/3-targets/postgres/dist/full-text-parsers-B_aFtL8u.d.mts
|
|
6
|
+
//#region src/core/full-text-document.d.ts
|
|
7
|
+
/** A textual column, nullable or not, as an expression rather than a value. */
|
|
8
|
+
type FullTextDocumentColumn = Extract<TraitExpression<readonly ['textual'], boolean, ExtractedCodecTypes>, {
|
|
9
|
+
buildAst(): unknown;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* The weight groups of a search document: each item is one group, strongest first, either one
|
|
13
|
+
* column or a list of columns.
|
|
14
|
+
*/
|
|
15
|
+
type FullTextDocumentGroups = readonly (FullTextDocumentColumn | readonly FullTextDocumentColumn[])[];
|
|
16
|
+
/**
|
|
17
|
+
* A search document built from columns in weight groups, for `fullTextMatches` and `fullTextRank`
|
|
18
|
+
* to search without a full-text index. Postgres uses an index only for a query over the same
|
|
19
|
+
* document, so to search an index, pass the index from the table's `indexes` instead.
|
|
20
|
+
*/
|
|
21
|
+
declare class FullTextDocument {
|
|
22
|
+
readonly weightGroups: FullTextWeightGroups<FullTextDocumentColumn>;
|
|
23
|
+
private constructor();
|
|
24
|
+
static of(groups: FullTextDocumentGroups): FullTextDocument;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The search document of columns in weight groups, strongest first: `fullTextDocument([[f.title,
|
|
28
|
+
* f.subtitle], [f.body]])`. Each group takes the next weight, `A` to `D`; a column named twice is
|
|
29
|
+
* not refused, because column expressions have no name to compare.
|
|
30
|
+
*/
|
|
31
|
+
declare function fullTextDocument(groups: FullTextDocumentGroups): FullTextDocument;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/core/full-text-parsers.d.ts
|
|
34
|
+
interface TsqueryParserOptions {
|
|
35
|
+
/** Text-search configuration the parser normalizes the words with. Defaults to `english`. */
|
|
36
|
+
readonly language?: FullTextSearchLanguage;
|
|
37
|
+
}
|
|
38
|
+
type TsqueryExpression = Expression<{
|
|
39
|
+
codecId: typeof PG_TSQUERY_CODEC_ID;
|
|
40
|
+
nullable: false;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* What a parser parses: a string, bound as `text`, or a non-null expression whose codec is one of
|
|
44
|
+
* this target's `textual` codecs, such as a `text` or `varchar` column.
|
|
45
|
+
*/
|
|
46
|
+
type TextArgument = TraitExpression<readonly ['textual'], false, ExtractedCodecTypes>;
|
|
47
|
+
/** Postgres `websearch_to_tsquery`: search-box syntax with quotes, `or` and `-`. Never errors. */
|
|
48
|
+
declare const websearchToTsquery: (text: TextArgument, options?: TsqueryParserOptions) => TsqueryExpression;
|
|
49
|
+
/**
|
|
50
|
+
* Postgres `to_tsquery`: operator syntax (`'zebra' & !'graze'`, `zeb:*`), each word normalized.
|
|
51
|
+
* Malformed input fails at execution, so pass only text the application wrote, never user input;
|
|
52
|
+
* `tsquery` interpolates user input safely.
|
|
53
|
+
*/
|
|
54
|
+
declare const toTsquery: (text: TextArgument, options?: TsqueryParserOptions) => TsqueryExpression;
|
|
55
|
+
/** Postgres `plainto_tsquery`: every word must match. */
|
|
56
|
+
declare const plaintoTsquery: (text: TextArgument, options?: TsqueryParserOptions) => TsqueryExpression;
|
|
57
|
+
/** Postgres `phraseto_tsquery`: the words must match in order. */
|
|
58
|
+
declare const phrasetoTsquery: (text: TextArgument, options?: TsqueryParserOptions) => TsqueryExpression;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { TsqueryExpression as a, phrasetoTsquery as c, websearchToTsquery as d, TextArgument as i, plaintoTsquery as l, FullTextDocumentColumn as n, TsqueryParserOptions as o, FullTextDocumentGroups as r, fullTextDocument as s, FullTextDocument as t, toTsquery as u };
|
|
61
|
+
//# sourceMappingURL=full-text-parsers-B_aFtL8u-BTbiMXi1.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"full-text-parsers-B_aFtL8u-BTbiMXi1.d.mts","names":[],"sources":["../../../../3-targets/3-targets/postgres/dist/full-text-parsers-B_aFtL8u.d.mts"],"mappings":";;;;;;;KAMK,yBAAyB,QAAQ,+CAA+C;EACnF;;;;;;KAMG,mCAAmC,kCAAkC;;;;;;cAM5D;WACH,cAAc,qBAAqB;UACpC;SACD,GAAG,QAAQ,yBAAyB;;;;;;;iBAO5B,iBAAiB,QAAQ,yBAAyB;;;UAGzD;;WAEC,WAAW;;KAEjB,oBAAoB;EACvB,gBAAgB;EAChB;;;;;;KAMG,eAAe,6CAA6C;;cAEnD,qBAAqB,MAAM,cAAc,UAAU,yBAAyB;;;;;;cAM5E,YAAY,MAAM,cAAc,UAAU,yBAAyB;;cAEnE,iBAAiB,MAAM,cAAc,UAAU,yBAAyB;;cAExE,kBAAkB,MAAM,cAAc,UAAU,yBAAyB"}
|
package/dist/{full-text-parsers-96VfzkHS-C8YGYKhj.mjs → full-text-parsers-DHtcrdrH-DpbFRMEu.mjs}
RENAMED
|
@@ -1,9 +1,44 @@
|
|
|
1
1
|
import { S as PG_TEXT_CODEC_ID, j as PG_TSQUERY_CODEC_ID } from "./codec-ids-Cb0yO-IS--e0P2rfI.mjs";
|
|
2
2
|
import { s as postgresError } from "./errors-DYyzTYzE-39CV_aMo.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { d as isFullTextSearchLanguage, f as weightGroupsOf, i as POSTGRES_TEXT_SEARCH_LANGUAGES, l as fullTextIndexProblems, o as describeFullTextIndexProblem, r as FULL_TEXT_WEIGHTS } from "./full-text-index-definition-D-QC3DO2-DXbQitDn.mjs";
|
|
4
4
|
import { LiteralExpr } from "@prisma/orm-family-sql/relational-core/ast";
|
|
5
5
|
import { buildOperation, toExpr } from "@prisma/orm-family-sql/relational-core/expression";
|
|
6
|
-
//#region ../../../3-targets/3-targets/postgres/dist/full-text-parsers-
|
|
6
|
+
//#region ../../../3-targets/3-targets/postgres/dist/full-text-parsers-DHtcrdrH.mjs
|
|
7
|
+
/**
|
|
8
|
+
* A search document built from columns in weight groups, for `fullTextMatches` and `fullTextRank`
|
|
9
|
+
* to search without a full-text index. Postgres uses an index only for a query over the same
|
|
10
|
+
* document, so to search an index, pass the index from the table's `indexes` instead.
|
|
11
|
+
*/
|
|
12
|
+
var FullTextDocument = class FullTextDocument {
|
|
13
|
+
weightGroups;
|
|
14
|
+
constructor(weightGroups) {
|
|
15
|
+
this.weightGroups = weightGroups;
|
|
16
|
+
Object.freeze(this);
|
|
17
|
+
}
|
|
18
|
+
static of(groups) {
|
|
19
|
+
const weightGroups = weightGroupsOf(groups, (item) => !Array.isArray(item));
|
|
20
|
+
let position = 0;
|
|
21
|
+
const [problem] = fullTextIndexProblems({ weightGroups: weightGroups.map((group) => group.map(() => String(position++))) });
|
|
22
|
+
if (problem !== void 0) throw postgresError("RUNTIME.ARGUMENT_INVALID", describeFullTextIndexProblem("fullTextDocument: the document", problem), {
|
|
23
|
+
why: `Each weight group takes one of the weights Postgres has, ${FULL_TEXT_WEIGHTS.join(", ")}.`,
|
|
24
|
+
fix: "Pass one to four weight groups, none of them empty.",
|
|
25
|
+
meta: {
|
|
26
|
+
helper: "fullTextDocument",
|
|
27
|
+
argument: "groups",
|
|
28
|
+
received: weightGroups.length
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return new FullTextDocument(weightGroups);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The search document of columns in weight groups, strongest first: `fullTextDocument([[f.title,
|
|
36
|
+
* f.subtitle], [f.body]])`. Each group takes the next weight, `A` to `D`; a column named twice is
|
|
37
|
+
* not refused, because column expressions have no name to compare.
|
|
38
|
+
*/
|
|
39
|
+
function fullTextDocument(groups) {
|
|
40
|
+
return FullTextDocument.of(groups);
|
|
41
|
+
}
|
|
7
42
|
/**
|
|
8
43
|
* Options for the Postgres full-text operations, and the checks each one goes through.
|
|
9
44
|
*
|
|
@@ -99,6 +134,6 @@ const plaintoTsquery = parser("plaintoTsquery", "plainto_tsquery");
|
|
|
99
134
|
/** Postgres `phraseto_tsquery`: the words must match in order. */
|
|
100
135
|
const phrasetoTsquery = parser("phrasetoTsquery", "phraseto_tsquery");
|
|
101
136
|
//#endregion
|
|
102
|
-
export {
|
|
137
|
+
export { normalizationLiteral as a, toTsquery as c, languageLiteral as i, websearchToTsquery as l, fullTextDocument as n, phrasetoTsquery as o, headlineOptionsLiteral as r, plaintoTsquery as s, FullTextDocument as t };
|
|
103
138
|
|
|
104
|
-
//# sourceMappingURL=full-text-parsers-
|
|
139
|
+
//# sourceMappingURL=full-text-parsers-DHtcrdrH-DpbFRMEu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"full-text-parsers-DHtcrdrH-DpbFRMEu.mjs","names":[],"sources":["../../../../3-targets/3-targets/postgres/dist/full-text-parsers-DHtcrdrH.mjs"],"sourcesContent":["import { S as PG_TEXT_CODEC_ID, j as PG_TSQUERY_CODEC_ID } from \"./codec-ids-Cb0yO-IS.mjs\";\nimport { s as postgresError } from \"./errors-DYyzTYzE.mjs\";\nimport { d as FULL_TEXT_WEIGHTS, f as weightGroupsOf, l as POSTGRES_TEXT_SEARCH_LANGUAGES, o as fullTextIndexProblems, r as describeFullTextIndexProblem, u as isFullTextSearchLanguage } from \"./full-text-index-definition-D-QC3DO2.mjs\";\nimport { LiteralExpr } from \"@internal/sql-relational-core/ast\";\nimport { buildOperation, toExpr } from \"@internal/sql-relational-core/expression\";\n//#region src/core/full-text-document.ts\n/**\n* A search document built from columns in weight groups, for `fullTextMatches` and `fullTextRank`\n* to search without a full-text index. Postgres uses an index only for a query over the same\n* document, so to search an index, pass the index from the table's `indexes` instead.\n*/\nvar FullTextDocument = class FullTextDocument {\n\tweightGroups;\n\tconstructor(weightGroups) {\n\t\tthis.weightGroups = weightGroups;\n\t\tObject.freeze(this);\n\t}\n\tstatic of(groups) {\n\t\tconst weightGroups = weightGroupsOf(groups, (item) => !Array.isArray(item));\n\t\tlet position = 0;\n\t\tconst [problem] = fullTextIndexProblems({ weightGroups: weightGroups.map((group) => group.map(() => String(position++))) });\n\t\tif (problem !== void 0) throw postgresError(\"RUNTIME.ARGUMENT_INVALID\", describeFullTextIndexProblem(\"fullTextDocument: the document\", problem), {\n\t\t\twhy: `Each weight group takes one of the weights Postgres has, ${FULL_TEXT_WEIGHTS.join(\", \")}.`,\n\t\t\tfix: \"Pass one to four weight groups, none of them empty.\",\n\t\t\tmeta: {\n\t\t\t\thelper: \"fullTextDocument\",\n\t\t\t\targument: \"groups\",\n\t\t\t\treceived: weightGroups.length\n\t\t\t}\n\t\t});\n\t\treturn new FullTextDocument(weightGroups);\n\t}\n};\n/**\n* The search document of columns in weight groups, strongest first: `fullTextDocument([[f.title,\n* f.subtitle], [f.body]])`. Each group takes the next weight, `A` to `D`; a column named twice is\n* not refused, because column expressions have no name to compare.\n*/\nfunction fullTextDocument(groups) {\n\treturn FullTextDocument.of(groups);\n}\n//#endregion\n//#region src/core/full-text-options.ts\n/**\n* Options for the Postgres full-text operations, and the checks each one goes through.\n*\n* Every option here reaches the SQL as an inline literal rather than a bound parameter, because\n* Postgres accepts no parameter in these positions. Each is therefore validated before a statement\n* exists; anything unrecognized throws `RUNTIME.ARGUMENT_INVALID`.\n*\n* The headline markers are the only free text among them, and `checkMarker` restricts their\n* characters precisely so that the literal path never carries a quote or a backslash for\n* `escapeLiteral` to have to reason about.\n*/\nfunction invalid(method, argument, received, why, fix) {\n\treturn postgresError(\"RUNTIME.ARGUMENT_INVALID\", `${method}: ${why}`, {\n\t\twhy: \"The option is written into the SQL as an inline literal, not a bound parameter, so it is checked before the statement is built.\",\n\t\tfix,\n\t\tmeta: {\n\t\t\thelper: method,\n\t\t\targument,\n\t\t\treceived\n\t\t}\n\t});\n}\nfunction languageLiteral(method, language) {\n\tif (!isFullTextSearchLanguage(language)) throw invalid(method, \"language\", language, `'${language}' is not a PostgreSQL text-search configuration Prisma recognizes.`, `Pass one of: ${POSTGRES_TEXT_SEARCH_LANGUAGES.join(\", \")}.`);\n\treturn LiteralExpr.of(language);\n}\nfunction normalizationLiteral(method, normalization) {\n\tif (!Number.isInteger(normalization) || normalization < 0 || normalization > 63) throw invalid(method, \"normalization\", normalization, `normalization must be an integer between 0 and 63, received ${normalization}.`, \"Combine the flags documented for ts_rank, e.g. 32 to divide the rank by itself plus one.\");\n\treturn LiteralExpr.of(normalization);\n}\nfunction checkWordCount(method, argument, value) {\n\tif (!Number.isInteger(value) || value < 1) throw invalid(method, argument, value, `${argument} must be a positive integer, received ${value}.`, \"Pass a whole number of words, one or more.\");\n}\n/** Non-empty, and none of `\"` `,` `=` `\\` or whitespace. */\nconst MARKER = /^[^\"=,\\\\\\s]+$/;\nfunction checkMarker(method, argument, value) {\n\tif (!MARKER.test(value)) throw invalid(method, argument, value, `${argument} must be non-empty and free of \" , = \\\\ and whitespace, received ${JSON.stringify(value)}.`, \"ts_headline parses its options as a quoted, comma-separated list of Key=Value pairs, and the whole list reaches SQL as one literal, so a marker carrying those characters cannot survive either step. Use markup such as <mark> or <b>.\");\n}\n/**\n* The fourth `ts_headline` argument: one text literal of `Key=Value` pairs. Returns `undefined` when\n* nothing but the language was given, so the common call keeps rendering the three-argument form.\n*/\nfunction headlineOptionsLiteral(method, options) {\n\tconst pairs = [];\n\tif (options.startSel !== void 0) {\n\t\tcheckMarker(method, \"startSel\", options.startSel);\n\t\tpairs.push(`StartSel=${options.startSel}`);\n\t}\n\tif (options.stopSel !== void 0) {\n\t\tcheckMarker(method, \"stopSel\", options.stopSel);\n\t\tpairs.push(`StopSel=${options.stopSel}`);\n\t}\n\tif (options.maxWords !== void 0) {\n\t\tcheckWordCount(method, \"maxWords\", options.maxWords);\n\t\tpairs.push(`MaxWords=${options.maxWords}`);\n\t}\n\tif (options.minWords !== void 0) {\n\t\tcheckWordCount(method, \"minWords\", options.minWords);\n\t\tif (options.maxWords !== void 0 && options.minWords >= options.maxWords) throw invalid(method, \"minWords\", options.minWords, `minWords (${options.minWords}) must be below maxWords (${options.maxWords}).`, \"Postgres requires MinWords strictly below MaxWords. Lower minWords, or raise maxWords.\");\n\t\tpairs.push(`MinWords=${options.minWords}`);\n\t}\n\tif (options.highlightAll !== void 0) {\n\t\tif (typeof options.highlightAll !== \"boolean\") throw invalid(method, \"highlightAll\", options.highlightAll, `highlightAll must be a boolean, received ${JSON.stringify(options.highlightAll)}.`, \"Pass true to mark up the whole document, or false to extract fragments.\");\n\t\tpairs.push(`HighlightAll=${options.highlightAll}`);\n\t}\n\treturn pairs.length === 0 ? void 0 : LiteralExpr.of(pairs.join(\", \"));\n}\n//#endregion\n//#region src/core/full-text-parsers.ts\nconst TEXT_REF = { codecId: PG_TEXT_CODEC_ID };\nfunction parser(method, fn) {\n\treturn (text, options = {}) => buildOperation({\n\t\tmethod,\n\t\targs: [toExpr(text, TEXT_REF), languageLiteral(method, options.language ?? \"english\")],\n\t\treturns: {\n\t\t\tcodecId: PG_TSQUERY_CODEC_ID,\n\t\t\tnullable: false\n\t\t},\n\t\tlowering: {\n\t\t\ttargetFamily: \"sql\",\n\t\t\ttemplate: `${fn}({{arg0}}, {{self}})`\n\t\t}\n\t});\n}\n/** Postgres `websearch_to_tsquery`: search-box syntax with quotes, `or` and `-`. Never errors. */\nconst websearchToTsquery = parser(\"websearchToTsquery\", \"websearch_to_tsquery\");\n/**\n* Postgres `to_tsquery`: operator syntax (`'zebra' & !'graze'`, `zeb:*`), each word normalized.\n* Malformed input fails at execution, so pass only text the application wrote, never user input;\n* `tsquery` interpolates user input safely.\n*/\nconst toTsquery = parser(\"toTsquery\", \"to_tsquery\");\n/** Postgres `plainto_tsquery`: every word must match. */\nconst plaintoTsquery = parser(\"plaintoTsquery\", \"plainto_tsquery\");\n/** Postgres `phraseto_tsquery`: the words must match in order. */\nconst phrasetoTsquery = parser(\"phrasetoTsquery\", \"phraseto_tsquery\");\n//#endregion\nexport { headlineOptionsLiteral as a, FullTextDocument as c, websearchToTsquery as i, fullTextDocument as l, plaintoTsquery as n, languageLiteral as o, toTsquery as r, normalizationLiteral as s, phrasetoTsquery as t };\n\n//# sourceMappingURL=full-text-parsers-DHtcrdrH.mjs.map"],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { s as postgresError } from "./errors-DYyzTYzE-39CV_aMo.mjs";
|
|
2
|
+
import { r as quoteIdentifier } from "./sql-utils-CVsvXiX4-C7xD0Bgv.mjs";
|
|
3
|
+
import { l as fullTextIndexProblems, o as describeFullTextIndexProblem, r as FULL_TEXT_WEIGHTS } from "./full-text-index-definition-D-QC3DO2-DXbQitDn.mjs";
|
|
4
|
+
import { assertDefined } from "@prisma/orm-framework/utils/assertions";
|
|
5
|
+
//#region ../../../3-targets/3-targets/postgres/dist/full-text-search-document-DJd-9K-K.mjs
|
|
6
|
+
/**
|
|
7
|
+
* The search document of a full-text index: the expression the index is built over and the one
|
|
8
|
+
* `fullTextMatches` and `fullTextRank` search. Postgres uses an expression index only when the
|
|
9
|
+
* query carries the same expression, so the index DDL, the schema node and the query operations
|
|
10
|
+
* all render it here, from weight groups their callers have already checked.
|
|
11
|
+
*
|
|
12
|
+
* One field alone is `to_tsvector(language, field)`. With more fields, each gets its own
|
|
13
|
+
* `to_tsvector`, wrapped in `coalesce(field, '')` since one null would make the whole document
|
|
14
|
+
* null, and they are joined with `||`. With more than one group, each field is weighted with its
|
|
15
|
+
* group's weight, `A` for the first. The document depends on the groups and the language only, so
|
|
16
|
+
* a column's nullability never changes it.
|
|
17
|
+
*/
|
|
18
|
+
function renderFullTextDocument(groups, writer) {
|
|
19
|
+
const fieldCount = groups.reduce((count, group) => count + group.length, 0);
|
|
20
|
+
const weighted = groups.length > 1;
|
|
21
|
+
const vectors = groups.flatMap((group, position) => group.map((field) => {
|
|
22
|
+
const column = writer.column(field);
|
|
23
|
+
const text = fieldCount > 1 ? `coalesce(${column}, '')` : column;
|
|
24
|
+
const vector = `to_tsvector(${writer.language}, ${text})`;
|
|
25
|
+
if (!weighted) return vector;
|
|
26
|
+
const weight = FULL_TEXT_WEIGHTS[position];
|
|
27
|
+
assertDefined(weight, `a full-text document has no weight for group ${position + 1}`);
|
|
28
|
+
return `setweight(${vector}, '${weight}')`;
|
|
29
|
+
}));
|
|
30
|
+
const [only] = vectors;
|
|
31
|
+
assertDefined(only, "a full-text document has at least one field");
|
|
32
|
+
return vectors.length === 1 ? only : `(${vectors.join(" || ")})`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The search document over storage columns, as the index DDL and the schema node carry it. A
|
|
36
|
+
* definition that breaks a rule of a full-text index is refused.
|
|
37
|
+
*/
|
|
38
|
+
function renderFullTextIndexDocument(definition) {
|
|
39
|
+
const { weightGroups } = definition;
|
|
40
|
+
const [problem] = fullTextIndexProblems({ weightGroups });
|
|
41
|
+
if (problem !== void 0) throw postgresError("CONTRACT.INDEX_INVALID", describeFullTextIndexProblem("The full-text index definition", problem), {
|
|
42
|
+
why: "Each field of a search document is weighted by the position of its group, so the document is rendered only from weight groups that follow the rules of a full-text index.",
|
|
43
|
+
fix: "Pass one to four non-empty weight groups that name each column once.",
|
|
44
|
+
meta: { weightGroups }
|
|
45
|
+
});
|
|
46
|
+
return renderFullTextDocument(weightGroups, {
|
|
47
|
+
column: quoteIdentifier,
|
|
48
|
+
language: `'${definition.language}'`
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { renderFullTextIndexDocument as n, renderFullTextDocument as t };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=full-text-search-document-DJd-9K-K-CuV_QLH3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"full-text-search-document-DJd-9K-K-CuV_QLH3.mjs","names":[],"sources":["../../../../3-targets/3-targets/postgres/dist/full-text-search-document-DJd-9K-K.mjs"],"sourcesContent":["import { s as postgresError } from \"./errors-DYyzTYzE.mjs\";\nimport { r as quoteIdentifier } from \"./sql-utils-CVsvXiX4.mjs\";\nimport { d as FULL_TEXT_WEIGHTS, o as fullTextIndexProblems, r as describeFullTextIndexProblem } from \"./full-text-index-definition-D-QC3DO2.mjs\";\nimport { assertDefined } from \"@internal/utils/assertions\";\n//#region src/core/full-text-search-document.ts\n/**\n* The search document of a full-text index: the expression the index is built over and the one\n* `fullTextMatches` and `fullTextRank` search. Postgres uses an expression index only when the\n* query carries the same expression, so the index DDL, the schema node and the query operations\n* all render it here, from weight groups their callers have already checked.\n*\n* One field alone is `to_tsvector(language, field)`. With more fields, each gets its own\n* `to_tsvector`, wrapped in `coalesce(field, '')` since one null would make the whole document\n* null, and they are joined with `||`. With more than one group, each field is weighted with its\n* group's weight, `A` for the first. The document depends on the groups and the language only, so\n* a column's nullability never changes it.\n*/\nfunction renderFullTextDocument(groups, writer) {\n\tconst fieldCount = groups.reduce((count, group) => count + group.length, 0);\n\tconst weighted = groups.length > 1;\n\tconst vectors = groups.flatMap((group, position) => group.map((field) => {\n\t\tconst column = writer.column(field);\n\t\tconst text = fieldCount > 1 ? `coalesce(${column}, '')` : column;\n\t\tconst vector = `to_tsvector(${writer.language}, ${text})`;\n\t\tif (!weighted) return vector;\n\t\tconst weight = FULL_TEXT_WEIGHTS[position];\n\t\tassertDefined(weight, `a full-text document has no weight for group ${position + 1}`);\n\t\treturn `setweight(${vector}, '${weight}')`;\n\t}));\n\tconst [only] = vectors;\n\tassertDefined(only, \"a full-text document has at least one field\");\n\treturn vectors.length === 1 ? only : `(${vectors.join(\" || \")})`;\n}\n/**\n* The search document over storage columns, as the index DDL and the schema node carry it. A\n* definition that breaks a rule of a full-text index is refused.\n*/\nfunction renderFullTextIndexDocument(definition) {\n\tconst { weightGroups } = definition;\n\tconst [problem] = fullTextIndexProblems({ weightGroups });\n\tif (problem !== void 0) throw postgresError(\"CONTRACT.INDEX_INVALID\", describeFullTextIndexProblem(\"The full-text index definition\", problem), {\n\t\twhy: \"Each field of a search document is weighted by the position of its group, so the document is rendered only from weight groups that follow the rules of a full-text index.\",\n\t\tfix: \"Pass one to four non-empty weight groups that name each column once.\",\n\t\tmeta: { weightGroups }\n\t});\n\treturn renderFullTextDocument(weightGroups, {\n\t\tcolumn: quoteIdentifier,\n\t\tlanguage: `'${definition.language}'`\n\t});\n}\n//#endregion\nexport { renderFullTextIndexDocument as n, renderFullTextDocument as t };\n\n//# sourceMappingURL=full-text-search-document-DJd-9K-K.mjs.map"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAS,uBAAuB,QAAQ,QAAQ;CAC/C,MAAM,aAAa,OAAO,QAAQ,OAAO,UAAU,QAAQ,MAAM,QAAQ,CAAC;CAC1E,MAAM,WAAW,OAAO,SAAS;CACjC,MAAM,UAAU,OAAO,SAAS,OAAO,aAAa,MAAM,KAAK,UAAU;EACxE,MAAM,SAAS,OAAO,OAAO,KAAK;EAClC,MAAM,OAAO,aAAa,IAAI,YAAY,OAAO,SAAS;EAC1D,MAAM,SAAS,eAAe,OAAO,SAAS,IAAI,KAAK;EACvD,IAAI,CAAC,UAAU,OAAO;EACtB,MAAM,SAAS,kBAAkB;EACjC,cAAc,QAAQ,gDAAgD,WAAW,GAAG;EACpF,OAAO,aAAa,OAAO,KAAK,OAAO;CACxC,CAAC,CAAC;CACF,MAAM,CAAC,QAAQ;CACf,cAAc,MAAM,6CAA6C;CACjE,OAAO,QAAQ,WAAW,IAAI,OAAO,IAAI,QAAQ,KAAK,MAAM,EAAE;AAC/D;;;;;AAKA,SAAS,4BAA4B,YAAY;CAChD,MAAM,EAAE,iBAAiB;CACzB,MAAM,CAAC,WAAW,sBAAsB,EAAE,aAAa,CAAC;CACxD,IAAI,YAAY,KAAK,GAAG,MAAM,cAAc,0BAA0B,6BAA6B,kCAAkC,OAAO,GAAG;EAC9I,KAAK;EACL,KAAK;EACL,MAAM,EAAE,aAAa;CACtB,CAAC;CACD,OAAO,uBAAuB,cAAc;EAC3C,QAAQ;EACR,UAAU,IAAI,WAAW,SAAS;CACnC,CAAC;AACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { n as FULL_TEXT_INDEX_TYPE, u as fullTextIndexType } from "./full-text-index-definition-D-QC3DO2-DXbQitDn.mjs";
|
|
2
|
+
import { type } from "arktype";
|
|
3
|
+
import { accessMethodOf, defineIndexTypes } from "@prisma/orm-family-sql/contract/index-types";
|
|
4
|
+
//#region ../../../3-targets/3-targets/postgres/dist/index-types-Bdy_UGfY.mjs
|
|
5
|
+
const postgresIndexTypes = defineIndexTypes().add("btree", { options: type("object") }).add("hash", { options: type("object") }).add("gin", { options: type("object") }).add("gist", { options: type("object") }).add("spgist", { options: type("object") }).add("brin", { options: type("object") }).add(FULL_TEXT_INDEX_TYPE, fullTextIndexType);
|
|
6
|
+
/** The access method an index of this type is created with; a type Postgres does not register is its own. */
|
|
7
|
+
function postgresAccessMethodOf(typeLiteral) {
|
|
8
|
+
const entry = postgresIndexTypes.entries.find((candidate) => candidate.type === typeLiteral);
|
|
9
|
+
return entry === void 0 ? typeLiteral : accessMethodOf(entry);
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { postgresIndexTypes as n, postgresAccessMethodOf as t };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=index-types-Bdy_UGfY-CqEPukzT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-types-Bdy_UGfY-CqEPukzT.mjs","names":[],"sources":["../../../../3-targets/3-targets/postgres/dist/index-types-Bdy_UGfY.mjs"],"sourcesContent":["import { s as fullTextIndexType, t as FULL_TEXT_INDEX_TYPE } from \"./full-text-index-definition-D-QC3DO2.mjs\";\nimport { type } from \"arktype\";\nimport { accessMethodOf, defineIndexTypes } from \"@internal/sql-contract/index-types\";\n//#region src/core/index-types.ts\nconst postgresIndexTypes = defineIndexTypes().add(\"btree\", { options: type(\"object\") }).add(\"hash\", { options: type(\"object\") }).add(\"gin\", { options: type(\"object\") }).add(\"gist\", { options: type(\"object\") }).add(\"spgist\", { options: type(\"object\") }).add(\"brin\", { options: type(\"object\") }).add(FULL_TEXT_INDEX_TYPE, fullTextIndexType);\n/** The access method an index of this type is created with; a type Postgres does not register is its own. */\nfunction postgresAccessMethodOf(typeLiteral) {\n\tconst entry = postgresIndexTypes.entries.find((candidate) => candidate.type === typeLiteral);\n\treturn entry === void 0 ? typeLiteral : accessMethodOf(entry);\n}\n//#endregion\nexport { postgresIndexTypes as n, postgresAccessMethodOf as t };\n\n//# sourceMappingURL=index-types-Bdy_UGfY.mjs.map"],"mappings":";;;;AAIA,MAAM,qBAAqB,iBAAiB,CAAC,CAAC,IAAI,SAAS,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,UAAU,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,sBAAsB,iBAAiB;;AAEjV,SAAS,uBAAuB,aAAa;CAC5C,MAAM,QAAQ,mBAAmB,QAAQ,MAAM,cAAc,UAAU,SAAS,WAAW;CAC3F,OAAO,UAAU,KAAK,IAAI,cAAc,eAAe,KAAK;AAC7D"}
|
package/dist/{infer-psl-contract-Buc1MJaS-70Kw0cxc.mjs → infer-psl-contract-lnoCopbJ-DRVPVZyI.mjs}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { S as PG_TEXT_CODEC_ID } from "./codec-ids-Cb0yO-IS--e0P2rfI.mjs";
|
|
2
2
|
import { s as postgresError } from "./errors-DYyzTYzE-39CV_aMo.mjs";
|
|
3
3
|
import { t as createPostgresBuiltinDataTypeLookup } from "./data-types-DRkmmE9S-C5Q9oH4Q.mjs";
|
|
4
|
-
import { r as POLICY_BLOCK_KEYWORDS } from "./authoring-
|
|
4
|
+
import { r as POLICY_BLOCK_KEYWORDS } from "./authoring-CL05jlfX-CKUKjRVV.mjs";
|
|
5
5
|
import { t as postgresRenderCheckExpressions } from "./check-expressions-BaFrBceq-ChgvazEN.mjs";
|
|
6
6
|
import { t as postgresDataTypeEntries } from "./data-type-entries-DoR61yeO-BB2cY7rI.mjs";
|
|
7
7
|
import { t as parsePostgresDefault } from "./default-normalizer-Bf_Fhv4v-CugGfLAe.mjs";
|
|
@@ -9,8 +9,8 @@ import { canonicalFormOf, codecForRef } from "@prisma/orm-framework/components/c
|
|
|
9
9
|
import { blindCast } from "@prisma/orm-framework/utils/casts";
|
|
10
10
|
import { escapePslString } from "@prisma/orm-family-sql/contract/data-type-support";
|
|
11
11
|
import { coordinateKey, elementCoordinates } from "@prisma/orm-framework/components/ir";
|
|
12
|
-
import { composeCheckWirePrefix, computeCheckContentHash, computeIndexContentHash, formatWireName, parseWireName } from "@prisma/orm-family-sql/schema-ir/naming";
|
|
13
12
|
import { assertDefined } from "@prisma/orm-framework/utils/assertions";
|
|
13
|
+
import { composeCheckWirePrefix, computeCheckContentHash, computeIndexContentHash, formatWireName, parseWireName } from "@prisma/orm-family-sql/schema-ir/naming";
|
|
14
14
|
import { ifDefined } from "@prisma/orm-framework/utils/defined";
|
|
15
15
|
import { getAuthoringTypeConstructor, instantiateAuthoringTypeConstructor, validateAuthoringHelperArguments } from "@prisma/orm-framework/components/authoring";
|
|
16
16
|
import { NAME_THE_PSL_SOURCE_LOSES, isPslIdentifier } from "@prisma/orm-framework/psl-parser";
|
|
@@ -21,7 +21,7 @@ import { UNSPECIFIED_PSL_NAMESPACE_ID, makePslNamespace, makePslNamespaceEntries
|
|
|
21
21
|
import { parsePslPositionalArgs } from "@prisma/orm-framework/psl-parser/interpret";
|
|
22
22
|
import { mapDefault, toEnumMemberName } from "@prisma/orm-family-sql/family/psl-build";
|
|
23
23
|
import { isColumnDefault } from "@prisma/orm-framework/contract/types";
|
|
24
|
-
//#region ../../../3-targets/3-targets/postgres/dist/infer-psl-contract-
|
|
24
|
+
//#region ../../../3-targets/3-targets/postgres/dist/infer-psl-contract-lnoCopbJ.mjs
|
|
25
25
|
/** A contract written for an existing database reads every date and time column as PostgreSQL's text. */
|
|
26
26
|
const EXISTING_COLUMN_DATE_TIME_TYPES = {
|
|
27
27
|
timestamp: "TimestampString",
|
|
@@ -577,6 +577,19 @@ function buildIndexAttribute(index, fieldNames, naming = detectIndexNaming(index
|
|
|
577
577
|
return buildAttribute("model", "index", args);
|
|
578
578
|
}
|
|
579
579
|
/**
|
|
580
|
+
* Emits one `@@fullTextIndex` attribute. A weight group of one field is written as the bare field,
|
|
581
|
+
* a larger group as a list, and the language only when it is not the default.
|
|
582
|
+
*/
|
|
583
|
+
function buildFullTextIndexAttribute(index, definition, fieldNameOf, naming) {
|
|
584
|
+
const args = [positionalArg(`[${definition.weightGroups.map((group) => {
|
|
585
|
+
const names = group.map(fieldNameOf);
|
|
586
|
+
return names.length === 1 ? names[0] ?? "" : `[${names.join(", ")}]`;
|
|
587
|
+
}).join(", ")}]`), namingArg(naming, index.name)];
|
|
588
|
+
if (definition.language !== "english") args.push(namedArg("language", `"${definition.language}"`));
|
|
589
|
+
if (index.where !== void 0) args.push(namedArg("where", `"${escapePslString(index.where)}"`));
|
|
590
|
+
return buildAttribute("model", "fullTextIndex", args);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
580
593
|
* Emits one `@@check` attribute, named as `naming` says. Without it, a live,
|
|
581
594
|
* non-derived check is written in the `map:` form. Re-detecting `name:` is not
|
|
582
595
|
* attempted there: the live expression is Postgres's own reprint, but a
|
|
@@ -1078,6 +1091,6 @@ function buildPslDocumentAst(schemaIR, options, foreignKeyExtras, namespaceName,
|
|
|
1078
1091
|
};
|
|
1079
1092
|
}
|
|
1080
1093
|
//#endregion
|
|
1081
|
-
export {
|
|
1094
|
+
export { positionalArg as _, buildFullTextIndexAttribute as a, buildModelConstraintAttribute as c, createPostgresDefaultMapping as d, createPostgresTypeMap as f, parseDefaultAttributeString as g, noColumnDefaults as h, buildCheckAttribute as i, buildNativeEnumBlock as l, namedArg as m, SYNTHETIC_SPAN as n, buildIndexAttribute as o, inferPostgresPslContract as p, buildAttribute as r, buildMapAttribute as s, EXISTING_COLUMN_DATE_TIME_TYPES as t, buildPslDocumentAst as u };
|
|
1082
1095
|
|
|
1083
|
-
//# sourceMappingURL=infer-psl-contract-
|
|
1096
|
+
//# sourceMappingURL=infer-psl-contract-lnoCopbJ-DRVPVZyI.mjs.map
|