7 Package Queries
(require denxi/query) | package: denxi |
A package query is a colon-separated string used to find package definitions.
7.1 Package Query Syntax
With no omissions, a query follows this form:
<provider>:<package>:<edition>:<revision-min>:<revision-max>:<interval-bounds> |
e.g. "example.com:htdp:teachers:8:201:ii"
<provider> is, as expected, the name of the package’s provider. This may or may not be the author of the package. A domain name for a provider name is not required, but using one is helpful if your package appears across multiple services.
<package> is the name of the package.
<revision-min> and <revision-max> can each be a revision number or a revision name.
Finally, <interval-bounds> can be "ee", "ie", "ei", or "ii". These characters control if <revision-min> or <revision-max> are interpreted as inclusive or exclusive interval boundaries. The first character controls <revision-min>. The second character controls <revision-max>. If the character is "i", then the boundary is inclusive of the defined revision. If "e", exclusive.
7.2 Package Query Omissions
To omit a field, use consecutive colons, or leave fields off the end of the string. An omitted field is set to the empty string.
e.g. "example.com:htdp::8::ie", or "example.com:htdp".
When a field is set to the empty string, a fallback value may be used instead. See Autocompleting Package Queries for more information.
The empty string is equivalent to using only default values.
7.3 Package Query Classifications
A parsed package query is an instance of parsed-package-query.
A well-formed package query is a parsed package query that uses strings for all fields.
A malformed package query is a parsed package query that is not a well-formed package query.
A resolved package query is a well-formed package query where the minimum and maximum revisions are digit strings that can be trivially converted to revision numbers.
An exact package query is a resolved package query where the minimum and maximum revisions form an inclusive interval that matches exactly one version.
7.4 Parsing a Package Query
Assume that a query Q is bound to a well-formed package query with no omissions. In that case you can construct an instance of parsed-package-query using (apply parsed-package-query (string-split Q ":")).
In the general case where fields may be omitted, any missing fields should be set to the empty string like so:
(define (parse-package-query s) (define user-defined (string-split s ":")) (define num-fields (length user-defined)) (apply parsed-package-query (build-list (procedure-arity parsed-package-query) (λ (i) (if (< i num-fields) (list-ref user-defined i) "")))))
7.5 Examples
Field positions are important. You can still create a query for just calculator, but calculator would be intepreted as the provider, and not the package name.
7.5.1 Specifying an Edition
If you prefer a scientific calculator, the package author can provide that design under a different edition. Specify an edition using the next field.
example.com:calculator:scientific |
7.5.2 Specifying Accepted Revisions
The next field is for requesting a specific revision of a package.
example.com:calculator:scientific:288 |
example.com:calculator:scientific:open-beta |
A revision can be an exact nonnegative integer or a name. Names are aliases for numbers.
What about version ranges? Just add another revision to act as the maximum accepted revision.
example.com:calculator:scientific:288:288 |
From here we can change the endpoints of the interval to accept alternative packages. This is useful if some implementations are not available.
example.com:calculator:scientific:102:288 |
7.5.3 Marking Inclusive and Exclusive Endpoints
By default, revision intervals are inclusive of their endpoints. You can add flags to mark the interval as inclusive or exclusive of each endpoint. Use the letter i for inclusive, and e for exclusive. In the below form, revision 288 will not match this query because of the e on the right side of the two flags.
example.com:calculator:scientific:102:288:ie |
Using integer interval notation:
ii means {102 .. 288}
ie means {102 .. 287}
ei means {103 .. 288}
ee means {103 .. 287}
Marking exclusive bounds are useful with revision names. The below query requests a scientific calculator’s closed beta implementation, up to but not including the production-ready revision.
example.com:calculator:scientific:closed-beta:production:ie |
If the author did not define a revision name marking the end of a beta, then you would have to know the revision number in advance of writing the query. With the interval flags, you do not have to know any revision numbers.
When resolving revision names, Denxi will raise an error for queries like these because they each resolve to a backwards interval:
example.com:calculator:scientific:production:closed-beta |
example.com:calculator:scientific:9:0 |
example.com:calculator:scientific:3:3:ee |
7.5.4 Omitting Information
You may omit fields in package queries. Two contiguous colons will set the associated field to the empty string. Any contiguous colon sequence at the end of a query is implied and does not need to be typed.
example.com:calculator::production |
Even the empty string is a valid package query. In fact, "" and ":::" parse the same way.
7.6 Primitive Package Query Operations
struct
(struct parsed-package-query ( provider-name package-name edition-name revision-min revision-max interval-bounds)) provider-name : string? package-name : string? edition-name : string? revision-min : string? revision-max : string? interval-bounds : string?
procedure
v : any/c
procedure
v : any/c
procedure
v : any/c
procedure
(exact-package-query? v) → boolean?
v : any/c
value
procedure
(coerce-parsed-package-query variant) → parsed-package-query?
variant : package-query-variant?
procedure
(format-parsed-package-query query) → string?
query : well-formed-package-query?
procedure
(make-exact-package-query provider name revision-number) → exact-package-query? provider : string? name : string? revision-number : revision-number?
procedure
(resolve-minimum-revision query find-revision-number) → any/c query : parsed-package-query? find-revision-number : (-> string? any/c)
Pass the implementation for translating revision names to revision numbers as find-revision-number. When necessary, resolve-minimum-revision will apply find-revision-number to a revision name to resolve.
find-revision-number may return something other than a revision number. resolve-minimum-revision will return that value as-is. find-revision-number may also raise an error, which will be caught and returned only if it’s not an instance of exn:break. Leverage these rules to understand why a particular resolution failed (e.g. a web service 404s for a minimum revision name, but not the maximum).
If find-revision-number returns a revision number, it is adjusted according to (parsed-package-query-interval-bounds query) using make-minimum-revision-number.
procedure
(resolve-maximum-revision query find-revision-number) → any/c query : parsed-package-query? find-revision-number : (-> string? any/c)
procedure
(abbreviate-exact-package-query query) → string?
query : exact-package-query?
procedure
str : string?
7.7 Autocompleting Package Queries
This section covers autocompleting package queries, which entails replacing empty strings and non-string elements of parsed-package-query instances with well-formed values.
It implements every method using the same code as the fallbacks for the generic interface.
procedure
(autocomplete-parsed-package-query autocomplete query) → well-formed-package-query? autocomplete : package-query-defaults-implementation/c query : parsed-package-query?
procedure
(get-default-provider defaults) → string?
defaults : package-query-defaults?
The fallback implementation for this method always returns DEFAULT_STRING.
procedure
(get-default-package defaults provider) → string?
defaults : package-query-defaults? provider : string?
The fallback implementation for this method always returns DEFAULT_STRING.
procedure
(get-default-edition defaults provider package-name) → string? defaults : package-query-defaults? provider : string? package-name : string?
The fallback implementation for this method always returns DEFAULT_STRING.
procedure
(get-default-min-revision defaults provider package-name edition) → string? defaults : package-query-defaults? provider : string? package-name : string? edition : string?
The fallback implementation for this method always returns "0".
procedure
(get-default-max-revision defaults provider package-name edition min-revision) → string? defaults : package-query-defaults? provider : string? package-name : string? edition : string? min-revision : string?
The fallback implementation for this method always returns DEFAULT_STRING.
procedure
c : package-query-defaults?
The fallback implementation for this method always returns "ii".
7.8 Creating Canonical Package Queries
Package queries may or may not refer to existing data at some location. They require an authority to state that not only is a package query meaningful, but the authority can direct a program to the data using an exact variant of the query that it will provide.
A package query canon (or just “canon” in the context of this section) is an implementation of gen:package-query-canon that represents the authority. A package query produced using make-canonical-package-query is said to be in canonical form with respect to a canon. We can also call the result a canonical package query.
A canonical package query is an exact package query. There is no predicate for canonical package queries, so the only meaningful difference is that canonical package queries are expected to work with the canon that defines them.
Therefore, make-canonical-package-query represents a social contract for a package query canon to only make valid queries. If it is not able to do this, it should not return a query at all.
syntax
value
procedure
(make-canonical-package-query [ #:force-complete-interval? force-complete-interval?] canon defaults query) → (subprogram/c exact-package-query?) force-complete-interval? : any/c = #f canon : package-query-canon-implementation/c defaults : package-query-defaults-implementation/c query : package-query-variant?
Autocomplete query using (autocomplete-parsed-package-query defaults query).
Convert all revision names in the output of Step 1 to a revision number interval.
Select exactly one revision number from the interval defined in Step 2 that points to an available package definition.
Return an exact package query using the output of Step 3.
In the event only one of the two revision interval endpoints is resolved, the return value depends on force-complete-interval?. If force-complete-interval? is a true value, the process will skip Step 3 and use the only available revision number to perform Step 4. Be careful with this option, because it discards the error information for the unresolved boundary.
struct
(struct $package-query-canon $message ( user-query autocompleted-query) #:prefab) user-query : package-query? autocompleted-query : package-query?
user-query reflects what was passed to make-canonical-package-query. autocompleted-query is the result of applying autocomplete-parsed-package-query to user-query in advance of the attempted conversion.
struct
(struct $package-query-canon:backwards $package-query-canon (alleged-minimum alleged-maximum)) alleged-minimum : revision-number? alleged-maximum : revision-number?
struct
(struct $package-query-canon:no-minimum $package-query-canon (hint))
hint : any/c
hint is the value—or a derived serializeable value—created by applying resolve-minimum-revision to the autocompleted query. It may clarify why the revision name did not resolve.
struct
(struct $package-query-canon:no-maximum $package-query-canon (hint))
hint : any/c
struct
(struct $package-query-canon:no-selection $package-query-canon (minimum maximum hint)) minimum : revision-number? maximum : revision-number? hint : any/c
hint is an implementation-specific value meant to explain why this is the case.
struct
(struct $package-query-canon:oob $package-query-canon ( minimum maximum selection)) minimum : revision-number? maximum : revision-number? selection : revision-number?
procedure
(find-revision-number canon provider package edition revision-name) → any/c canon : package-query-canon-implementation/c provider : string? package : string? edition : string? revision-name : string?
procedure
(select-revision-number canon provider package edition revision-min revision-max) → any/c canon : package-query-canon-implementation/c provider : string? package : string? edition : string? revision-min : revision-number? revision-max : revision-number?
revision-min and revision-max are boundaries to an inclusive integer interval. The revisions they represent may not exist where definitions would be stored. If select-revision-number returns a revision number, it will be constrained to {revision-min ... revision-max} to represent the best available revision (Typically this is the revision number closest to revision-max).
Warning: Only return a revision number from your implementation if the caller may assume that the package definition it references actually exists. Failure to do so will cause a runtime error.