rbw / aiosnow

Asynchronous ServiceNow Library
MIT License
73 stars 12 forks source link

Document nested fields usage #93

Closed netixx closed 3 years ago

netixx commented 3 years ago

Hello,

I am trying to retrieve values from a table which contains values that refer to other tables (e.g. alm_hardware table has a company field which refers to the core_company table)

By naively using String() field, I get a sys_id value, which means I need to dump the corresponding table to get the corresponding value:

class Company(aiosnow.TableModel):
    sys_id = aiosnow.fields.String(is_primary=True)
    name = aiosnow.fields.String()

class Hardware(aiosnow.TableModel):
    sys_id = aiosnow.fields.String(is_primary=True)
    asset_tag = aiosnow.fields.String()
    company = aiosnow.fields.String()

My guess is that I should use nested fields, but I cannot figure out how to do this with aiosnow. Also, we could use the displayvalue=True instead of the displayvalue=all in the query, but I didn't find any way to do this either.

Could you document/explain ?

rbw commented 3 years ago

I realize this isn't included in the recently reworked documentation, so thanks for reporting :)

Anyway..

If you're only interested in sys_id and name of core_company, simply use a fields.StringMap; it validates and maps those fields to key and value respectively. Example access of IncidentModel.priority.value in a response: https://github.com/rbw/aiosnow/blob/99e057da9d6f2677a92805b41ac436d05355b9c8/examples/table/create.py#L15

This would return something like str("5 - Planning"), while IncidentModel.priority.key in this case would return the nested item's identifier of int(5).

If you want aiosnow to fully resolve the related core_company object, you'll need to use a nested schema, which will enable querying by fields of that schema and automatically fetch referenced objects on request, with caching support.

Here's an example of nested schema use: https://github.com/rbw/aiosnow/blob/master/examples/table/read/nested.py

Also, we could use the displayvalue=True instead of the displayvalue=all in the query, but I didn't find any way to do this either.

aiosnow controls the displayvalue parameter; it's configured as needed based on what's in the model declaration.

netixx commented 3 years ago

Thank you for your help! My goal by opening this issue was also to help future newcomers that may want to do the same results.

To summarised, this gives us 4 solutions:

# case 1: return the sys-id of the company
class Hardware(aiosnow.TableModel):
    sys_id = aiosnow.fields.String(is_primary=True)
    company = aiosnow.fields.String()

# case 2: return the display name
from aiosnow.models.common.schema.helpers import Pluck
class Hardware(aiosnow.TableModel):
    sys_id = aiosnow.fields.String(is_primary=True)
    company = aiosnow.fields.String(pluck=Pluck.DISPLAY_VALUE)

# case 3: return the sys_id, display_name as key, value
class Hardware(aiosnow.TableModel):
    sys_id = aiosnow.fields.String(is_primary=True)
    company = aiosnow.fields.StringMap()

# case 4: do a nested table => get any fields from the company table
from aiosnow.models.common.schema import ModelSchema
class Company(ModelSchema):
    name = aiosnow.fields.String()

class Hardware(aiosnow.TableModel):
    sys_id = aiosnow.fields.String(is_primary=True)
    company = Company

Now that I get how it works, I tried to do filtering on those fields, e.g:

async with Hardware(servicenow_client, table_name="alm_hardware") as hardware:
        hardware_items = await hardware.get(Hardware.company.in_list(['ACME UK', 'ACME US']))

However I couldn't get it to work using company names (using case 2). Does only sys-id works for filtering in this case ?

rbw commented 3 years ago

Sorry for the late response.

Yep, you covered all possible solutions to this problem. I'll try to include this in some form in the docs, thanks.

It should be Hardware.company.name.in_list(['ACME UK', 'ACME US'])), note the missing name in your example.

netixx commented 3 years ago

Thank you for all the detailed answers.