diff --git a/docs/basic-usage.md b/docs/basic-usage.md index 3cb26ff..75ff4d8 100644 --- a/docs/basic-usage.md +++ b/docs/basic-usage.md @@ -12,7 +12,8 @@ There are several categories of operations that can be accomplished against docu - **Save** adds a new document, updating an existing one if the ID is already present ("upsert") - **Update** updates an existing document, doing nothing if no documents satisfy the criteria - **Patch** updates a portion of an existing document, doing nothing if no documents satisfy the criteria -- **Find** returns the documents matching some criteria +- **Find** returns the documents matching some criteria as domain objects +- **Json** returns documents as JSON strings or outputs that JSON directly - **RemoveFields** removes fields from documents matching some criteria - **Delete** removes documents matching some criteria @@ -23,7 +24,7 @@ There are several categories of operations that can be accomplished against docu - **byContains** (PostgreSQL only) uses a JSON containment query (the `@>` operator) to find documents where the given sub-document occurs (think of this as an `=` comparison based on one or more properties in the document; looking for hotels with `{ "country": "USA", "rating": 4 }` would find all hotels with a rating of 4 in the United States); applies to all but Update - **byJsonPath** (PostgreSQL only) uses a JSON patch match query (the `@?` operator) to make specific queries against a document's structure (it also supports more operators than a containment query; to find all hotels rated 4 _or higher_ in the United States, we could query for `"$ ? (@.country == \"USA\" && @.rating > 4)"`); applies to all but Update -Finally, `Find` also has `firstBy*` implementations for all supported criteria types. +Finally, `Find` and `Json` also has `firstBy*` implementations for all supported criteria types. ## Saving Documents @@ -62,10 +63,15 @@ For SQLite, we can utilize a `Field` query with a between operator. (This will a ```php // SQLite -Patch::byFields('room', [Field::between('roomNumber', 221, 240)], ['inService' => false]); +Patch::byFields('room', + [Field::equal('hotelId', 'abc'), Field::between('roomNumber', 221, 240)], + ['inService' => false]); ``` -## Finding Documents +> [!NOTE] +> When multiple fields are provided to any `*byFields` function, the default matching behavior is `FieldMatch.All`; any documents identified will match all criteria. Passing `FieldMatch.Any` modifies this behavior to identify documents where any one of the criteria match. + +## Finding Documents as Domain Items Functions to find documents start with `Find::`. There are variants to find all documents in a table, find by ID, find by JSON field comparison, find by JSON containment, or find by JSON Path. The hotel update example above utilizes an ID lookup; the descriptions of JSON containment and JSON Path show examples of the criteria used to retrieve using those techniques. @@ -109,6 +115,13 @@ foreach ($result->items as $item) { // Do something amazing with $item } ``` +## Finding Documents as JSON + +If an application serves endpoints that return JSON, taking the time to retrieve documents, deserialize them into objects, then turning around and serializing those same documents back to JSON - there's a lot of unnecessary processing going on. Static functions on the `Json` object address this by returning, or directly outputting, the JSON text received from the database. + +`Json` has the same function names as `Find`, and these functions return the JSON as a string. These always return some string with valid JSON; an empty multiple-document request will be `[]`, and a one-or-none document request will be `{}` in the "none" scenario. + +A second set of functions are prefixed with `output` (ex. `Json::outputAll`); these functions `echo` the JSON as it is retrieved from the database. This is the preferred method for JSON APIs, as it incurs no intermediate overhead; take the documents from the database and ship 'em off to the distant end. As these responses end up as a stream of text, we will need to identify this as JSON; `Json::setContentType()` will do this, and should be called before any other output is sent. ## Deleting Documents @@ -126,14 +139,14 @@ Functions to check for existence start with `Exists::`. Documents may be checked The table below shows which commands are available for each access method. (X = supported for both, P = PostgreSQL only) -| Operation | `all` | `byId` | `byFields` | `byContains` | `byJsonPath` | `firstByFields` | `firstByContains` | `firstByJsonPath` | -|----------------|:-----:|:------:|:----------:|:------------:|:------------:|:---------------:|:-----------------:|:-----------------:| -| `Count` | X | | X | P | P | | | | -| `Exists` | | X | X | P | P | | | | -| `Find` | X | X | X | P | P | X | P | P | -| `Patch` | | X | X | P | P | | | | -| `RemoveFields` | | X | X | P | P | | | | -| `Delete` | | X | X | P | P | | | | +| Operation | `all` | `byId` | `byFields` | `byContains` | `byJsonPath` | `firstByFields` | `firstByContains` | `firstByJsonPath` | +|-----------------|:-----:|:------:|:----------:|:------------:|:------------:|:---------------:|:-----------------:|:-----------------:| +| `Count` | X | | X | P | P | | | | +| `Exists` | | X | X | P | P | | | | +| `Find` / `Json` | X | X | X | P | P | X | P | P | +| `Patch` | | X | X | P | P | | | | +| `RemoveFields` | | X | X | P | P | | | | +| `Delete` | | X | X | P | P | | | | `Document::insert`, `Document::save`, and `Document::update` operate on single documents. diff --git a/src/Json.php b/src/Json.php index e7b9e0f..1ec1cac 100644 --- a/src/Json.php +++ b/src/Json.php @@ -241,4 +241,12 @@ class Json { echo self::firstByJsonPath($tableName, $path, $orderBy); } + + /** + * Set the content type of this page's output to JSON + */ + public static function setContentType(): void + { + header('Content-Type: application/json'); + } }