@simtlix/simfinity-postgres 3.15.0 → 3.16.0
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/README.md +5 -3
- package/package.json +3 -3
- package/src/codecs.js +1 -1
- package/src/index.js +1 -1
- package/src/plugin.js +1 -1
- package/src/query/case-fold.js +4 -4
- package/src/query/compiler.js +24 -2
- package/types/index.d.ts +9 -5
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ import { postgresPlugin } from '@simtlix/simfinity-postgres';
|
|
|
31
31
|
const simfinity = createSQL({ plugin: postgresPlugin({ pool, schema: 'library' }) });
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Install `@simtlix/simfinity-sql@3.
|
|
34
|
+
Install `@simtlix/simfinity-sql@3.16.0` as a direct dependency when importing its factory. PostgreSQL 15 or later is the only supported SQL plugin. The [SQL package guide](https://github.com/simtlix/simfinity.js/tree/master/packages/sql) documents relational planning and the versioned plugin contract.
|
|
35
35
|
|
|
36
36
|
Both factories permanently bind one pool and schema, and five optional settings: `multiRowInserts: false` keeps one `INSERT` per owned row instead of multi-row statements; `explicitNullsOrder: true` keeps the `NULLS` clause on sorts of `id` and required fields, as 3.5.9 did, instead of letting indexes serve them; `batchedCollections: true` reads the generated collection fields of the parents that share their arguments with one statement per 100 parents, in a transaction that turns JIT off for that transaction only, instead of one statement per field as 3.6.0 did and as the default still does, and can return unsorted and tied rows in another order; the opt-in `refreshTriggers: 'perRoot'` refreshes each changed root's owned shape and unique keys once per transaction, while its guard trigger stays deferred, instead of once per changed row; and the opt-in `ownerIndexes: 'minimal'` leaves out the `(__owner_id)` indexes that the primary key or a unique index covers on new owned and guard tables. An unknown `refreshTriggers` or `ownerIndexes` value throws `INVALID_DATABASE_SCHEMA` (400). Read the [upgrade notes](https://simtlix.github.io/simfinity.js/resources/compatibility.html#upgrade-to-3-6-0) before enabling the opt-ins: versions up to 3.5.9 cannot validate databases created with them. The returned runtime supports registration, generated queries and mutations, middleware and scopes, controllers and validators, custom queries and mutations, named views, state machines, nested relationship writes, embedded reconstruction, and native PostgreSQL model handles. Native handles expose `findById`, `find`, `create`, `update`, and `delete`; they are not Mongoose models. `find(args, { session })` accepts the generated GraphQL list query arguments. Existing `pg.Pool` configuration and `pg.PoolClient` query interfaces remain compatible across both factories. A custom pool or client wrapper should pass `pg`'s `command` through in query results: the plugin reads it from the `COMMIT` result to detect a transaction that PostgreSQL rolled back because one of its statements failed, and without it such a transaction reports success with nothing stored.
|
|
37
37
|
|
|
@@ -55,6 +55,8 @@ await initializeDatabase({ mode: 'validate' });
|
|
|
55
55
|
|
|
56
56
|
Called without arguments after `createSchema()`, the module's `describeDatabase()` and `compileDatabaseSchema()` describe and compile this default instance in its configured schema.
|
|
57
57
|
|
|
58
|
+
Since 3.16.0, the module and every instance also expose `updateObject`, `deleteObject` and `transitionObject` next to `saveObject`, which run the update, delete and state action lifecycle in an owned transaction or in a session from `withTransaction`, and `createSchema(…, { transaction })` can add a mutation that runs several generated mutations in one PostgreSQL transaction.
|
|
59
|
+
|
|
58
60
|
Transactions use one borrowed `pg` client and repeatable-read isolation. Reads without a session of types without owned embedded tables run as a single statement on a pooled connection instead. With `batchedCollections: true`, the runtime reads the generated collection fields of up to 100 parents that share their arguments in one batch, with one statement, a `UNION ALL` of each parent's own statement with its parent ID as a parameter of its own, so PostgreSQL plans each parent's rows as it plans that parent's own statement; more parents run as several batches, each in its own transaction. Each batch runs in one repeatable-read transaction: `BEGIN`, `SET LOCAL jit = off`, the statement, the owned-row reads, then `COMMIT`. Only a direct `findChildrenBatch` call on the SQL adapter with more than 100 IDs repeats `SET LOCAL` and the statement for each further 100 within its transaction. The batch's plan can cost more than `jit_above_cost` when no parent's own plan does, and JIT compilation of its branches can take longer than the statement itself; `SET LOCAL` ends with the transaction, so pooled connections keep the server's setting. A batch takes these 4 round trips, or more with owned rows, one after another on one connection and runs its parents one after another, where per-parent statements take one round trip each, concurrently on the pool's free connections. It pays off when the pool is saturated or much smaller than the number of parents per level, as with many parents with small child lists; with free connections it can be slower, even on a remote database, so measure before enabling it. Transaction-mode PgBouncer keeps each batch on one server connection, while Amazon RDS Proxy pins the pooled connections that run batches, for their `SET LOCAL` and their statements over 16 KB. See [batched collection reads](https://simtlix.github.io/simfinity.js/guide/relationships.html#batched-collection-reads). A supplied Simfinity PostgreSQL session joins the active transaction. Serialization failures and deadlocks are retried up to five times, each after a short random delay that starts once the client is released; mutation input is reset for each attempt. Unknown commit outcomes are not replayed. The caller owns the pool lifecycle.
|
|
59
61
|
|
|
60
62
|
The module and every `createPostgres` instance expose the shared `auth`, `validators`, `scalars`, and `plugins` helpers. These are the same helper objects exported by the MongoDB package, so rules, scalar identities, and errors can be shared safely between backends.
|
|
@@ -62,7 +64,7 @@ The module and every `createPostgres` instance expose the shared `auth`, `valida
|
|
|
62
64
|
MCP integration is an independent opt-in and does not add MCP dependencies to PostgreSQL applications:
|
|
63
65
|
|
|
64
66
|
```sh
|
|
65
|
-
npm install @simtlix/simfinity-mcp@3.
|
|
67
|
+
npm install @simtlix/simfinity-mcp@3.16.0 @modelcontextprotocol/sdk@^1.31.0
|
|
66
68
|
```
|
|
67
69
|
|
|
68
70
|
```javascript
|
|
@@ -77,7 +79,7 @@ Entity identities and references use UUIDs. Scalars use native PostgreSQL types,
|
|
|
77
79
|
|
|
78
80
|
Queries support nested scalar/reference paths, logical filter groups, scopes, sort, pagination, count, and grouped `SUM`, `COUNT`, `AVG`, `MIN`, and `MAX` facts. The PostgreSQL implementation preserves root multiplicity when joining collection paths.
|
|
79
81
|
|
|
80
|
-
The text operators take literal values as bound parameters. `LIKE`, `STARTS_WITH` and `ENDS_WITH` compare code points, and `STARTS_WITH` can use a column's btree index. `ILIKE`, `ISTARTS_WITH`, `IENDS_WITH` and `IEQ` fold both sides with the Unicode simple case foldings that MongoDB's case-insensitive matching applies, through one expression, `translate(lower((x) COLLATE "pg_catalog"."und-x-icu"), from, to)`, where `translate()` maps the 22 lowercase variants that ICU `lower()` keeps, such as `ſ`, `µ` and the final sigma `ς`, to their usual letters; so each returns every row that its case-sensitive form returns, and `ISTARTS_WITH "ΚΑΣ"` finds `ΚΑΣΤΡΟ`. The first three match a `LIKE` pattern whose `%`, `_` and `\` are escaped. The two backends still differ on `İ`, which ICU lowers to `i` followed by U+0307, and on letters newer than one side's Unicode tables. The fold needs a `UTF8` database on a server built with ICU: on another, such as one in `LATIN1`, these four operators fail with `UNSUPPORTED_QUERY` (400), and every other operation works. Indexes serve them only on exactly the compiled expression, which the exported `caseFoldExpression(sqlExpression)` returns, such as `caseFoldExpression('"name"')`: a btree with `text_pattern_ops` on it serves `IEQ` and `ISTARTS_WITH`, and a `pg_trgm` GIN index with `gin_trgm_ops` serves `ILIKE`, `ISTARTS_WITH` and `IENDS_WITH`. The [queries guide](https://simtlix.github.io/simfinity.js/guide/queries.html#case-folding) gives the details and the index statements.
|
|
82
|
+
The text operators take literal values as bound parameters. `LIKE`, `STARTS_WITH` and `ENDS_WITH` compare code points, and `STARTS_WITH` can use a column's btree index. `ILIKE`, `ISTARTS_WITH`, `IENDS_WITH` and `IEQ` fold both sides with the Unicode simple case foldings that MongoDB's case-insensitive matching applies, through one expression, `translate(lower((x) COLLATE "pg_catalog"."und-x-icu"), from, to)`, where `translate()` maps the 22 lowercase variants that ICU `lower()` keeps, such as `ſ`, `µ` and the final sigma `ς`, to their usual letters; so each returns every row that its case-sensitive form returns, and `ISTARTS_WITH "ΚΑΣ"` finds `ΚΑΣΤΡΟ`. The first three match a `LIKE` pattern whose `%`, `_` and `\` are escaped. The two backends still differ on `İ`, which ICU lowers to `i` followed by U+0307, and on letters newer than one side's Unicode tables. `IIN`, `IN` ignoring case, folds both sides the same way, as `fold("column") = ANY (ARRAY(SELECT fold(w.value) FROM unnest($1::text[]) w(value)))` with its values bound as one array, and compiles `IIN []` to `FALSE`. The fold needs a `UTF8` database on a server built with ICU: on another, such as one in `LATIN1`, these four operators and `IIN` fail with `UNSUPPORTED_QUERY` (400), and every other operation works. Indexes serve them only on exactly the compiled expression, which the exported `caseFoldExpression(sqlExpression)` returns, such as `caseFoldExpression('"name"')`: a btree with `text_pattern_ops` on it serves `IEQ`, `IIN` and `ISTARTS_WITH`, and a `pg_trgm` GIN index with `gin_trgm_ops` serves `ILIKE`, `ISTARTS_WITH` and `IENDS_WITH`. [`CONTAINS_ALL`](https://simtlix.github.io/simfinity.js/guide/queries.html#filters-on-lists) compiles to `"column" @> $1::type[]` on a list of the root record, which a GIN index of your own on the column serves, and initialization keeps such an index in both modes; lists inside embedded values are scanned. The [queries guide](https://simtlix.github.io/simfinity.js/guide/queries.html#case-folding) gives the details and the index statements.
|
|
81
83
|
|
|
82
84
|
`IS_EMPTY` and `IS_NOT_EMPTY` take no value and test the queried record's own fields: a missing, null or `""` String, a missing or null value of any other scalar, a missing, null or `[]` list, and an embedded object that is missing, null or has every stored member empty. They compile from where the path is stored and bind no parameters: `(c IS NULL OR c = '')` for a String column, so that a btree serves it through a `BitmapOr`, `c IS NULL` for any other column, including the uuid identity of a record whose `id` is declared `String`, and `COALESCE(cardinality(c), 0) = 0` for a native array, also on owned rows; a jsonb member is read as text with `->>` and never cast, a jsonb list through a `jsonb_typeof` guard, and a jsonb object as SQL `NULL`, JSON `null` or all of its members empty; an owned single object is empty when its state is not `present` or no owned row has a member that is not empty, and an owned list when its state is not `present` or it has no row, null items included, with a subquery alias of its own at each level of owned storage. `IS_NOT_EMPTY` is the positive form of a leaf and the `NOT` of an object or owned form, so every record matches exactly one of the two. An emptiness path that continues inside an embedded list, such as `lines.qty`, fails with `INVALID_FILTER_PATH` (400), since emptiness of an item inside that list is not defined. Through a collection, use an explicit frame and test the element's own field (for example `ANY seasons` with `year IS_EMPTY`); the flattened `seasons.year IS_EMPTY` shorthand is excluded. The [queries guide](https://simtlix.github.io/simfinity.js/guide/queries.html) describes the rules.
|
|
83
85
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simtlix/simfinity-postgres",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.16.0",
|
|
4
4
|
"description": "PostgreSQL GraphQL runtime and schema generation with foreign keys for Simfinity",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"directory": "packages/postgres"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@simtlix/simfinity-core": "3.
|
|
31
|
-
"@simtlix/simfinity-sql": "3.
|
|
30
|
+
"@simtlix/simfinity-core": "3.16.0",
|
|
31
|
+
"@simtlix/simfinity-sql": "3.16.0",
|
|
32
32
|
"pg": "^8.16.3"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
package/src/codecs.js
CHANGED
|
@@ -77,7 +77,7 @@ export const isPostgresError = (error) => typeof error?.code === 'string' && /^[
|
|
|
77
77
|
|
|
78
78
|
// A statement that folds case on a database that cannot evaluate the fold (see isCaseFoldUnsupported): the request
|
|
79
79
|
// uses an operator that this database cannot run, while every other operation keeps working.
|
|
80
|
-
const CASE_FOLD_UNSUPPORTED = ['ILIKE, ISTARTS_WITH, IENDS_WITH and
|
|
80
|
+
const CASE_FOLD_UNSUPPORTED = ['ILIKE, ISTARTS_WITH, IENDS_WITH, IEQ and IIN need a UTF8 database with the ICU collation und-x-icu', 'UNSUPPORTED_QUERY', 400];
|
|
81
81
|
|
|
82
82
|
/** Maps PostgreSQL errors (and exhausted retries) without SQL details; returns every other value unchanged. */
|
|
83
83
|
export const normalizeDatabaseError = (error) => {
|
package/src/index.js
CHANGED
|
@@ -22,7 +22,7 @@ export {
|
|
|
22
22
|
/** Each instance permanently binds one pool/schema; getModel exposes PostgreSQL native helpers. */
|
|
23
23
|
export const createPostgres = (options) => createSQL({ plugin: postgresPlugin(options) });
|
|
24
24
|
const defaultInstance = createPostgres();
|
|
25
|
-
export const { configureQueryLimits, configureMutationLimits, configureAfterCommit, configure, connect, addNoEndpointType, createSchema, getModel, getType, getInputType, getRegistrations, use, registerMutation, registerCustomQuery, registerView, saveObject, preventCreatingCollection, withTransaction } = defaultInstance;
|
|
25
|
+
export const { configureQueryLimits, configureMutationLimits, configureAfterCommit, configure, connect, addNoEndpointType, createSchema, getModel, getType, getInputType, getRegistrations, use, registerMutation, registerCustomQuery, registerView, saveObject, updateObject, deleteObject, transitionObject, preventCreatingCollection, withTransaction } = defaultInstance;
|
|
26
26
|
|
|
27
27
|
/** Preserve the foundation low-level API while allowing initialization of the configured default instance. */
|
|
28
28
|
export const initializeDatabase = (poolOrOptions, description, options) => description
|
package/src/plugin.js
CHANGED
|
@@ -24,7 +24,7 @@ export const postgresPlugin = (options) => ({
|
|
|
24
24
|
// declaration names the compileQuery it describes, so a copy of this plugin with another compileQuery compiles the
|
|
25
25
|
// operators of 3.7.0, without reference emptiness or quantifiers, until it declares its own.
|
|
26
26
|
queryFeatures: {
|
|
27
|
-
operators: ['EQ', 'NE', 'LT', 'LTE', 'GT', 'GTE', 'BTW', 'IN', 'NIN', 'LIKE', 'ILIKE', 'STARTS_WITH', 'ISTARTS_WITH', 'ENDS_WITH', 'IENDS_WITH', 'IEQ', 'IS_EMPTY', 'IS_NOT_EMPTY'],
|
|
27
|
+
operators: ['EQ', 'NE', 'LT', 'LTE', 'GT', 'GTE', 'BTW', 'IN', 'NIN', 'LIKE', 'ILIKE', 'STARTS_WITH', 'ISTARTS_WITH', 'ENDS_WITH', 'IENDS_WITH', 'IEQ', 'IS_EMPTY', 'IS_NOT_EMPTY', 'CONTAINS_ALL', 'IIN'],
|
|
28
28
|
referenceEmptiness: true,
|
|
29
29
|
quantifiers: true,
|
|
30
30
|
compileQuery,
|
package/src/query/case-fold.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The case fold of the case-insensitive
|
|
1
|
+
// The case fold of the case-insensitive operators (ILIKE, ISTARTS_WITH, IENDS_WITH, IEQ and IIN), the shared
|
|
2
2
|
// contract of #108 section 3.1: the Unicode simple case foldings that MongoDB's case-insensitive regular expressions
|
|
3
3
|
// apply. lower() under ICU's root collation applies them to every script the same way on every server, whatever the
|
|
4
4
|
// database's default collation (text paths are `C` columns, under which lower() folds ASCII only), except for the
|
|
@@ -47,9 +47,9 @@ const FROM = `'${CASE_FOLD_MAPPINGS.map(([from]) => from).join('')}'`;
|
|
|
47
47
|
const TO = `'${CASE_FOLD_MAPPINGS.map(([, to]) => to).join('')}'`;
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* The SQL text that folds `sqlExpression` for the case-insensitive text operators, exactly as the compiler
|
|
51
|
-
* both sides of each comparison: `translate(lower((<expression>) COLLATE "pg_catalog"."und-x-icu"),
|
|
52
|
-
* '<their simple case foldings>')`. Applications build their expression indexes with it, such as
|
|
50
|
+
* The SQL text that folds `sqlExpression` for the case-insensitive text operators and IIN, exactly as the compiler
|
|
51
|
+
* writes it on both sides of each comparison: `translate(lower((<expression>) COLLATE "pg_catalog"."und-x-icu"),
|
|
52
|
+
* '<22 characters>', '<their simple case foldings>')`. Applications build their expression indexes with it, such as
|
|
53
53
|
* `CREATE INDEX ... (${caseFoldExpression('"name"')} text_pattern_ops)`. The expression is trusted SQL, inserted as
|
|
54
54
|
* given: quote identifiers yourself and never pass request input. It goes in parentheses, because COLLATE binds more
|
|
55
55
|
* tightly than `->>` and every other binary operator: without them, `"details" ->> 'label'` would collate only
|
package/src/query/compiler.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { QLQuantifier, resolveModelPath, SimfinityError } from '@simtlix/simfinity-core';
|
|
2
2
|
import {
|
|
3
|
-
crossingKeys, describeEmptiness, describeModelEmptiness, emptinessScopePaths, isEmptinessOperator, textQueryOperator,
|
|
3
|
+
assertContainsAllPath, crossingKeys, describeEmptiness, describeModelEmptiness, emptinessScopePaths, isEmptinessOperator, textQueryOperator,
|
|
4
|
+
validateContainsAllValue, validateQuantifiedGroups, validateTextFilterValue, validateTextListFilterValue,
|
|
4
5
|
} from '@simtlix/simfinity-core/internal/query-operators';
|
|
5
6
|
import { identifier as q, literal, qualified } from '../schema/sql.js';
|
|
6
7
|
import { encodeScalar, storageTypes, invalidValue } from '../codecs.js';
|
|
@@ -347,6 +348,22 @@ const compileSelect = (models, database, plan, extra, configuration, batched) =>
|
|
|
347
348
|
return operator === 'IN' ? expressionSQL : `NOT ${expressionSQL}`;
|
|
348
349
|
}
|
|
349
350
|
if (operator === 'BTW') return `(${predicate(expression, 'GTE', value[0], negated)} AND ${predicate(expression, 'LTE', value[1], negated)})`;
|
|
351
|
+
if (operator === 'CONTAINS_ALL') {
|
|
352
|
+
validateContainsAllValue(value);
|
|
353
|
+
// One array parameter of the path's element type, cast like IN elements: set containment, as MongoDB's $all. NULL
|
|
354
|
+
// elements of the stored list are ignored, and a NULL list gives NULL, which only the negated form turns into false.
|
|
355
|
+
const contains = `${sql} @> ${bind(value.map(encodeValue), `${type}[]`)}`;
|
|
356
|
+
return negated ? `COALESCE(${contains}, FALSE)` : contains;
|
|
357
|
+
}
|
|
358
|
+
if (operator === 'IIN') {
|
|
359
|
+
validateTextListFilterValue(operator, value, field.scalar);
|
|
360
|
+
if (!value.length) return 'FALSE';
|
|
361
|
+
// The values are folded by the server, once per statement, so that application indexes on the folded column serve it.
|
|
362
|
+
const members = `ANY (ARRAY(SELECT ${fold('w.value')} FROM unnest(${bind(value, 'text[]')}) w(value)))`;
|
|
363
|
+
if (list) return `EXISTS (SELECT 1 FROM unnest(${sql}) v(value) WHERE ${fold('v.value')} = ${members})`;
|
|
364
|
+
const compare = `${fold(expression.uncollated)} = ${members}`;
|
|
365
|
+
return negated ? `COALESCE(${compare}, FALSE)` : compare;
|
|
366
|
+
}
|
|
350
367
|
if (value == null || Array.isArray(value)) invalidValue(`${operator} requires a non-null scalar value`);
|
|
351
368
|
const text = textQueryOperator(operator);
|
|
352
369
|
if (text) return textPredicate(expression, operator, text, value, negated);
|
|
@@ -598,6 +615,9 @@ const compileSelect = (models, database, plan, extra, configuration, batched) =>
|
|
|
598
615
|
if (!node) return 'TRUE';
|
|
599
616
|
if (node.kind === 'quantified') return quantified(node, frame);
|
|
600
617
|
if (node.kind === 'predicate' && isEmptinessOperator(node.operator)) return `(${emptiness(node, frame)})`;
|
|
618
|
+
// CONTAINS_ALL's path and leaf rules (#108 part 4), with core's codes, before any join or alias, so that a plan built
|
|
619
|
+
// by hand never compiles to the legacy collection join or the multiplying vector join, or raises 42883.
|
|
620
|
+
if (node.kind === 'predicate' && node.operator === 'CONTAINS_ALL') assertContainsAllPath(resolveModelPath(models, frame.entity, node.path));
|
|
601
621
|
if (node.kind === 'predicate') {
|
|
602
622
|
// Check ordinary paths and values before the new client metadata, without creating joins or aliases.
|
|
603
623
|
if (Object.hasOwn(node, 'joins')) validateQuantifiedGroups({ AND: [{ conditions: [{ field: node.path.join('.'), operator: node.operator, value: node.value }] }] }, { models, entity: frame.entity, referenceEmptiness: true, quantifiers: true });
|
|
@@ -609,7 +629,9 @@ const compileSelect = (models, database, plan, extra, configuration, batched) =>
|
|
|
609
629
|
const leaf = steps.at(-1);
|
|
610
630
|
const identity = ['id', '_id'].includes(leaf.name) && (steps.length === 1 ? !frame.table.ownership : steps.at(-2).kind !== 'embedded');
|
|
611
631
|
const field = operandField(leaf, identity);
|
|
612
|
-
|
|
632
|
+
// The placeholders are never emitted: detached() follows. They must be non-empty, because textPredicate and the IIN
|
|
633
|
+
// branch fold `uncollated` with caseFoldExpression, which rejects an empty expression (case-fold.js:60).
|
|
634
|
+
predicate({ field, type: storageTypes[field.scalar], list: field.list, sql: 'NULL', uncollated: 'NULL' }, node.operator, node.value, negated);
|
|
613
635
|
detached(checked.reason);
|
|
614
636
|
}
|
|
615
637
|
const sql = predicate(path(node.path, 'filter', frame, checked.joins), node.operator, node.value, negated);
|
package/types/index.d.ts
CHANGED
|
@@ -246,9 +246,10 @@ export interface PostgresRuntime extends Runtime<PostgresModel, PostgresSession>
|
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
248
248
|
* PostgreSQL 15+ plugin for createSQL; omitted options allow later runtime.configure. Its `queryFeatures` lists every
|
|
249
|
-
* `QLOperator` value. The case-insensitive text operators fold case with {@link caseFoldExpression}, which
|
|
250
|
-
* database with the ICU collation `und-x-icu`: on another database, such as one in LATIN1 or on a server
|
|
251
|
-
* ICU, they fail with UNSUPPORTED_QUERY (400),
|
|
249
|
+
* `QLOperator` value. The case-insensitive text operators and `IIN` fold case with {@link caseFoldExpression}, which
|
|
250
|
+
* needs a UTF8 database with the ICU collation `und-x-icu`: on another database, such as one in LATIN1 or on a server
|
|
251
|
+
* built without ICU, they fail with UNSUPPORTED_QUERY (400), except `IIN []`, which compiles to `FALSE` without a fold,
|
|
252
|
+
* and every other operation works.
|
|
252
253
|
*
|
|
253
254
|
* `IS_EMPTY` and `IS_NOT_EMPTY` compile from where a path is stored, binding no parameters: `(c IS NULL OR c = '')`
|
|
254
255
|
* for a String column and `c IS NULL` for any other, the uuid identity included; `COALESCE(cardinality(c), 0) = 0`
|
|
@@ -293,7 +294,7 @@ export function postgresPlugin(options?: PostgresConfiguration): SQLPlugin<
|
|
|
293
294
|
>;
|
|
294
295
|
export function createPostgres(options?: PostgresConfiguration): PostgresRuntime;
|
|
295
296
|
/**
|
|
296
|
-
* The SQL text with which ILIKE, ISTARTS_WITH, IENDS_WITH and
|
|
297
|
+
* The SQL text with which ILIKE, ISTARTS_WITH, IENDS_WITH, IEQ and IIN fold both sides of their comparison, for an SQL
|
|
297
298
|
* expression such as a quoted column name or a jsonb member: `translate(lower((<expression>) COLLATE
|
|
298
299
|
* "pg_catalog"."und-x-icu"), '<22 characters>', '<their simple case foldings>')`, the Unicode simple case foldings that
|
|
299
300
|
* MongoDB's case-insensitive matching applies. Indexes serve these operators only on exactly this expression, so build
|
|
@@ -317,6 +318,9 @@ export const registerMutation: PostgresRuntime['registerMutation'];
|
|
|
317
318
|
export const registerCustomQuery: PostgresRuntime['registerCustomQuery'];
|
|
318
319
|
export const registerView: PostgresRuntime['registerView'];
|
|
319
320
|
export const saveObject: PostgresRuntime['saveObject'];
|
|
321
|
+
export const updateObject: PostgresRuntime['updateObject'];
|
|
322
|
+
export const deleteObject: PostgresRuntime['deleteObject'];
|
|
323
|
+
export const transitionObject: PostgresRuntime['transitionObject'];
|
|
320
324
|
export const preventCreatingCollection: PostgresRuntime['preventCreatingCollection'];
|
|
321
325
|
export const withTransaction: PostgresRuntime['withTransaction'];
|
|
322
326
|
/** Initializes the default module instance, after configure/connect/createSchema. */
|
|
@@ -325,6 +329,6 @@ export function initializeDatabase(options?: InitializationOptions): Promise<Ini
|
|
|
325
329
|
export const configureQueryLimits: Runtime['configureQueryLimits'];
|
|
326
330
|
/**
|
|
327
331
|
* The same process-wide setter as every runtime's configureMutationLimits. Unknown or misspelled
|
|
328
|
-
* options throw INVALID_MUTATION_LIMITS (400) and keep the current
|
|
332
|
+
* options throw INVALID_MUTATION_LIMITS (400) and keep the current limits.
|
|
329
333
|
*/
|
|
330
334
|
export const configureMutationLimits: Runtime['configureMutationLimits'];
|