Projet

Général

Profil

0001-opengis-add-text-search-for-queries-40743.patch

Valentin Deniaud, 07 avril 2020 16:40

Télécharger (6,1 ko)

Voir les différences:

Subject: [PATCH] opengis: add text search for queries (#40743)

 .../migrations/0009_auto_20200407_1544.py     | 26 +++++++++++++++++++
 passerelle/apps/opengis/models.py             | 26 ++++++++++++++++---
 tests/test_opengis.py                         | 23 ++++++++++++++++
 3 files changed, 71 insertions(+), 4 deletions(-)
 create mode 100644 passerelle/apps/opengis/migrations/0009_auto_20200407_1544.py
passerelle/apps/opengis/migrations/0009_auto_20200407_1544.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2020-04-07 13:44
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations, models
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    dependencies = [
11
        ('opengis', '0008_featurecache'),
12
    ]
13

  
14
    operations = [
15
        migrations.AddField(
16
            model_name='featurecache',
17
            name='text',
18
            field=models.CharField(default='', max_length=2048),
19
            preserve_default=False,
20
        ),
21
        migrations.AddField(
22
            model_name='query',
23
            name='index_properties',
24
            field=models.CharField(blank=True, help_text='Comma separated list such as property1,property2', max_length=1024, verbose_name='Properties for searching'),
25
        ),
26
    ]
passerelle/apps/opengis/models.py
380 380
                  'bbox': {
381 381
                      'description': _('Only include results inside bounding box'),
382 382
                      'example_value': '-0.489,51.28,0.236,51.686'
383
                  },
384
                  'q': {
385
                      'description': _('Text search for specified properties'),
386
                      'example_value': 'library'
383 387
                  }
384 388
              },
385 389
              show=False)
386
    def query(self, request, query_slug, bbox=None):
390
    def query(self, request, query_slug, bbox=None, q=None):
387 391
        query = get_object_or_404(Query, resource=self, slug=query_slug)
388
        return query.q(request, bbox)
392
        return query.q(request, bbox, q)
389 393

  
390 394
    def export_json(self):
391 395
        d = super(OpenGIS, self).export_json()
......
441 445
        verbose_name=_('XML filter'),
442 446
        max_length=4096,
443 447
        blank=True)
448
    index_properties = models.CharField(
449
        verbose_name=_('Properties for searching'),
450
        help_text=_('Comma separated list such as property1,property2'),
451
        max_length=1024,
452
        blank=True)
444 453

  
445 454
    delete_view = 'opengis-query-delete'
446 455
    edit_view = 'opengis-query-edit'
......
454 463
        endpoint.parameters = copy.deepcopy(resource_endpoint.parameters)
455 464
        return endpoint
456 465

  
457
    def q(self, request, bbox):
466
    def q(self, request, bbox, q):
458 467
        features = self.features.all()
459 468
        if not features.exists():
460 469
            raise APIError('Data is not synchronized yet. Retry in a few minutes.')
......
466 475
                               'floating point numbers of the form lonmin,latmin,lonmax,latmax')
467 476
            features = features.filter(lon__gte=lonmin, lon__lte=lonmax, lat__gte=latmin,
468 477
                                       lat__lte=latmax)
478
        if q:
479
            features = features.filter(text__icontains=q)
469 480
        data = {
470 481
            'type': 'FeatureCollection',
471 482
            'name': self.typename
......
483 494
            except (KeyError, TypeError):
484 495
                self.resource.logger.warning('invalid coordinates in geometry: %s', geometry)
485 496
                continue
486
            features.append(FeatureCache(query=self, lat=lat, lon=lon, data=feature))
497
            text = ''
498
            if self.index_properties:
499
                properties = [x.strip() for x in self.index_properties.split(',') if x.strip()]
500
                values = [val for prop, val in feature.get('properties', {}).items()
501
                          if prop in properties]
502
                text = ' '.join(values)
503
            features.append(FeatureCache(query=self, lat=lat, lon=lon, text=text, data=feature))
487 504
        with transaction.atomic():
488 505
            self.features.all().delete()
489 506
            FeatureCache.objects.bulk_create(features)
......
501 518
        verbose_name=_('Query'))
502 519
    lat = models.FloatField()
503 520
    lon = models.FloatField()
521
    text = models.CharField(max_length=2048)
504 522
    data = JSONField()
tests/test_opengis.py
644 644
    assert '/opengis/test/query/test_query/?bbox=' in resp.text
645 645

  
646 646

  
647
@mock.patch('passerelle.utils.Request.get')
648
def test_opengis_query_text_search(mocked_get, app, connector, query):
649
    endpoint = utils.generic_endpoint_url('opengis', 'query/test_query/', slug=connector.slug)
650
    mocked_get.side_effect = geoserver_geolocated_responses
651
    query.update_cache()
652

  
653
    resp = app.get(endpoint + '?q=grenoble')
654
    assert len(resp.json['features']) == 0
655

  
656
    query.index_properties = 'nom_commune,nom_voie'
657
    query.save()
658
    query.update_cache()
659

  
660
    resp = app.get(endpoint + '?q=grenoble')
661
    assert len(resp.json['features']) == 4
662

  
663
    resp = app.get(endpoint + '?q=victor')
664
    assert len(resp.json['features']) == 2
665

  
666
    resp = app.get(endpoint + '?q=nomatch')
667
    assert len(resp.json['features']) == 0
668

  
669

  
647 670
def test_opengis_export_import(query):
648 671
    assert OpenGIS.objects.count() == 1
649 672
    assert Query.objects.count() == 1
650
-