The Parts Database Query API¶
JITX comes with an optional high-level framework to manage queries to the parts database in a JITX design. To use this framework, add
import jitx/parts
jitx
, so it is not sufficient to have import jitx
.
This article mainly documents the jitx/parts/query-api
package, which is forwarded by jitx/parts
.
Overview: query objects and query functions¶
The Query API defines various types of query objects such as BaseQuery , ResistorQuery
, CapacitorQuery
, and so on. These serve as re-usable containers of query parameters (key-value pairs) that can used in various query functions such as create-resistor
, insert-resistor
, search-capacitors
, etc. For example, you can write:
val my-query = ResistorQuery(resistance = 1000.,
mounting = "smd",
min-stock = 100)
pcb-module my-module :
inst r : create-resistor(my-query)
...
create-resistor
returns a component definition, not an instance¶
create-resistor
and other create-[cat]
query functions return component definitions, which are objects of type Instantiable
, not instances. In other words,
val my-resistor = create-resistor(my-query)
pcb-component my-resistor :
...
- Query objects can be reused to create multiple components.
- Components can be reused to create multiple instances.
The latter is an intrinsic capability of JITX so we will focus mainly on the former in this article. Note that a usage like inst r : create-resistor(my-query)
skips the second layer of abstraction and uses a query object to create a single instance, throwing away the intervening component definition.
Query objects are immutable¶
The add and update operations can be used to create new query objects. The old object remains unchanged. For example:
val my-query = ResistorQuery(resistance = 1000.,
mounting = "smd",
min-stock = 100)
val other-query = add(my-query, rated-power = AtLeast(0.1))
inst r1 : create-resistor(my-query)
inst r2 : create-resistor(other-query)
r1
and r2
will have resistance (within some tolerance) of 1kΩ and be SMD-mounted. The second one will have a rated power of at least 0.1W but the first one may or may not.
Extended example¶
This example offers a tour through various features of the API. All the features used will be explained in detail in later sections.
; These params will be used in all queries without needing to pass a
; query object arg.
set-global-query-defaults!(min-stock = 1, quantity-needed = 10)
; A basic query object to build off of. Note the usage a special
; value marker, FindMinimum. Instead of setting the parameter it is
; given with, it sets the ‘sort!’ parameter (aka ‘_sort’ in low-level
; query interface). This is meant to replace the OPTIMIZE-FOR
; functionality from OCDB.
val general-query = BaseQuery(price = FindMinimum
sellers! = [JLCPCB LCSC DigiKey Future
Mouser Arrow Avnet Newark])
; A more specialized, but still basic query object to build off of.
; This includes all parameters from the previous one.
val smd-query = add(general-query, mounting = "smd"
case = valid-smd-pkgs("0402"))
pcb-module main :
; Create a ResistorQuery, which allows us to set keys specific to
; resistor category.
val q1 = ResistorQuery(smd-query, resistance = 8000. +/- 500.
rated-power = AtLeast(0.1)
precision = (5 %)
)
; Variant with different resistance.
val q2 = update(q1, resistance = 1.0e3 +/- 500.0)
; If the query already has everything, component creation can be
; very terse.
inst r1 : create-resistor(q1)
; We can also override any key we want at the last minute.
inst r2 : create-resistor(q2, resistance = 12000.)
; Here we create a resistor directly from a base query and some
; explicit resistor keys.
inst r3 : create-resistor(smd-query, resistance = 100.,
rated-power = 0.25)
; Caution: here we do not use a query object, so the only keys
; respected are the global defaults and the ones explicitly given.
; This may well return a through-hole resistor from a seller not on
; our list.
inst r4 : create-resistor(resistance = 100.)
net (r1.p[2] r2.p[1])
net (r2.p[2] r3.p[1])
net (r3.p[2] r4.p[1])
val cap-query = CapacitorQuery(smd-query, type = "electrolytic")
insert-capacitor(r1.p[1], r4.p[2], cap-query, capacitance = 1.e-6)
; Here we show use of the special value marker FindDistinct, which
; maps to ‘_distinct’ in the low-level dbquery interface. This will
; give us all the possible values of rated-power for 1000Ω resistors
; with our basic smd-query parameters.
println("searching for possible values of rated-power...")
println(search-resistors(smd-query, rated-power = FindDistinct,
resistance = 1000.))
; prints output:
; [0.0625 0.063 0.1 0.125 0.25 0.2 0.5 0.333333 0.75 0.333 0.6]
; We can also just do a raw search. This will return the JSON from
; the lower-level dbquery call directly. In this case the ‘limit’
; keyword is helpful.
println("Searching for 1MΩ resistors...")
println(search-resistors(smd-query, resistance = 1.e6, limit = 1))
; prints output:
; a boatload of json which I will not copy here
Basic structure of the Query API¶
Most of the functions defined by the API are subdivided into families based on the category of component they operate on. The current component categories are:
- resistor
- capacitor
- inductor
- part - a catch-all category for all other parts
- wild - a special category which allows overriding the usual category rules
Terminological note: when referring to the function families generically, [Cat]
stands in for the capitalized category name like Resistor
while [cat]
stands for the uncapitalized category name like resistor
. So we have ResistorQuery
and create-resistor
or PartQuery and create-part
.
The standard functions defined for each category are:
create-[cat]
- run the query against the database and use the results to define a componentinsert-[cat]
- convenience wrapper forcreate-[cat]
which also makes an instance and nets it to two given pinssearch-[cat]s
- run the query against the database and return raw results
The query object types are:
- BaseQuery - a general type of query object that can be used anywhere but cannot hold category-specific keys
- [Cat]Query
- a type of query object specialized for a category which can hold general keys or keys specific to the category
Each query object type has a constructor of the same name which accepts optional keyword arguments for all the kinds of keys that the query object can hold. For [Cat]Query
, this is the same set of keys that are available to the query functions of that category. (There are no query functions associated to BaseQuery
.)
Future version of JITX may add more categories as well as more query function in each category.
Besides these families, we have a few other standard functions:
- BaseQuery - construct a query object which can be used as a base for any other query objects
to-component
- convert a raw search result, e.g. fromsearch-[cat]s
, into a component definition
In addition, certain special keys have helper functions specific to those keys; these will be documented alongside the special keys.
Query functions¶
All query functions accept a query builder as a (usually optional) positional argument, and additionally accept keyword arguments for all the keys legal for the given category. That generally means all base keys as well as any keys specific to that category.
Passing keys directly to the query function is equivalent to creating a new query object first using add or update on the same keys, except that it is less picky: if the query already has the key it will be updated and otherwise it will be added.
create-[cat]¶
Actual functions defined: create-resistor
create-capacitor
create-inductor
create-part
create-wild
create-[cat]
takes
- one optional positional argument
qo: [Cat]Query|BaseQuery|WildQuery
- any number of optional standard keyword arguments for all query keys legal for category [Cat]
- optional keyword argument:
comp-name: String
and returns an object of type Instantiable
.
create-[cat]
first constructs internally a final query object. This proceeds in two steps:
1. The given query object qo
is converted to an [Cat]Query
if it wasn't one already. If this argument is absent, a new one is created by [Cat]Query()
. Note that in this case, the key-values from set-global-query-defaults! will be used.
2. All standard keyword arguments are used to extend the query object as if using whatever combination of add and update is necessary to effect all the given values.
create-[cat]
then runs this query against the database, extracts the top result while ignoring all others, internally uses to-component
to define an instantiable satisfying all of the query parameters, and returns this instantiable.
If comp-name
was specified, the component will use this name as if by the name =
syntax in pcb-component
.
insert-[cat]¶
Actual functions defined: insert-resistor
insert-capacitor
insert-inductor
insert-part
insert-wild
insert-[cat]
takes
- mandatory positional argument
pin-a: JITXObject
- mandatory positional argument
pin-b: JITXObject
- optional positional argument
qo: [Cat]Query|BaseQuery|WildQuery
- any number of optional standard keyword arguments for all query keys legal for category [Cat]
- additional optional keyword arguments:
short-trace?: TwoPinShortTrace
comp-name: String
inst-name: String
and returns an object of type Instance
.
Note that pin-a
and pin-b
must be SinglePin
instances, not Bundle
or PortArray
.
insert-[cat]
first creates a component definition as if bycreate-[cat]
, usingqo
, the standard keyword args, andcomp-name
in exactly the same way.insert-[cat]
then instantiates this component, respectinginst-name
if supplied. Note that this name (whether user-specified or not) is not guaranteed to be unique within a pcb-module instance.insert-[cat]
identifies two pins of the instance to use by using theget-element-ports
function:- If pins named
a
andc
are found, they are used in that order. - If pins named
p[1]
andp[2]
are found, they are used in that order. - Otherwise an error is thrown.
- If pins named
insert-[cat]
nets the first pin topin-a
and the second pin topin-b
- if
short-trace?
was specified, one or both of these nets will additionally have the short-trace statement applied to it.TwoPinShortTrace
is an enum with these possible values:- ShortTraceBoth - both
- ShortTraceAnode - first pin only (regardless of name)
- ShortTraceCathode - second pin only (regardless of name)
- ShortTraceNeither - no
short-trace
is applied, same as default behavior
insert-[cat]
returns the instance.
Unlike with other query functions, after insert-[cat]
is called the queried part is already completely defined and instantiated in the module. The returned object can be referred to and introspected on if needed but you do not need to add your own inst
statement. If you add net
statements to make more connections to the returned objects' pins, the short-trace
behavior does not propagate automatically - manual short-trace
statements would need to be added.
search-[cat]s¶
Actual functions defined: search-resistors
search-capacitors
search-inductors
search-parts
search-wilds
search-[cat]s
takes
- one optional positional argument
qo: [Cat]Query|BaseQuery|WildQuery
- any number of optional standard keyword arguments for all query keys legal for category [Cat]
and returns an object of type
Instantiable
. - optional keyword argument:
limit:Int
with default value of1000
and returns an object of type Tuple<JSON>
.
search-[cat]s
constructs a final query object and runs the query against the database in exactly the same way as create-[cat]
. However it does not create any components, but instead just returns the raw results, up to the specified limit. The limit may not be greater than 1000.
The return value has two different possible meanings
- If the
distinct!
key was specified by any method, the return value is a tuple of values whose type depends the requested distinct key. For example, forresistance
it would beTuple<Double>
representing all the possible resistances in ohms. (Note thatDouble <: JSON
.) - Otherwise, the return value is a tuple of raw JSON objects representing all the information needed to construct component definitions. These can be converted to
Component
objects of the appropriate type (such asResistor
) usingto-component
, which in turn can be converted to component definitions usingto-jitx
. See documentation for thecomponent-types
package .
exceptions¶
If a part search fails to find a part, a NoComponentMeetingRequirements
error will be raised. This is a subtype of Exception
and can be caught. For errors related to the API itself, a runtime error is thrown which normally should not be caught.
Query objects¶
A query object is a record of key-value pairs. Different types of query objects accept different categories of keys, to enforce type discipline. There is a query object type, [Cat]Query
, for each part category [Cat], and there is also BaseQuery which is another distinct type of query object.
Although query objects are the main method of reusing key-value pairs between queries, there is another method which is to use the function set-global-query-defaults! at the beginning of the design, which bypasses the need to pass query objects into functions but can only be used once per design.
If reuse is not needed, key-value pairs can also be passed directly to query functions.
When working with query objects, there are three main ways to modify them:
- the add function
- the update function
- passing the query object to the constructor of another query type
- this behaves similarly to add except it also allows changing the type of query.
As mentioned in the overview, “modifying” a query object means to create a new query object using the first one as a template. The original query object still exists; individual query objects are immutable.
Base queries¶
A BaseQuery
cannot be used directly to call any of the query functions, but you can reuse its keys by passing it as the first non-keyword argument to [Cat]Query
:
val my-resistor-query = ResistorQuery(my-base-query, resistance = 1000., ...)
Queries can be persistently modified (not mutated) using the add and update functions which are defined for all of the query types. This means the result is a new query, and the original one is left unchanged:
val my-modified-query = update(my-resistor-query, resistance = 500.)
val yet-another-query = add(my-modified-query, rated-power = 12.0)
[Cat]Query
constructor does not modify the base query - besides making a new type of Query it has semantics similar to add .
[Cat]Query¶
Actual functions defined: ResistorQuery
CapacitorQuery
InductorQuery
PartQuery
WildQuery
[Cat]Query, the function, constructs a query object of type [Cat]Query
. [Cat]Query takes
- one optional positional argument of type
[Cat]Query|BaseQuery|WildQuery
- optional standard keyword arguments for all query keys legal for category [Cat]
and returns
If no positional argument was given, then [Cat]Query simply constructs a query object with the given key-values. If a positional argument was given, an existing query object, then [Cat]Query first converts it to type [Cat]Query if necessary and then adds all the given keys as if by add (so it is an error if the key already had a value).
add
¶
add
takes
- one mandatory positional argument, a query object of any type
- optional standard keyword arguments for all query keys legal for the type
and returns a new query object of the same type. The new object has the key-value pairs of the original and the key-value pairs specified as keyword arguments additionally, provided that none of those keys had values in the original object. If any of the keys already had values, add throws an error.
update
¶
update takes
- one mandatory positional argument, a query object of any type
- optional standard keyword arguments for all query keys legal for the type
and returns a new query object of the same type. The new object has the key-value pairs of the original except that each keyword argument updates the corresponding key to a new value. If any of the keys specified as keyword arguments were not already present, then update throws an error. (It is opposite to add in this regard.)
set-global-query-defaults!
¶
set-global-query-defaults!
takes
- optional standard keyword arguments for all query keys for any category
and has no meaningful return value.
set-global-query-defaults!
may only be run once per design; if it has already been run then it throws a runtime error.
Each of the given key-values will then apply to every query function for which that key is not otherwise given. So for example if min-stock
is set in the global defaults, then it will apply to every query by default, but if the query builder has a different min-stock
in it, or the query function itself has min-stock
specified by keyword, then that value will take precedence.
The function set-global-query-defaults!
accepts all keywords for all categories, and the values given will be used in any query for which no value was given for that key. This differs from the use of query objects because there is no object that has to be passed around. It is globally scoped so third-party libraries which call any of the query functions will also be affected.
The practical differences of setting key-values in the global defaults versus using query objects include:
- They can take effect without specifying any additional argument to the query function (even a query builder).
- They can take effect in query functions called in third-party libraries where you have no direct control over the parameters used. (But only if the library doesn't explicitly set the key.)
- They do not interact with add/update semantics. Any mention of the key in add or update calls will quietly override the global default.
Specifying intervals for keys with numerical values¶
Almost all numeric parameters accept an Interval argument so that a range of acceptable values can be expressed. This is a supertype of Toleranced so any Toleranced value can be used, but you can also use AtLeast or AtMost to conveniently specify a bound on only one side.
Clarification: difference between base, part, and wild¶
These are three different kinds of query objects that all have generic sounding names.
- A BaseQuery can only have general keys that are accepted by all categories. So they cannot have any specialized keys at all. They do not correspond to a category. There is no “base” version of
create-[cat]
for example. - A PartQuery can have general keys as well as specialized keys that don't belong to any standard category. For example currently you need to use this kind of query to access the specialized keys for MCUs, though that may be broken out into its own category in the future. This corresponds to the
Part
category with its own query functions:create-part
,insert-part
,search-parts
. These all have the usual category discipline: you cannot add specialized keys for resistors, for example. - A WildQuery can have any keys whatsoever. It should only be used when there is a specific need to override the usual category discipline. When a query function is called using a wild query, the parameters which are inapplicable (e.g. resistance for a capacitor) are quietly filtered out and have no effect.
Wild
is also a category with its own query functionscreate-wild
,insert-wild
,search-wild
. The reason to use these would be if you wanted to create parts programmatically when the part category is only known at runtime. Then you may also need to ensure that thecategory
field is appropriately set or the low-leveldbquery
will complain. (Normally thecategory
field is automatically set by the query function to its own category.)
There are some common ways that both base and wild queries can be used. For example any query function can accept a base or wild query instead of a query of the specific category. In the latter case, inapplicable keys are filtered out as just mentioned.
The global default keys are yet another way of setting parameters distinct from all of these. They behave somewhat similar to a WildQuery in that there are no restrictions on which keys are allowed, and inapplicable ones for a given query function call will be quietly ignored.
Table of Query Keys¶
This table lists all the standard keys that can be used with the Query API. Meanings of columns:
- category - indicates which of the categories can use this key. If the entry is italicized such as general or passive then it is not a true category (i.e. there is no
[Cat]Query
,create-[cat]
) but is a meta-category for keys which can be used in several different standard categories, as detailed in the following table. - keyword - the name of the Stanza keyword argument used to give a value for this key in any of the query functions which accept it.
- type - the Stanza type of the value expected for this key. If this entry is blank, it means the current implementation does not type-check this value at the API level, but it will still be checked for validity by
dbquery
. In most cases these accept string values. dbquery
key name - the name of the correspondingdbquery
key. If this is not present then thedbquery
key is the same as the API key, except that it should be quoted as a string. For example the dbquery key fortrust
is"trust"
. Caution: most but not all of the dbquery key names are determined programatically from the API key by replacing underscores with periods.
category | keyword | type | dbquery key name |
---|---|---|---|
general | trust |
String |
|
general | category |
String |
|
general | mpn |
String |
|
general | mounting |
String |
|
general | manufacturer |
String |
|
general | description |
String |
|
general | case |
String|Tuple<String> |
|
general | min-stock |
Int |
|
general | price |
Double|Interval |
|
general | x |
Double|Interval |
|
general | y |
Double|Interval |
|
general | z |
Double|Interval |
|
general | area |
Double|Interval |
|
general | rated-temperature_min |
Double|Interval |
"rated-temperature.min" |
general | rated-temperature_max |
Double|Interval |
"rated-temperature.max" |
general | operating-temperature |
Interval |
|
passive | type |
String |
|
passive | tolerance |
Double |
|
passive | precision |
Percentage |
|
passive | tolerance_min |
Double|Interval |
"tolerance.min" |
passive | tolerance_max |
Double|Interval |
"tolerance.max" |
passive | component_datasheet |
"component.datasheet" |
|
passive | metadata_image |
"metadata.image" |
|
passive | metadata_digi-key-part-number |
String |
"metadata.digi-key-part-number" |
passive | metadata_description |
String |
"metadata.description" |
passive | metadata_packaging |
"metadata.packaging" |
|
resistor | resistance |
Double|Interval |
|
resistor | rated-power |
Double|Interval |
|
resistor | composition |
String |
|
resistor | tcr_pos |
Double|Interval |
"tcr.pos" |
resistor | tcr_neg |
Double|Interval |
"tcr.neg" |
resistor | metadata_series |
String |
"metadata.series" |
resistor | metadata_features |
"metadata.features" |
|
resistor | metadata_supplier-device-package |
String |
"metadata.supplier-device-package" |
resistor | metadata_number-of-terminations |
Int |
"metadata.number-of-terminations" |
capacitor | capacitance |
Double|Interval |
|
capacitor | anode |
String |
|
capacitor | electrolyte |
String |
|
capacitor | esr |
Double|Interval |
|
capacitor | esr-frequency |
Double|Interval |
"esr_frequency" |
capacitor | rated-voltage |
Double|Interval |
|
capacitor | rated-voltage-ac |
Double|Interval |
|
capacitor | rated-current-pk |
Double|Interval |
|
capacitor | rated-current-rms |
Double|Interval |
|
capacitor | temperature-coefficient_code |
"temperature-coefficient.code" |
|
capacitor | temperature-coefficient_raw-data |
"temperature-coefficient.raw_data" |
|
capacitor | temperature-coefficient_tolerance |
"temperature-coefficient.tolerance" |
|
capacitor | temperature-coefficient_lower-temperature |
"temperature-coefficient.lower-temperature" |
|
capacitor | temperature-coefficient_upper-temperature |
"temperature-coefficient.upper-temperature" |
|
capacitor | temperature-coefficient_change |
"temperature-coefficient.change" |
|
capacitor | metadata_lifetime-temp |
Double|Interval |
"metadata.lifetime-temp" |
capacitor | metadata_applications |
"metadata.applications" |
|
capacitor | metadata_ripple-current-low-frequency |
Double|Interval |
"metadata.ripple-current-low-frequency" |
capacitor | metadata_ripple-current-high-frequency |
Double|Interval |
"metadata.ripple-current-high-frequency" |
capacitor | metadata_lead-spacing |
Double|Interval |
"metadata.lead-spacing" |
inductor | inductance |
Double|Interval |
|
inductor | material-core |
String |
|
inductor | shielding |
String |
|
inductor | current-rating |
Double|Interval |
|
inductor | saturation-current |
Double|Interval |
|
inductor | dc-resistance |
Double|Interval |
|
inductor | quality-factor |
Double|Interval |
|
inductor | quality-factor-frequency |
Double|Interval |
|
inductor | self-resonsant-frequency |
Double|Interval |
|
mcu | core |
||
mcu | core-architecture |
||
mcu | data-width |
||
mcu | flash |
||
mcu | frequency |
Double|Interval |
|
mcu | io |
||
mcu | line |
||
mcu | mfg-package |
||
mcu | eeprom |
||
mcu | rated-esd |
||
mcu | series |
||
mcu | supply-voltage_min |
Double|Interval |
"supply-voltage.min" |
mcu | supply-voltage_max |
Double|Interval |
"supply-voltage.max" |
special | stock! |
Int |
"_stock" |
special | sellers! |
Tuple<String|AuthorizedVendor> |
"_sellers" |
general | quantity-needed |
Int |
"max-minimum_quantity" |
special | ignore-stock |
True|False |
none |
special | sort! |
SortKey|Tuple<SortKey> |
"_sort" |
special | exist! |
ExistKeys |
"_exist" |
special | distinct! |
DistinctKey |
"_distinct" |
The metacategories refer to the following sets of actual categories:
metacategory | categories |
---|---|
general | usable anywhere including base queries |
passive | resistor, capacitor, inductor |
mcu | part |
special | special rules apply in each case |
For the mcu keys, a future version of JITX will likely put these in a separate actual category of their own.
Most of the special keys can go anywhere, including base queries, but have special restrictions on how they're used or other special semantics to be cautious of. See the advanced usage section for details.
Keys with special considerations¶
- The
category
key is normally set automatically by the query-builder constructor for the category. You only need to set it by hand if you are a query function of thewild
category, such ascreate-wild
, in which case you must specify a category if one is applicable. The value would be the category name as a string, for example"resistor"
. - The
case
key can be used to specify a minimum package size. For example:val my-min-pkg = "0402" val my-base-query = BaseQuery(case = valid-smd-pkgs(my-min-pkg))
- Special keys are discussed in a separate section.
Relationship to underlying dbquery
interface¶
This article describes the high-level query interface that is recommended as the tool of first resort for managing queries to the parts database. Internally it is currently implemented as a wrapper around the older, lower-level dbquery
interface which is documented separately. In some cases dbquery
will encounter an error state due to an issue that was not caught by the API, so it is useful to know how they relate.
Most of the keys here correspond to dbquery
keys on a one-to-one basis. In simple cases, the keyword name is the same as the underlying dbquery
key, but there are several kinds of exceptions:
- keyword named differently because they don't translate directly, such as
min-stock
(instead of having to specifystock
as an interval),quantity-needed
- keywords which do something special in the new API and don't translate at all, such as
ignore-stock
- dots are usually replaced by underscores, because dots cannot be used in a keyword. e.g.
metadata_packaging
. - special keys starting with an underscore have keyword names which instead end in a exclamation mark. for example
_sellers
becomessellers!
.
Advanced usage: special keywords and values¶
stock!
,sellers!
, andquantity-needed
are general keys that can go anywhere except that they will be ignored if theignore-stock
key is also specified.ignore-stock
can go anywhere and has no underlyingdbquery
key, serving only as a convenient way to override these keys. The intended use is to includeignore-stock
in the global query defaults when unrelated design work is in progress so as to speed up queries and not introduce unnecessary instability in the parts chosen when recompiling the design.sort!
is special in that it refers to other keys and affects the ordering of results but does not filter in any other way. Of course forcreate-[cat]
this can have a big influence on which part is chosen. It can go in any query.exist!
is special because it refers to other keys and filters based on their existence in the database (i.e., do they have any value at all), but not the value itself. It can go anywhere.distinct!
is special in that it changes the output semantics. It refers to another key and returns distinct possible values for that key instead of parts. It can only go insearch-[cat]s
.
The last three of these: sort!
, exist!
, and distinct!
have special value types because they need to refer to other keys. The method for specifying these values is a little bit indirect because of a technical limitation. The keywords themselves cannot be used to refer to themselves in Stanza code because they need to refer to the values passed in function call. The implementation does have a standard key object, defined as an enum, corresponding to each keyword, but to avoid confusion these are not exposed publicly. So we use intermediate functions: ExistKeys
, SortKey
, and DistinctKey
, to create the relevant values, and these functions use the familiar keywords.
For example:
val my-query =
ResistorQuery(exists! = ExistKeys(rated-power = true,
metadata_packaging = true))
rated-power
and metadata.packaging
keys exist in the returned part data. (Side note: don't try to do this by specifying an infinite interval, that won't work.)
That is the basic method, but for sort!
and distinct!
there is yet another shorthand which is to use a special value marker in the same function call instead of calling an intermediate function. The two special values for sort!
are FindMinimum
and FindMaximum
and the sole special value for distinct!
is FindDistinct
. For example:
val rated-powers = search-resistors(resistance = 1500.,
rated-power = FindDistinct)
_distinct
parameter by using the FindDistinct
special value marker instead of the distinct!
keyword. Note that this does not in any way supply a value for the rated-power
key. The method of using special value markers has the limitation that it blocks the regular use of that keyword, which is undesirable in some cases. It also can't be used more than once on the same keyword, which you might want for example with distinct!
and sort!
.
Here are all the details for each special key:
exists!
¶
exists!
has only one method. The value must be a ExistKeys
object which can be built by calling ExistKeys
with keyword arguments for each of the desired keys. The value assigned to each key is always true
.
Example:
val my-query =
ResistorQuery(exists! = ExistKeys(rated-power = true,
metadata_packaging = true))
distinct!
¶
distinct!
has two methods. The first is to specify the value as a DistinctKey
object created by calling DistinctKey
and specifying exactly one keyword argument with a value of true
. It is a runtime error to pass any other number of keyword arguments. Example:
val rated-powers =
search-resistors(resistance = 1500.,
distinct! = DistinctKey(rated-power = true))
FindDistinct
special value marker with the keyword corresponding to the desired key. Example:
val rated-powers = search-resistors(resistance = 1500.,
rated-power = FindDistinct)
It is a runtime error to use both methods in the same query function call.
sort!
¶
sort!
has two methods. The first is to specify the value as either a SortKey
or Tuple<SortKey>
object. Each SortKey
object is created by calling SortKey
and specifying exactly one keyword argument. The value of the keyword argument should be either Increasing
or Decreasing
(an enum defined just for this purpose). It is a runtime error to specify any other number of keyword arguments. It might be tempting to specify multiple search columns by passing multiple keyword arguments to SortKey
but this is an error. The order of keyword arguments is ill-defined in Stanza so this is not a valid method. Make a tuple of SortKeys instead.
Examples:
ResistorQuery(my-base-query, sort! = SortKey(price = Increasing))
ResistorQuery(my-base-query, sort! = [SortKey(price = Increasing)])
ResistorQuery(my-base-query, sort! = [SortKey(price = Increasing),
SortKey(resistance = Decreasing)])
The second method is to use the FindMinimum
or FindMaximum
special value markers. They are equivalent to specifying a single SortKey with Increasing
or Decreasing
respectively. The logic behind the naming is that these are intended for use with query functions which create a component based on the top result found so the only significance of the sort order is to optimize that field. This is especially intended to help replace the functionality of OPTIMIZE-FOR
from OCDB.
Example:
ResistorQuery(my-base-query, price = FindMinimum)
Related packages¶
This article mainly documents the interface provided by the jitx/parts/query-api
package. The jitx/parts
package also forwards these other packages, intended for advanced use:
The following packages, intended for advanced use, are also forwarded by jitx/parts
: