diff --git a/README.md b/README.md index 788ed715..972eac4c 100644 --- a/README.md +++ b/README.md @@ -550,6 +550,7 @@ CustomerRepository.find({ PostgreSQL supports the following PostgreSQL-specific operators: - [`contains`](#operator-contains) +- [`match`](#operator-match) Please note extended operators are disabled by default, you must enable them at datasource level or model level by setting `allowExtendedOperators` to @@ -596,6 +597,36 @@ const posts = await postRepository.find({ }); ``` +### Operator `match` + +The `match` operator allows you to perform a [full text search using the `@@` operator](https://www.postgresql.org/docs/10/textsearch-tables.html#TEXTSEARCH-TABLES-SEARCH) in PostgreSQL. + +Assuming a model such as this: +```ts +@model({ + settings: { + allowExtendedOperators: true, + } +}) +class Post { + @property({ + type: 'string', + }) + content: string; +} +``` +You can query the content field as follows: + +```ts +const posts = await postRepository.find({ + where: { + { + content: {match: 'someString'}, + } + } +}); +``` + ## Discovery and auto-migration ### Model discovery diff --git a/lib/postgresql.js b/lib/postgresql.js index 2ac994f2..398e5168 100644 --- a/lib/postgresql.js +++ b/lib/postgresql.js @@ -537,6 +537,8 @@ PostgreSQL.prototype.buildExpression = function(columnName, operator, case 'contains': return new ParameterizedSQL(columnName + ' @> array[' + operatorValue.map((v) => `'${v}'`) + ']::' + propertyDefinition.postgresql.dataType); + case 'match': + return new ParameterizedSQL(`to_tsvector(${columnName}) @@ to_tsquery('${operatorValue}')`); default: // invoke the base implementation of `buildExpression` return this.invokeSuper('buildExpression', columnName, operator, diff --git a/test/postgresql.test.js b/test/postgresql.test.js index 2d1fadd3..67e73b28 100644 --- a/test/postgresql.test.js +++ b/test/postgresql.test.js @@ -281,6 +281,24 @@ describe('postgresql connector', function() { found.map(p => p.title).should.deepEqual(['Growing LoopBack Community']); }); + it('should support full text search for text type fields using simple string query', async () => { + await Post.create({ + title: 'Loopback joined the OpenJS Foundation', + categories: ['Loopback', 'Announcements'], + }); + await Post.create({ + title: 'Loopback is a new incubating project in the OpenJS foundation', + categories: ['Loopback', 'Community'], + }); + + const found = await Post.find({where: {and: [ + { + title: {match: 'joining'}, + }, + ]}}); + found.map(p => p.title).should.deepEqual(['Loopback joined the OpenJS Foundation']); + }); + it('should support boolean types with false value', function(done) { Post.create( {title: 'T2', content: 'C2', approved: false, created: created},