You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: versioned_docs/version-4.3/developers/rest.md
+61-26Lines changed: 61 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -122,7 +122,7 @@ The comparison operators include standard FIQL operators, `lt` (less than), `le`
122
122
GET /Product/?category=software&price=gt=100&price=lt=200
123
123
```
124
124
125
-
Comparison operators can also be used on Date fields, however, we have to ensure that the date format is properly escaped. For example, if we are looking for a listing date greater than `2017-03-08T09:00:00.000Z` we must escape the colons as `%3A`:
125
+
Comparison operators can also be used on Date fields, however, we have to ensure that the date format is properly escaped. For example, if we are looking for a listing date greater than `2017-03-08T09:00:00.000Z` we must escape the colons as `%3A`:
126
126
127
127
```
128
128
GET /Product/?listDate=gt=2017-03-08T09%3A30%3A00.000Z
@@ -137,38 +137,49 @@ GET /Product/?name==Keyboard*
137
137
Note that some HTTP clients may be overly aggressive in encoding query parameters, and you may need to disable extra encoding of query parameters, to ensure operators are passed through without manipulation.
138
138
139
139
Here is a full list of the supported FIQL-style operators/comparators:
140
-
*`==`: equal
141
-
*`=lt=`: less than
142
-
*`=le=`: less than or equal
143
-
*`=gt=`: greater than
144
-
*`=ge=`: greater than or equal
145
-
*`=ne=`, !=: not equal
146
-
*`=ct=`: contains the value (for strings)
147
-
*`=sw=`, `==<value>*`: starts with the value (for strings)
148
-
*`=ew=`: ends with the value (for strings)
149
-
*`=`, `===`: strict equality (no type conversion)
150
-
*`!==`: strict inequality (no type conversion)
140
+
141
+
-`==`: equal
142
+
-`=lt=`: less than
143
+
-`=le=`: less than or equal
144
+
-`=gt=`: greater than
145
+
-`=ge=`: greater than or equal
146
+
-`=ne=`, !=: not equal
147
+
-`=ct=`: contains the value (for strings)
148
+
-`=sw=`, `==<value>*`: starts with the value (for strings)
149
+
-`=ew=`: ends with the value (for strings)
150
+
-`=`, `===`: strict equality (no type conversion)
151
+
-`!==`: strict inequality (no type conversion)
151
152
152
153
### Unions
154
+
153
155
Conditions can also be applied with `OR` logic, returning the union of records that match either condition. This can be specified by using the `|` operator instead of `&`. For example, to return any product a rating of `5`_or_ a `featured` attribute that is `true`, we could write:
156
+
154
157
```http
155
158
GET /Product/?rating=5|featured=true
156
159
```
157
160
158
161
### Grouping of Operators
162
+
159
163
Multiple conditions with different operators can be combined with grouping of conditions to indicate the order of operation. Grouping conditions can be done with parenthesis, with standard grouping conventions as used in query and mathematical expressions. For example, a query to find products with a rating of 5 OR a price between 100 and 200 could be written:
164
+
160
165
```http
161
166
GET /Product/?rating=5|(price=gt=100&price=lt=200)
162
167
```
168
+
163
169
Grouping conditions can also be done with square brackets, which function the same as parenthesis for grouping conditions. The advantage of using square brackets is that you can include user provided values that might have parenthesis in them, and use standard URI component encoding functionality, which will safely escape/encode square brackets, but not parenthesis. For example, if we were constructing a query for products with a rating of a 5 and matching one of a set of user provided tags, a query could be built like:
170
+
164
171
```http
165
172
GET /Product/?rating=5&[tag=fast|tag=scalable|tag=efficient]
166
173
```
174
+
167
175
And the tags could be safely generated from user inputs in a tag array like:
176
+
168
177
```javascript
169
-
let url =`/Product/?rating=5[${tags.map(encodeURIComponent).join('|')}]`
178
+
let url =`/Product/?rating=5[${tags.map(encodeURIComponent).join('|')}]`;
170
179
```
180
+
171
181
More complex queries can be created by further nesting groups:
182
+
172
183
```http
173
184
GET /Product/?price=lt=100|[rating=5&[tag=fast|tag=scalable|tag=efficient]&inStock=true]
174
185
```
@@ -181,11 +192,11 @@ HarperDB has several special query functions that use "call" syntax. These can b
181
192
182
193
This function allows you to specify which properties should be included in the responses. This takes several forms:
183
194
184
-
*`?select(property)`: This will return the values of the specified property directly in the response (will not be put in an object).
185
-
*`?select(property1,property2)`: This returns the records as objects, but limited to the specified properties.
186
-
*`?select([property1,property2,...])`: This returns the records as arrays of the property values in the specified properties.
187
-
*`?select(property1,)`: This can be used to specify that objects should be returned with the single specified property.
188
-
*`?select(property{subProperty1,subProperty2{subSubProperty,..}},...)`: This can be used to specify which sub-properties should be included in nested objects and joined/references records.
195
+
-`?select(property)`: This will return the values of the specified property directly in the response (will not be put in an object).
196
+
-`?select(property1,property2)`: This returns the records as objects, but limited to the specified properties.
197
+
-`?select([property1,property2,...])`: This returns the records as arrays of the property values in the specified properties.
198
+
-`?select(property1,)`: This can be used to specify that objects should be returned with the single specified property.
199
+
-`?select(property{subProperty1,subProperty2{subSubProperty,..}},...)`: This can be used to specify which sub-properties should be included in nested objects and joined/references records.
189
200
190
201
To get a list of product names with a category of software:
191
202
@@ -208,19 +219,25 @@ GET /Product/?rating=gt=3&inStock=true&select(rating,name)&limit(20)
208
219
This function allows you to indicate the sort order for the returned results. The argument for `sort()` is one or more properties that should be used to sort. If the property is prefixed with '+' or no prefix, the sort will be performed in ascending order by the indicated attribute/property. If the property is prefixed with '-', it will be sorted in descending order. If the multiple properties are specified, the sort will be performed on the first property, and for records with the same value for that property, the next property will be used to break the tie and sort results. This tie breaking will continue through any provided properties.
209
220
210
221
For example, to sort by product name (in ascending order):
222
+
211
223
```http
212
224
GET /Product?rating=gt=3&sort(+name)
213
225
```
226
+
214
227
To sort by rating in ascending order, then by price in descending order for products with the same rating:
228
+
215
229
```http
216
230
GET /Product?sort(+rating,-price)
217
231
```
218
232
219
233
# Relationships
234
+
220
235
HarperDB supports relationships in its data models, allowing for tables to define a relationship with data from other tables (or even itself) through foreign keys. These relationships can be one-to-many, many-to-one, or many-to-many (and even with ordered relationships). These relationships are defined in the schema, and then can easily be queried through chained attributes that act as "join" queries, allowing related attributes to referenced in conditions and selected for returned results.
221
236
222
237
## Chained Attributes and Joins
238
+
223
239
To support relationships and hierarchical data structures, in addition to querying on top-level attributes, you can also query on chained attributes. Most importantly, this provides HarperDB's "join" functionality, allowing related tables to be queried and joined in the results. Chained properties are specified by using dot syntax. In order to effectively leverage join functionality, you need to define a relationship in your schema:
240
+
224
241
```graphql
225
242
typeProduct@table@export {
226
243
id: ID@primaryKey
@@ -234,35 +251,47 @@ type Brand @table @export {
234
251
products: [Product] @relationship(to: "brandId")
235
252
}
236
253
```
254
+
237
255
Andthenyoucouldqueryaproductbybrandname:
256
+
238
257
```http
239
258
GET /Product/?brand.name=Microsoft
240
259
```
260
+
241
261
This will query for products for which the `brandId` references a `Brand` record with a `name` of `"Microsoft"`.
242
262
243
263
The `brand` attribute in `Product` is a "computed" attribute from the foreign key (`brandId`), for the many-to-one relationship to the `Brand`. In the schema above, we also defined the reverse one-to-many relationship from a `Brand` to a `Product`, and we could likewise query that:
264
+
244
265
```http
245
266
GET /Brand/?products.name=Keyboard
246
267
```
268
+
247
269
This would return any `Brand` with at least one product with a name `"Keyboard"`. Note, that both of these queries are effectively acting as an "INNER JOIN".
248
270
249
271
### Chained/Nested Select
272
+
250
273
Computed relationship attributes are not included by default in query results. However, we can include them by specifying them in a select:
274
+
251
275
```http
252
276
GET /Product/?brand.name=Microsoft&select(name,brand)
253
277
```
278
+
254
279
We can also do a "nested" select and specify which sub-attributes to include. For example, if we only wanted to include the name property from the brand, we could do so:
280
+
255
281
```http
256
282
GET /Product/?brand.name=Microsoft&select(name,brand{name})
257
283
```
284
+
258
285
Or to specify multiple sub-attributes, we can comma delimit them. Note that selects can "join" to another table without any constraint/filter on the related/joined table:
286
+
259
287
```http
260
288
GET /Product/?name=Keyboard&select(name,brand{name,id})
261
289
```
262
-
When selecting properties from a related table without any constraints on the related table, this effectively acts like a "LEFT JOIN" and will omit the `brand` property if the brandId is `null` or references a non-existent brand.
263
290
291
+
When selecting properties from a related table without any constraints on the related table, this effectively acts like a "LEFT JOIN" and will omit the `brand` property if the brandId is `null` or references a non-existent brand.
264
292
265
293
### Many-to-many Relationships (Array of Foreign Keys)
294
+
266
295
Many-to-many relationships are also supported, and can easily be created using an array of foreign key values, without requiring the traditional use of a junction table. This can be done by simply creating a relationship on an array-typed property that references a local array of foreign keys. For example, we could create a relationship to the resellers of a product (each product can have multiple resellers, each )
267
296
268
297
```graphql
@@ -278,11 +307,15 @@ type Reseller @table {
278
307
...
279
308
}
280
309
```
310
+
281
311
Theproductrecordcanthenholdanarrayoftheresellerids. Whenthe `reseller` propertyisaccessed (either through code or through select, conditions), thearrayofidsisresolvedtoanarrayofresellerrecords. Wecanalsoquerythroughtheresellersrelationshipslikewiththeotherrelationships. Forexample, toquerytheproductsthatareavailablethroughthe"Cool Shop":
312
+
282
313
```http
283
314
GET /Product/?resellers.name=CoolShop&select(id,name,resellers{name,id})
284
315
```
316
+
285
317
One of the benefits of using an array of foreign key values is that the this can be manipulated using standard array methods (in JavaScript), and the array can dictate an order to keys and therefore to the resulting records. For example, you may wish to define a specific order to the resellers and how they are listed (which comes first, last):
Queries parameters are simply text, so there are several features for converting parameter values to properly typed values for performing correct searches. For the FIQL comparators, which includes `==`, `!=`, `=gt=`, `=lt=`, `=ge=`, `=gt=`, the parser will perform type conversion, according to the following rules:
296
-
*`name==null`: Will convert the value to `null` for searching.
297
-
*`name==123`: Will convert the value to a number _if_ the attribute is untyped (there is no type specified in a GraphQL schema, or the type is specified to be `Any`).
298
-
*`name==true`: Will convert the value to a boolean _if_ the attribute is untyped (there is no type specified in a GraphQL schema, or the type is specified to be `Any`).
299
-
*`name==number:123`: Will explicitly convert the value after "number:" to a number.
300
-
*`name==boolean:true`: Will explicitly convert the value after "boolean:" to a boolean.
301
-
*`name==string:some%20text`: Will explicitly keep the value after "string:" as a string (and perform URL component decoding)
302
-
*`name==date:2024-01-05T20%3A07%3A27.955Z`: Will explicitly convert the value after "date:" to a Date object.
330
+
331
+
-`name==null`: Will convert the value to `null` for searching.
332
+
-`name==123`: Will convert the value to a number _if_ the attribute is untyped (there is no type specified in a GraphQL schema, or the type is specified to be `Any`).
333
+
-`name==true`: Will convert the value to a boolean _if_ the attribute is untyped (there is no type specified in a GraphQL schema, or the type is specified to be `Any`).
334
+
-`name==number:123`: Will explicitly convert the value after "number:" to a number.
335
+
-`name==boolean:true`: Will explicitly convert the value after "boolean:" to a boolean.
336
+
-`name==string:some%20text`: Will explicitly keep the value after "string:" as a string (and perform URL component decoding)
337
+
-`name==date:2024-01-05T20%3A07%3A27.955Z`: Will explicitly convert the value after "date:" to a Date object.
303
338
304
339
If the attribute specifies a type (like `Float`) in the schema definition, the value will always be converted to the specified type before searching.
Copy file name to clipboardExpand all lines: versioned_docs/version-4.4/developers/rest.md
+24-24Lines changed: 24 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -150,17 +150,17 @@ Note that some HTTP clients may be overly aggressive in encoding query parameter
150
150
151
151
Here is a full list of the supported FIQL-style operators/comparators:
152
152
153
-
*`==`: equal
154
-
*`=lt=`: less than
155
-
*`=le=`: less than or equal
156
-
*`=gt=`: greater than
157
-
*`=ge=`: greater than or equal
158
-
*`=ne=`, !=: not equal
159
-
*`=ct=`: contains the value (for strings)
160
-
*`=sw=`, `==<value>*`: starts with the value (for strings)
161
-
*`=ew=`: ends with the value (for strings)
162
-
*`=`, `===`: strict equality (no type conversion)
163
-
*`!==`: strict inequality (no type conversion)
153
+
-`==`: equal
154
+
-`=lt=`: less than
155
+
-`=le=`: less than or equal
156
+
-`=gt=`: greater than
157
+
-`=ge=`: greater than or equal
158
+
-`=ne=`, !=: not equal
159
+
-`=ct=`: contains the value (for strings)
160
+
-`=sw=`, `==<value>*`: starts with the value (for strings)
161
+
-`=ew=`: ends with the value (for strings)
162
+
-`=`, `===`: strict equality (no type conversion)
163
+
-`!==`: strict inequality (no type conversion)
164
164
165
165
#### Unions
166
166
@@ -187,7 +187,7 @@ GET /Product/?rating=5&[tag=fast|tag=scalable|tag=efficient]
187
187
And the tags could be safely generated from user inputs in a tag array like:
188
188
189
189
```javascript
190
-
let url =`/Product/?rating=5[${tags.map(encodeURIComponent).join('|')}]`
190
+
let url =`/Product/?rating=5[${tags.map(encodeURIComponent).join('|')}]`;
191
191
```
192
192
193
193
More complex queries can be created by further nesting groups:
@@ -204,11 +204,11 @@ Harper has several special query functions that use "call" syntax. These can be
204
204
205
205
This function allows you to specify which properties should be included in the responses. This takes several forms:
206
206
207
-
*`?select(property)`: This will return the values of the specified property directly in the response (will not be put in an object).
208
-
*`?select(property1,property2)`: This returns the records as objects, but limited to the specified properties.
209
-
*`?select([property1,property2,...])`: This returns the records as arrays of the property values in the specified properties.
210
-
*`?select(property1,)`: This can be used to specify that objects should be returned with the single specified property.
211
-
*`?select(property{subProperty1,subProperty2{subSubProperty,..}},...)`: This can be used to specify which sub-properties should be included in nested objects and joined/references records.
207
+
-`?select(property)`: This will return the values of the specified property directly in the response (will not be put in an object).
208
+
-`?select(property1,property2)`: This returns the records as objects, but limited to the specified properties.
209
+
-`?select([property1,property2,...])`: This returns the records as arrays of the property values in the specified properties.
210
+
-`?select(property1,)`: This can be used to specify that objects should be returned with the single specified property.
211
+
-`?select(property{subProperty1,subProperty2{subSubProperty,..}},...)`: This can be used to specify which sub-properties should be included in nested objects and joined/references records.
212
212
213
213
To get a list of product names with a category of software:
Queries parameters are simply text, so there are several features for converting parameter values to properly typed values for performing correct searches. For the FIQL comparators, which includes `==`, `!=`, `=gt=`, `=lt=`, `=ge=`, `=gt=`, the parser will perform type conversion, according to the following rules:
342
342
343
-
*`name==null`: Will convert the value to `null` for searching.
344
-
*`name==123`: Will convert the value to a number _if_ the attribute is untyped (there is no type specified in a GraphQL schema, or the type is specified to be `Any`).
345
-
*`name==true`: Will convert the value to a boolean _if_ the attribute is untyped (there is no type specified in a GraphQL schema, or the type is specified to be `Any`).
346
-
*`name==number:123`: Will explicitly convert the value after "number:" to a number.
347
-
*`name==boolean:true`: Will explicitly convert the value after "boolean:" to a boolean.
348
-
*`name==string:some%20text`: Will explicitly keep the value after "string:" as a string (and perform URL component decoding)
349
-
*`name==date:2024-01-05T20%3A07%3A27.955Z`: Will explicitly convert the value after "date:" to a Date object.
343
+
-`name==null`: Will convert the value to `null` for searching.
344
+
-`name==123`: Will convert the value to a number _if_ the attribute is untyped (there is no type specified in a GraphQL schema, or the type is specified to be `Any`).
345
+
-`name==true`: Will convert the value to a boolean _if_ the attribute is untyped (there is no type specified in a GraphQL schema, or the type is specified to be `Any`).
346
+
-`name==number:123`: Will explicitly convert the value after "number:" to a number.
347
+
-`name==boolean:true`: Will explicitly convert the value after "boolean:" to a boolean.
348
+
-`name==string:some%20text`: Will explicitly keep the value after "string:" as a string (and perform URL component decoding)
349
+
-`name==date:2024-01-05T20%3A07%3A27.955Z`: Will explicitly convert the value after "date:" to a Date object.
350
350
351
351
If the attribute specifies a type (like `Float`) in the schema definition, the value will always be converted to the specified type before searching.
0 commit comments