Skip to content

Commit

Permalink
Support Postgres POSIX regex operators (close #4317) (#119)
Browse files Browse the repository at this point in the history
Co-authored-by: christophediprima <dipdipdip84@gmail.com>
Co-authored-by: dip <dipdipdip84@gmail.com>
Co-authored-by: Auke Booij <auke@hasura.io>
Co-authored-by: Antoine Leblanc <antoine@hasura.io>
GITHUB_PR_NUMBER: 6172
GITHUB_PR_URL: #6172
  • Loading branch information
4 people authored Nov 27, 2020
1 parent 748ab71 commit 5192d23
Show file tree
Hide file tree
Showing 38 changed files with 416 additions and 20 deletions.
10 changes: 5 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ This release contains the [PDV refactor (#4111)](https://github.com/hasura/graph
- server: validate remote schema queries (fixes #4143)
- server: introduce optional custom table name in table configuration to track the table according to the custom name. The `set_table_custom_fields` API has been deprecated, A new API `set_table_customization` has been added to set the configuration. (#3811)
- server: support joining Int or String scalar types to ID scalar type in remote relationship
- server: add support for POSIX operators (close #4317) (#6172)
- console: allow user to cascade Postgres dependencies when dropping Postgres objects (close #5109) (#5248)
- console: mark inconsistent remote schemas in the UI (close #5093) (#5181)
- console: remove ONLY as default for ALTER TABLE in column alter operations (close #5512) #5706
Expand Down Expand Up @@ -122,7 +123,7 @@ For a more comprehensive overview, please see [the readme located here](./contri
**Sample Code**

```ts
import { TableEntry } from "../generated/HasuraMetadataV2"
import { TableEntry } from "../generated/HasuraMetadataV2";

const newTable: TableEntry = {
table: { schema: "public", name: "user" },
Expand All @@ -140,7 +141,7 @@ const newTable: TableEntry = {
},
},
],
}
};
```

**IntelliSense Example**
Expand Down Expand Up @@ -178,14 +179,14 @@ arguments.
- server: allow configuring timeouts for actions (fixes #4966)
- server: fix bug which arised when renaming a table which had a manual relationship defined (close #4158)
- server: limit the length of event trigger names (close #5786)
**NOTE:** If you have event triggers with names greater than 42 chars, then you should update their names to avoid running into Postgres identifier limit bug (#5786)
**NOTE:** If you have event triggers with names greater than 42 chars, then you should update their names to avoid running into Postgres identifier limit bug (#5786)
- server: enable HASURA_GRAPHQL_PG_CONN_LIFETIME by default to reclaim memory
- server: fix issue with tracking custom functions that return `SETOF` materialized view (close #5294) (#5945)
- server: allow remote relationships with union, interface and enum type fields as well (fixes #5875) (#6080)
- server: Fix fine-grained incremental cache invalidation (fix #6027)
This issue could cause enum table values to sometimes not be properly reloaded without restarting `graphql-engine`. Now a `reload_metadata` API call (or clicking “Reload enum values” in the console) should consistently force a reload of all enum table values.
- server: fix event trigger cleanup on deletion via replace_metadata (fix #5461) (#6137)
**WARNING**: This can cause significant load on PG on startup if you have lots of event triggers. Delay in starting up is expected.
**WARNING**: This can cause significant load on PG on startup if you have lots of event triggers. Delay in starting up is expected.
- console: add notifications (#5070)
- cli: fix bug in metadata apply which made the server aquire some redundant and unnecessary locks (close #6115)
- cli: fix cli-migrations-v2 image failing to run as a non root user (close #4651, close #5333)
Expand All @@ -195,7 +196,6 @@ arguments.
- docs: add postgres concepts page to docs (close #4440) (#4471)
- docs: add guides on connecting hasura cloud to pg databases of different cloud vendors (#5948)


## `v1.3.2`

### Bug fixes and improvements
Expand Down
36 changes: 36 additions & 0 deletions cli-ext/tests/sdl/payload.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,42 @@ const toPayload = {
"ofType": null
},
"description": null
}, {
"name": "_nregex",
"defaultValue": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"description": null
}, {
"name": "_regex",
"defaultValue": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"description": null
}, {
"name": "_niregex",
"defaultValue": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"description": null
}, {
"name": "_iregex",
"defaultValue": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"description": null
}],
"kind": "INPUT_OBJECT",
"possibleTypes": null,
Expand Down
5 changes: 4 additions & 1 deletion community/sample-apps/react-relay/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,10 @@ input String_comparison_exp {
_nlike: String
_nsimilar: String
_similar: String
_niregex: String
_iregex: String
_nregex: String
_regex: String
}

# subscription root
Expand Down Expand Up @@ -654,4 +658,3 @@ input uuid_comparison_exp {
_neq: uuid
_nin: [uuid!]
}

6 changes: 5 additions & 1 deletion console/src/components/Common/FilterQuery/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export type Operator =
| '$ilike'
| '$nilike'
| '$similar'
| '$nsimilar';
| '$nsimilar'
| '$regex'
| '$iregex'
| '$nregex'
| '$niregex';

// Operator with names and aliases
export type OperatorDef = {
Expand Down
16 changes: 16 additions & 0 deletions console/src/components/Common/FilterQuery/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ export const allOperators: OperatorDef[] = [
},
{ name: 'similar', operator: '$similar', alias: '_similar' },
{ name: 'not similar', operator: '$nsimilar', alias: '_nsimilar' },
{ name: '~', operator: '$regex', alias: '_regex' },
{
name: '~*',
operator: '$iregex',
alias: '_iregex',
},
{
name: '!~',
operator: '$nregex',
alias: '_nregex',
},
{
name: '!~*',
operator: '$niregex',
alias: '_niregex',
},
];

export const getOperatorDefaultValue = (op: Operator) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,22 @@ const columnOperatorsInfo = {
type: 'pattern_match',
inputStructure: 'object',
},
_regex: {
type: 'pattern_match',
inputStructure: 'object',
},
_iregex: {
type: 'pattern_match',
inputStructure: 'object',
},
_nregex: {
type: 'pattern_match',
inputStructure: 'object',
},
_niregex: {
type: 'pattern_match',
inputStructure: 'object',
},
_contains: {
type: 'jsonb',
inputStructure: 'object',
Expand Down
21 changes: 21 additions & 0 deletions console/src/components/Services/Data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ export const Operators = [
},
{ name: 'similar', value: '$similar', graphqlOp: '_similar' },
{ name: 'not similar', value: '$nsimilar', graphqlOp: '_nsimilar' },

{
name: '~',
value: '$regex',
graphqlOp: '_regex',
},
{
name: '~*',
value: '$iregex',
graphqlOp: '_iregex',
},
{
name: '!~',
value: '$nregex',
graphqlOp: '_nregex',
},
{
name: '!~*',
value: '$niregex',
graphqlOp: '_niregex',
},
];

export const Integers = [
Expand Down
16 changes: 16 additions & 0 deletions contrib/metadata-types/src/unused/BoolExp.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,22 @@
"type": "string",
"title": "_similar"
},
"_regex": {
"type": "string",
"title": "_regex"
},
"_iregex": {
"type": "string",
"title": "_iregex"
},
"_nregex": {
"type": "string",
"title": "_nregex"
},
"_niregex": {
"type": "string",
"title": "_niregex"
},
"_eq": {
"type": "string",
"title": "_eq"
Expand Down
4 changes: 4 additions & 0 deletions contrib/metadata-types/src/unused/BoolExp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ interface StringOperator extends GenericOperator<string> {
_nlike?: string
_nsimilar?: string
_similar?: string
_regex?: string
_iregex?: string
_nregex?: string
_niregex?: string
}

/** expression to compare columns of type json. All fields are combined with logical 'AND'. */
Expand Down
4 changes: 4 additions & 0 deletions docs/graphql/core/api-reference/graphql-api/mutation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,10 @@ Operator
- ``_nilike``
- ``_similar``
- ``_nsimilar``
- ``_iregex``
- ``_niregex``
- ``_regex``
- ``_nregex``

**Checking for NULL values:**

Expand Down
8 changes: 8 additions & 0 deletions docs/graphql/core/api-reference/graphql-api/query.rst
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,14 @@ Operator
- ``SIMILAR TO``
* - ``_nsimilar``
- ``NOT SIMILAR TO``
* - ``_regex``
- ``~``
* - ``_iregex``
- ``~*``
* - ``_nregex``
- ``!~``
* - ``_niregex``
- ``!~*``

(For more details on text related operators, refer to the `Postgres docs <https://www.postgresql.org/docs/current/functions-matching.html>`__.)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,15 @@ Operator
- ``SIMILAR TO``
* - ``"$nsimilar"``
- ``NOT SIMILAR TO``
* - ``$regex``
- ``~``
* - ``$iregex``
- ``~*``
* - ``$nregex``
- ``!~``
* - ``$niregex``
- ``!~*``


(For more details on text related operators, refer to the `Postgres docs <https://www.postgresql.org/docs/current/functions-matching.html>`__.)

Expand Down
2 changes: 1 addition & 1 deletion docs/graphql/core/queries/query-filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ Fetch a list of those authors whose names are NOT part of a list:
Text search or pattern matching operators (_like, _similar, etc.)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The ``_like``, ``_nlike``, ``_ilike``, ``_nilike``, ``_similar``, ``_nsimilar`` operators are used for
The ``_like``, ``_nlike``, ``_ilike``, ``_nilike``, ``_similar``, ``_nsimilar``, ``_regex``, ``_nregex``, ``_iregex``, ``_niregex`` operators are used for
pattern matching on string/text fields.

For more details on text search operators and Postgres equivalents, refer to the :ref:`API reference <text_operators>`.
Expand Down
14 changes: 11 additions & 3 deletions server/src-lib/Hasura/Backends/Postgres/SQL/DML.hs
Original file line number Diff line number Diff line change
Expand Up @@ -725,15 +725,19 @@ data CompareOp
| SLT
| SIN
| SNE
| SGTE
| SLTE
| SNIN
| SLIKE
| SNLIKE
| SILIKE
| SNILIKE
| SSIMILAR
| SNSIMILAR
| SGTE
| SLTE
| SNIN
| SREGEX
| SIREGEX
| SNREGEX
| SNIREGEX
| SContains
| SContainedIn
| SHasKey
Expand All @@ -760,6 +764,10 @@ instance Show CompareOp where
SNILIKE -> "NOT ILIKE"
SSIMILAR -> "SIMILAR TO"
SNSIMILAR -> "NOT SIMILAR TO"
SREGEX -> "~"
SIREGEX -> "~*"
SNREGEX -> "!~"
SNIREGEX -> "!~*"
SContains -> "@>"
SContainedIn -> "<@"
SHasKey -> "?"
Expand Down
17 changes: 17 additions & 0 deletions server/src-lib/Hasura/Backends/Postgres/Translate/BoolExp.hs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ parseOperationsExpression rhsParser fim columnInfo =
"$nsimilar" -> parseNsimilar
"_nsimilar" -> parseNsimilar

"$regex" -> parseRegex
"_regex" -> parseRegex
"$iregex" -> parseIRegex
"_iregex" -> parseIRegex
"$nregex" -> parseNRegex
"_nregex" -> parseNRegex
"$niregex" -> parseNIRegex
"_niregex" -> parseNIRegex

"$is_null" -> parseIsNull
"_is_null" -> parseIsNull

Expand Down Expand Up @@ -180,6 +189,10 @@ parseOperationsExpression rhsParser fim columnInfo =
parseNilike = guardType stringTypes >> ANILIKE () <$> parseOne
parseSimilar = guardType stringTypes >> ASIMILAR <$> parseOne
parseNsimilar = guardType stringTypes >> ANSIMILAR <$> parseOne
parseRegex = guardType stringTypes >> AREGEX <$> parseOne
parseIRegex = guardType stringTypes >> AIREGEX <$> parseOne
parseNRegex = guardType stringTypes >> ANREGEX <$> parseOne
parseNIRegex = guardType stringTypes >> ANIREGEX <$> parseOne

parseIsNull = bool ANISNOTNULL ANISNULL -- is null
<$> parseVal
Expand Down Expand Up @@ -404,6 +417,10 @@ mkFieldCompExp qual lhsField = mkCompExp (mkQField lhsField)
ANILIKE _ val -> S.BECompare S.SNILIKE lhs val
ASIMILAR val -> S.BECompare S.SSIMILAR lhs val
ANSIMILAR val -> S.BECompare S.SNSIMILAR lhs val
AREGEX val -> S.BECompare S.SREGEX lhs val
AIREGEX val -> S.BECompare S.SIREGEX lhs val
ANREGEX val -> S.BECompare S.SNREGEX lhs val
ANIREGEX val -> S.BECompare S.SNIREGEX lhs val
AContains val -> S.BECompare S.SContains lhs val
AContainedIn val -> S.BECompare S.SContainedIn lhs val
AHasKey val -> S.BECompare S.SHasKey lhs val
Expand Down
12 changes: 12 additions & 0 deletions server/src-lib/Hasura/GraphQL/Schema/BoolExp.hs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ comparisonExps = P.memoize 'comparisonExps \columnType -> do
, P.fieldOptional $$(G.litName "_nsimilar")
(Just "does the column NOT match the given SQL regular expression")
(ANSIMILAR . mkParameter <$> columnParser)
, P.fieldOptional $$(G.litName "_regex")
(Just "does the column match the given POSIX regular expression, case sensitive")
(AREGEX . mkParameter <$> columnParser)
, P.fieldOptional $$(G.litName "_iregex")
(Just "does the column match the given POSIX regular expression, case insensitive")
(AIREGEX . mkParameter <$> columnParser)
, P.fieldOptional $$(G.litName "_nregex")
(Just "does the column NOT match the given POSIX regular expression, case sensitive")
(ANREGEX . mkParameter <$> columnParser)
, P.fieldOptional $$(G.litName "_niregex")
(Just "does the column NOT match the given POSIX regular expression, case insensitive")
(ANIREGEX . mkParameter <$> columnParser)
]
-- Ops for JSONB type
, guard (isScalarColumnWhere (== PGJSONB) columnType) *>
Expand Down
Loading

0 comments on commit 5192d23

Please sign in to comment.