Merge pull request #139 from eReuse/bugfix/#138-search-device-for-devicehubId
Bugfix/#138 search device for devicehub
This commit is contained in:
commit
9c2b8b6eb3
|
@ -16,6 +16,7 @@ ml).
|
||||||
- [addend] #122 system for verify all documents that it's produced from devicehub
|
- [addend] #122 system for verify all documents that it's produced from devicehub
|
||||||
- [addend] #127 add one code for every named tag
|
- [addend] #127 add one code for every named tag
|
||||||
- [addend] #131 add one code for every device
|
- [addend] #131 add one code for every device
|
||||||
|
- [bugfix] #138 search device with devicehubId
|
||||||
|
|
||||||
## [1.0.4-beta]
|
## [1.0.4-beta]
|
||||||
- [addend] #95 adding endpoint for check the hash of one report
|
- [addend] #95 adding endpoint for check the hash of one report
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
"""add code device search
|
||||||
|
|
||||||
|
Revision ID: 8d34480c82c4
|
||||||
|
Revises: 8cb91ad1cc40
|
||||||
|
Create Date: 2021-04-26 12:00:36.635784
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
from alembic import context
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
from ereuse_devicehub.resources.device.search import DeviceSearch
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '8d34480c82c4'
|
||||||
|
down_revision = '8cb91ad1cc40'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_inv():
|
||||||
|
INV = context.get_x_argument(as_dictionary=True).get('inventory')
|
||||||
|
if not INV:
|
||||||
|
raise ValueError("Inventory value is not specified")
|
||||||
|
return INV
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('device_search',
|
||||||
|
sa.Column('devicehub_ids',
|
||||||
|
postgresql.TSVECTOR(),
|
||||||
|
nullable=True),
|
||||||
|
schema=f'{get_inv()}')
|
||||||
|
|
||||||
|
op.create_index('devicehub_ids gist',
|
||||||
|
'device_search',
|
||||||
|
['devicehub_ids'],
|
||||||
|
unique=False,
|
||||||
|
postgresql_using='gist',
|
||||||
|
schema=f'{get_inv()}')
|
||||||
|
|
||||||
|
# Next of the migration execute: dh inv search
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_index('devicehub_ids gist',
|
||||||
|
table_name='device_search',
|
||||||
|
schema=f'{get_inv()}')
|
||||||
|
op.drop_column('device_search', 'devicehub_ids', schema=f'{get_inv()}')
|
|
@ -26,12 +26,14 @@ class DeviceSearch(db.Model):
|
||||||
|
|
||||||
properties = db.Column(TSVECTOR, nullable=False)
|
properties = db.Column(TSVECTOR, nullable=False)
|
||||||
tags = db.Column(TSVECTOR)
|
tags = db.Column(TSVECTOR)
|
||||||
|
devicehub_ids = db.Column(TSVECTOR)
|
||||||
|
|
||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
# todo to add concurrency this should be commited separately
|
# todo to add concurrency this should be commited separately
|
||||||
# see https://docs.sqlalchemy.org/en/latest/dialects/postgresql.html#indexes-with-concurrently
|
# see https://docs.sqlalchemy.org/en/latest/dialects/postgresql.html#indexes-with-concurrently
|
||||||
db.Index('properties gist', properties, postgresql_using='gist'),
|
db.Index('properties gist', properties, postgresql_using='gist'),
|
||||||
db.Index('tags gist', tags, postgresql_using='gist'),
|
db.Index('tags gist', tags, postgresql_using='gist'),
|
||||||
|
db.Index('devicehub_ids gist', devicehub_ids, postgresql_using='gist'),
|
||||||
{
|
{
|
||||||
'prefixes': ['UNLOGGED']
|
'prefixes': ['UNLOGGED']
|
||||||
# Only for temporal tables, can cause table to empty on turn on
|
# Only for temporal tables, can cause table to empty on turn on
|
||||||
|
@ -140,10 +142,16 @@ class DeviceSearch(db.Model):
|
||||||
)
|
)
|
||||||
).filter(Tag.device_id == device.id).join(Tag.org)
|
).filter(Tag.device_id == device.id).join(Tag.org)
|
||||||
|
|
||||||
|
devicehub_ids = session.query(
|
||||||
|
search.Search.vectorize(
|
||||||
|
(db.func.string_agg(Device.devicehub_id, ' '), search.Weight.A),
|
||||||
|
)
|
||||||
|
).filter(Device.devicehub_id == device.devicehub_id)
|
||||||
|
|
||||||
# Note that commit flushes later
|
# Note that commit flushes later
|
||||||
# todo see how to get rid of the one_or_none() by embedding those as subqueries
|
# todo see how to get rid of the one_or_none() by embedding those as subqueries
|
||||||
# I don't like this but I want the 'on_conflict_on_update' thingie
|
# I don't like this but I want the 'on_conflict_on_update' thingie
|
||||||
device_document = dict(properties=properties.one_or_none(), tags=tags.one_or_none())
|
device_document = dict(properties=properties.one_or_none(), tags=tags.one_or_none(), devicehub_ids=devicehub_ids.one_or_none())
|
||||||
insert = postgresql.insert(DeviceSearch.__table__) \
|
insert = postgresql.insert(DeviceSearch.__table__) \
|
||||||
.values(device_id=device.id, **device_document) \
|
.values(device_id=device.id, **device_document) \
|
||||||
.on_conflict_do_update(constraint='device_search_pkey', set_=device_document)
|
.on_conflict_do_update(constraint='device_search_pkey', set_=device_document)
|
||||||
|
|
|
@ -54,6 +54,7 @@ class LotQ(query.Query):
|
||||||
|
|
||||||
class Filters(query.Query):
|
class Filters(query.Query):
|
||||||
id = query.Or(query.Equal(Device.id, fields.Integer()))
|
id = query.Or(query.Equal(Device.id, fields.Integer()))
|
||||||
|
devicehub_id = query.Or(query.ILike(Device.devicehub_id))
|
||||||
type = query.Or(OfType(Device.type))
|
type = query.Or(OfType(Device.type))
|
||||||
model = query.ILike(Device.model)
|
model = query.ILike(Device.model)
|
||||||
manufacturer = query.ILike(Device.manufacturer)
|
manufacturer = query.ILike(Device.manufacturer)
|
||||||
|
@ -154,10 +155,15 @@ class DeviceView(View):
|
||||||
if search_p:
|
if search_p:
|
||||||
properties = DeviceSearch.properties
|
properties = DeviceSearch.properties
|
||||||
tags = DeviceSearch.tags
|
tags = DeviceSearch.tags
|
||||||
|
devicehub_ids = DeviceSearch.devicehub_ids
|
||||||
query = query.join(DeviceSearch).filter(
|
query = query.join(DeviceSearch).filter(
|
||||||
search.Search.match(properties, search_p) | search.Search.match(tags, search_p)
|
search.Search.match(properties, search_p) |
|
||||||
|
search.Search.match(tags, search_p) |
|
||||||
|
search.Search.match(devicehub_ids, search_p)
|
||||||
).order_by(
|
).order_by(
|
||||||
search.Search.rank(properties, search_p) + search.Search.rank(tags, search_p)
|
search.Search.rank(properties, search_p) +
|
||||||
|
search.Search.rank(tags, search_p) +
|
||||||
|
search.Search.rank(devicehub_ids, search_p)
|
||||||
)
|
)
|
||||||
return query.filter(*args['filter']).order_by(*args['sort'])
|
return query.filter(*args['filter']).order_by(*args['sort'])
|
||||||
|
|
||||||
|
|
|
@ -248,6 +248,8 @@ def test_device_query_search(user: UserClient):
|
||||||
assert i['items'][0]['id'] == 1
|
assert i['items'][0]['id'] == 1
|
||||||
i, _ = user.get(res=Device, query=[('search', 'intel')])
|
i, _ = user.get(res=Device, query=[('search', 'intel')])
|
||||||
assert len(i['items']) == 1
|
assert len(i['items']) == 1
|
||||||
|
i, _ = user.get(res=Device, query=[('search', i['items'][0]['devicehubID'])])
|
||||||
|
assert len(i['items']) == 1
|
||||||
i, _ = user.get(res=Device, query=[('search', '1')])
|
i, _ = user.get(res=Device, query=[('search', '1')])
|
||||||
assert len(i['items']) == 1
|
assert len(i['items']) == 1
|
||||||
|
|
||||||
|
|
Reference in New Issue