Skip to content

Commit

Permalink
Add query hook for any API method (#53)
Browse files Browse the repository at this point in the history
## What does this PR do?

When no command is found, Kourou will try to execute the given command with the `sdk:query` command.  

The first argument has to be the name of the controller and the action separated by a semicolon (eg `document:create`)

Kourou will try to infer common arguments like `index`, `collection`, `_id` or `body`.  

It will automatically infer and accept the following lists of arguments:
 - `<command> <index>`
    * _eg: `kourou collection:list iot`_
.


 - `<command> <index> <collection>`
    * _eg: `kourou collection:truncate iot sensors`_
.


 - `<command> <index> <collection> <body>`
    * _eg: `kourou bulk:import iot sensors '{bulkData: []}'`_
.


 - `<command> <index> <collection> <id>`
    * _eg: `kourou document:delete iot sensors sigfox-123`_
.


 - `<command> <index> <collection> <id> <body>`
    * _eg: `kourou document:create iot sensors sigfox-123 '{temperature: 42}'`_

Then any argument will be passed as-is to the `sdk:query` method.


### Other changes

  - add `--id` argument to `sdk:query`
 - remove `document:get`
 - remove `document:create`
  • Loading branch information
Aschen authored Jun 25, 2020
1 parent 3f839f0 commit 7e87476
Show file tree
Hide file tree
Showing 11 changed files with 277 additions and 154 deletions.
74 changes: 64 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,40 @@ $ kourou sdk:query auth:getCurrentUser --as gordon --username admin --password a
[...]
```

## Automatic command infering for API methods

When no command is found, Kourou will try to execute the given command with the `sdk:query` command.

The first argument has to be the name of the controller and the action separated by a semicolon (eg `document:create`)

Kourou will try to infer common arguments like `index`, `collection`, `_id` or `body`.

It will automatically infer and accept the following lists of arguments:
- `<command> <index>`
* _eg: `kourou collection:list iot`_
.


- `<command> <index> <collection>`
* _eg: `kourou collection:truncate iot sensors`_
.


- `<command> <index> <collection> <body>`
* _eg: `kourou bulk:import iot sensors '{bulkData: []}'`_
.


- `<command> <index> <collection> <id>`
* _eg: `kourou document:delete iot sensors sigfox-123`_
.


- `<command> <index> <collection> <id> <body>`
* _eg: `kourou document:create iot sensors sigfox-123 '{temperature: 42}'`_

Then any argument will be passed as-is to the `sdk:query` method.

# Commands

<!-- commands -->
Expand Down Expand Up @@ -861,6 +895,8 @@ OPTIONS
--host=host [default: localhost] Kuzzle server host
--id=id ID argument (_id)
--password=password Kuzzle user password
--port=port [default: 7512] Kuzzle server port
Expand All @@ -876,16 +912,17 @@ DESCRIPTION
Query arguments
arguments can be passed and repeated using the --arg or -a flag.
index and collection names can be passed with --index (-i) and --collection (-c) flags
Arguments can be passed and repeated using the --arg or -a flag.
Index and collection names can be passed with --index (-i) and --collection (-c) flags
ID can be passed with the --id flag.
Examples:
- kourou sdk:query document:get -i iot -c sensors -a _id=sigfox-42
- kourou sdk:query document:delete -i iot -c sensors -a refresh=wait_for
Query body
body can be passed with the --body flag with either a JSON or JS string.
body will be read from STDIN if available
Body can be passed with the --body flag with either a JSON or JS string.
Body will be read from STDIN if available
Examples:
- kourou sdk:query document:create -i iot -c sensors --body '{creation: Date.now())}'
Expand All @@ -894,12 +931,29 @@ DESCRIPTION
Other
use the --editor flag to modify the query before sending it to Kuzzle
use the --display flag to display a specific property of the response
Use the --editor flag to modify the query before sending it to Kuzzle
Use the --display flag to display a specific property of the response
Examples:
- kourou sdk:query document:create -i iot -c sensors --editor
- kourou sdk:query server:now --display 'result.now'
Default fallback to API method
It's possible to use this command by only specifying the corresponding controller
and action as first argument.
Kourou will try to infer the 4th first arguments to one the following:
- <index> <collection> <id> <body>
- <index> <collection> <body>
If a flag is given (-i, -c, --body or --id), then the flag value has prior to
argument infering.
Examples:
- kourou document:createOrReplace iot sensors sigfox-1 '{}'
- kourou collection:delete iot sensors
- kourou collection:list iot
- kourou bulk:import iot sensors '{bulkData: [...]}'
- kourou admin:loadMappings < mappings.json
```

_See code: [src/commands/sdk/query.ts](src/commands/sdk/query.ts)_
Expand Down Expand Up @@ -985,10 +1039,10 @@ DESCRIPTION
The users will be exported WITHOUT their credentials since Kuzzzle can't access them.
You can either:
- manually re-create credentials for your users
- use the "mustChangePasswordIfSetByAdmin" option Kuzzle password policies (see
- Manually re-create credentials for your users
- Use the "mustChangePasswordIfSetByAdmin" option Kuzzle password policies (see
https://github.com/kuzzleio/kuzzle-plugin-auth-passport-local/#optional-properties)
- use the "--generate-credentials" flag to auto-generate credentials for your users
- Use the "--generate-credentials" flag to auto-generate credentials for your users
Auto-generation of credentials
Expand Down
47 changes: 47 additions & 0 deletions features/ApiMethodHook.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Feature: Hooks

# command_not_found hook =====================================================

@mappings
Scenario: Unregistered API method
Given an existing collection "nyc-open-data":"yellow-taxi"
When I run the command "document:createOrReplace" with:
| flag | --arg | index=nyc-open-data |
| flag | --arg | collection=yellow-taxi |
| flag | -a | _id=chuon-chuon-kim |
| flag | --body | { "other-name": "my" } |
Then The document "chuon-chuon-kim" content match:
| other-name | "my" |

@mappings
Scenario: Infer common arguments
Given an existing collection "nyc-open-data":"yellow-taxi"
# <command> <index>
When I run the command "collection:list" with:
| arg | nyc-open-data | |
Then I should match stdout with "yellow-taxi"
# <command> <index> <collection>
When I run the command "collection:truncate" with:
| arg | nyc-open-data | |
| arg | yellow-taxi | |
Then I should match stdout with "acknowledged"
# <command> <index> <collection> <id> <body>
When I run the command "document:createOrReplace" with:
| arg | nyc-open-data | |
| arg | yellow-taxi | |
| arg | foobar-1 | |
| arg | {helloWorld: 42} | |
Then I should match stdout with "helloWorld"
# <command> <index> <collection> <id>
When I run the command "document:delete" with:
| arg | nyc-open-data | |
| arg | yellow-taxi | |
| arg | foobar-1 | |
Then I should match stdout with "foobar-1"
# <command> <index> <collection> <body>
When I run the command "collection:updateMapping" with:
| arg | nyc-open-data | |
| arg | yellow-taxi | |
| arg | { dynamic: "false" } | |
Then I should match stdout with "false"

6 changes: 3 additions & 3 deletions features/Collection.feature
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ Feature: Collection Commands

Scenario: Creates a collection
When I run the command "collection:create" with:
| arg | mtp-open-data | |
| arg | yellow-taxi | |
| flag | --body | { mappings: { dynamic: false } } |
| arg | mtp-open-data | |
| arg | yellow-taxi | |
| arg | { mappings: { dynamic: "false" } } | |
And I successfully call the route "collection":"getMapping" with args:
| index | "mtp-open-data" |
| collection | "yellow-taxi" |
Expand Down
35 changes: 0 additions & 35 deletions features/Document.feature
Original file line number Diff line number Diff line change
@@ -1,40 +1,5 @@
Feature: Document Management

# document:create ============================================================

@mappings
Scenario: Creates a document
Given an existing collection "nyc-open-data":"yellow-taxi"
When I run the command "document:create" with:
| arg | nyc-open-data | |
| arg | yellow-taxi | |
| flag | --id | chuon-chuon-kim |
| flag | --body | { "my": "name" } |
Then The document "chuon-chuon-kim" content match:
| my | "name" |
When I run the command "document:create" with:
| arg | nyc-open-data | |
| arg | yellow-taxi | |
| flag | --id | chuon-chuon-kim |
| flag | --body | { "my": "other name" } |
| flag | --replace | |
Then The document "chuon-chuon-kim" content match:
| my | "other name" |

# document:get ===============================================================

@mappings
Scenario: Gets a document
Given an existing collection "nyc-open-data":"yellow-taxi"
And I create the following document:
| _id | "chuon-chuon-kim" |
| body | {} |
When I run the command "document:get" with args:
| "nyc-open-data" |
| "yellow-taxi" |
| "chuon-chuon-kim" |
Then I should match stdout with "chuon-chuon-kim"

# document:search ============================================================

@mappings
Expand Down
6 changes: 4 additions & 2 deletions features/support/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ async function resetSecurityDefault(sdk) {
controller: 'admin',
action: 'loadSecurities',
body: testSecurities,
refresh: 'wait_for'
refresh: 'wait_for',
onExistingUsers: 'overwrite'
});

await sdk.auth.login(
Expand All @@ -46,7 +47,8 @@ BeforeAll(({ timeout: 10 * 1000 }), async function () {
controller: 'admin',
action: 'loadSecurities',
body: testSecurities,
refresh: 'wait_for'
refresh: 'wait_for',
onExistingUsers: 'overwrite'
});

world.sdk.disconnect();
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@
"sdk": {
"description": "directly manipulate the sdk"
}
},
"hooks": {
"command_not_found": "./lib/hooks/command_not_found/api-method"
}
},
"repository": "kuzzleio/kourou",
Expand All @@ -117,4 +120,4 @@
"test:functional:cucumber": "./node_modules/.bin/cucumber-js"
},
"types": "lib/index.d.ts"
}
}
11 changes: 4 additions & 7 deletions src/commands/collection/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,27 @@ export default class CollectionCreate extends Kommand {

static flags = {
help: flags.help(),
body: flags.string({
description: 'Collection mappings and settings in JS or JSON format. Will be read from STDIN if available',
default: '{}'
}),
...kuzzleFlags
}

static args = [
{ name: 'index', description: 'Index name', required: true },
{ name: 'collection', description: 'Collection name', required: true }
{ name: 'collection', description: 'Collection name', required: true },
{ name: 'body', description: 'Collection mappings and settings in JS or JSON format. Will be read from STDIN if available' },
]

static readStdin = true

async runSafe() {
const body = this.stdin ? this.parseJs(this.stdin) : this.parseJs(this.flags.body)
const body = this.stdin ? this.stdin : this.args.body || '{}'

if (!await this.sdk?.index.exists(this.args.index)) {
await this.sdk?.index.create(this.args.index)

this.logInfo(`Index "${this.args.index}" created`)
}

await this.sdk?.collection.create(this.args.index, this.args.collection, body)
await this.sdk?.collection.create(this.args.index, this.args.collection, this.parseJs(body))

this.logOk(`Collection "${this.args.index}":"${this.args.collection}" created`)
}
Expand Down
60 changes: 0 additions & 60 deletions src/commands/document/create.ts

This file was deleted.

28 changes: 0 additions & 28 deletions src/commands/document/get.ts

This file was deleted.

Loading

0 comments on commit 7e87476

Please sign in to comment.