@adobe/aio-cli-plugin-app-storage 1.1.0 → 1.2.0-pre.2025-11-18.sha-9c4079ac

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +665 -1
  2. package/package.json +33 -6
  3. package/src/BaseCommand.js +11 -58
  4. package/src/DBBaseCommand.js +112 -0
  5. package/src/StateBaseCommand.js +87 -0
  6. package/src/commands/app/add/db.js +20 -0
  7. package/src/commands/app/db/collection/create.js +119 -0
  8. package/src/commands/app/db/collection/drop.js +90 -0
  9. package/src/commands/app/db/collection/list.js +100 -0
  10. package/src/commands/app/db/collection/rename.js +98 -0
  11. package/src/commands/app/db/collection/stats.js +94 -0
  12. package/src/commands/app/db/delete.js +89 -0
  13. package/src/commands/app/db/document/count.js +96 -0
  14. package/src/commands/app/db/document/delete.js +95 -0
  15. package/src/commands/app/db/document/find.js +133 -0
  16. package/src/commands/app/db/document/insert.js +147 -0
  17. package/src/commands/app/db/document/replace.js +122 -0
  18. package/src/commands/app/db/document/update.js +144 -0
  19. package/src/commands/app/db/index/create.js +170 -0
  20. package/src/commands/app/db/index/drop.js +87 -0
  21. package/src/commands/app/db/index/list.js +82 -0
  22. package/src/commands/app/db/ping.js +77 -0
  23. package/src/commands/app/db/provision.js +190 -0
  24. package/src/commands/app/db/stats.js +87 -0
  25. package/src/commands/app/db/status.js +159 -0
  26. package/src/commands/app/state/delete.js +3 -3
  27. package/src/commands/app/state/get.js +2 -2
  28. package/src/commands/app/state/list.js +3 -3
  29. package/src/commands/app/state/put.js +4 -4
  30. package/src/commands/app/state/stats.js +2 -2
  31. package/src/constants/db.js +32 -0
  32. package/src/constants/global.js +14 -0
  33. package/src/{constants.js → constants/state.js} +3 -0
  34. package/src/utils/inputValidation.js +74 -0
  35. package/src/utils/output.js +35 -0
  36. package/oclif.manifest.json +0 -311
@@ -0,0 +1,100 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { DBBaseCommand } from '../../../../DBBaseCommand.js'
14
+ import chalk from 'chalk'
15
+ import { Flags } from '@oclif/core'
16
+ import { prettyJson } from '../../../../utils/output.js'
17
+ import { makeTable } from '@oclif/table'
18
+
19
+ export class List extends DBBaseCommand {
20
+ async run () {
21
+ const { info } = this.flags
22
+ try {
23
+ this.log(chalk.blue('Fetching collections...'))
24
+
25
+ const client = await this.db.connect()
26
+ const collectionInfo = await client.listCollections()
27
+
28
+ this.debugLogger?.info?.(`Retrieved ${collectionInfo.length} collections:`, collectionInfo)
29
+
30
+ this.log(chalk.green('Collection Information:'))
31
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
32
+
33
+ if (collectionInfo && collectionInfo.length > 0) {
34
+ this.log(chalk.dim(` Total Collections: ${collectionInfo.length}`))
35
+
36
+ const formattedInfo = collectionInfo.map(col => {
37
+ const colInfo = {
38
+ name: col.name
39
+ }
40
+ if (info) {
41
+ colInfo.idIndex = `key: ${JSON.stringify(col.idIndex.key)}\nname: ${col.idIndex.name}`
42
+ colInfo.info = Object.entries(col.info).map(([key, value]) => {
43
+ return `${key}: ${JSON.stringify(value)}`
44
+ }).join('\n')
45
+
46
+ if (col.options?.validator) {
47
+ colInfo.validator = prettyJson(col.options.validator.$jsonSchema, 0)
48
+ }
49
+ if (col.options?.validationLevel) {
50
+ colInfo.validationLevel = prettyJson(col.options.validationLevel, 0)
51
+ }
52
+ if (col.options?.validationAction) {
53
+ colInfo.validationAction = prettyJson(col.options.validationAction, 0)
54
+ }
55
+ }
56
+
57
+ return colInfo
58
+ })
59
+ const table = makeTable({ data: formattedInfo, overflow: 'wrap', trimWhitespace: false })
60
+ this.log(' ' + table.replaceAll('\n', '\n ').trimEnd())
61
+ } else {
62
+ this.log(chalk.dim(' No collections found'))
63
+ }
64
+
65
+ this.log(chalk.dim(`\n Retrieved: ${new Date().toLocaleString()}`))
66
+
67
+ return info ? collectionInfo : collectionInfo.map(col => col.name)
68
+ } catch (error) {
69
+ this.debugLogger?.error?.('Error fetching collections', error)
70
+
71
+ this.log(chalk.red('Error fetching collections'))
72
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
73
+ this.log(chalk.dim(` Error: ${error.message}`))
74
+
75
+ this.error(`Failed to fetch collections: ${error.message}`)
76
+ }
77
+ }
78
+ }
79
+
80
+ List.description = 'Get the list of collections in your App Builder database'
81
+
82
+ List.examples = [
83
+ '$ aio app db collection list',
84
+ '$ aio app db collection list --info',
85
+ '$ aio app db collection list --json',
86
+ '$ aio app db col list --info --json'
87
+ ]
88
+
89
+ List.flags = {
90
+ ...DBBaseCommand.flags,
91
+ info: Flags.boolean({
92
+ char: 'i',
93
+ description: 'Show detailed collection information instead of just names',
94
+ default: false
95
+ })
96
+ }
97
+
98
+ List.args = {}
99
+
100
+ List.aliases = ['app:db:col:list', 'app:db:show:collections']
@@ -0,0 +1,98 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { DBBaseCommand } from '../../../../DBBaseCommand.js'
14
+ import { Args } from '@oclif/core'
15
+ import chalk from 'chalk'
16
+ import { isNonEmptyString } from '../../../../utils/inputValidation.js'
17
+ import { prettyJson } from '../../../../utils/output.js'
18
+
19
+ export class RenameCollection extends DBBaseCommand {
20
+ async run () {
21
+ const { currentName, newName } = this.args
22
+
23
+ try {
24
+ this.log(chalk.blue(`Renaming collection '${currentName}' to '${newName}'...`))
25
+
26
+ const client = await this.db.connect()
27
+
28
+ // Get the collection object
29
+ const collection = client.collection(currentName)
30
+
31
+ // Rename the collection
32
+ const result = await collection.renameCollection(newName)
33
+
34
+ this.debugLogger?.info?.('Collection renamed successfully:', result)
35
+
36
+ const response = {
37
+ currentName,
38
+ newName,
39
+ status: 'renamed',
40
+ namespace: this.rtNamespace,
41
+ timestamp: new Date().toISOString(),
42
+ result
43
+ }
44
+
45
+ this.log(chalk.green(`Collection '${currentName}' renamed to '${newName}' successfully`))
46
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
47
+
48
+ if (result && typeof result === 'object' && Object.keys(result).length > 0) {
49
+ this.log(chalk.dim(` Details:\n${prettyJson(result)}`))
50
+ }
51
+
52
+ this.log(chalk.dim(` Renamed: ${new Date().toLocaleString()}`))
53
+
54
+ return response
55
+ } catch (error) {
56
+ this.debugLogger?.error?.('Error renaming collection:', error)
57
+
58
+ const errorMessage = `Failed to rename collection '${currentName}': ${error.message}`
59
+
60
+ this.log(chalk.red('Failed to rename collection'))
61
+ this.log(chalk.dim(` Current: ${currentName}`))
62
+ this.log(chalk.dim(` New: ${newName}`))
63
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
64
+ this.log(chalk.dim(` Error: ${error.message}`))
65
+
66
+ this.error(errorMessage)
67
+ }
68
+ }
69
+ }
70
+
71
+ RenameCollection.description = 'Rename a collection in the database'
72
+
73
+ RenameCollection.examples = [
74
+ '$ aio app db collection rename users customers',
75
+ '$ aio app db collection rename old_products new_products --json',
76
+ '$ aio app db col rename inventory stock'
77
+ ]
78
+
79
+ RenameCollection.args = {
80
+ currentName: Args.string({
81
+ name: 'currentName',
82
+ description: 'The current name of the collection to rename',
83
+ required: true,
84
+ parse: input => isNonEmptyString(input, 'Current collection name')
85
+ }),
86
+ newName: Args.string({
87
+ name: 'newName',
88
+ description: 'The new name for the collection',
89
+ required: true,
90
+ parse: input => isNonEmptyString(input, 'New collection name')
91
+ })
92
+ }
93
+
94
+ RenameCollection.flags = {
95
+ ...DBBaseCommand.flags
96
+ }
97
+
98
+ RenameCollection.aliases = ['app:db:col:rename']
@@ -0,0 +1,94 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { DBBaseCommand } from '../../../../DBBaseCommand.js'
14
+ import { Args } from '@oclif/core'
15
+ import chalk from 'chalk'
16
+ import { isNonEmptyString } from '../../../../utils/inputValidation.js'
17
+ import { prettyJson } from '../../../../utils/output.js'
18
+
19
+ export class StatsCollection extends DBBaseCommand {
20
+ async run () {
21
+ const { collection } = this.args
22
+
23
+ try {
24
+ this.log(chalk.blue(`Getting stats for collection '${collection}'...`))
25
+
26
+ const client = await this.db.connect()
27
+
28
+ // Get the collection object
29
+ const coll = client.collection(collection)
30
+
31
+ // Get collection-level statistics
32
+ const stats = await coll.stats()
33
+
34
+ this.debugLogger?.info?.('Collection stats retrieved successfully:', stats)
35
+
36
+ const response = {
37
+ collection,
38
+ stats,
39
+ namespace: this.rtNamespace,
40
+ timestamp: new Date().toISOString()
41
+ }
42
+
43
+ this.log(chalk.green(`Stats for collection '${collection}':`))
44
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
45
+
46
+ // Display stats in a formatted way
47
+ Object.entries(stats).forEach(([key, value]) => {
48
+ if (typeof value === 'object' && value !== null) {
49
+ this.log(chalk.dim(` ${key}:\n${prettyJson(value)}`))
50
+ } else {
51
+ this.log(chalk.dim(` ${key}: ${value}`))
52
+ }
53
+ })
54
+
55
+ this.log(chalk.dim(` Retrieved: ${new Date().toLocaleString()}`))
56
+
57
+ return response
58
+ } catch (error) {
59
+ this.debugLogger?.error?.('Error getting collection stats:', error)
60
+
61
+ const errorMessage = `Failed to get stats for collection '${collection}': ${error.message}`
62
+
63
+ this.log(chalk.red('Failed to get collection stats'))
64
+ this.log(chalk.dim(` Collection: ${collection}`))
65
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
66
+ this.log(chalk.dim(` Error: ${error.message}`))
67
+
68
+ this.error(errorMessage)
69
+ }
70
+ }
71
+ }
72
+
73
+ StatsCollection.description = 'Get statistics for a collection in the database'
74
+
75
+ StatsCollection.examples = [
76
+ '$ aio app db collection stats users',
77
+ '$ aio app db collection stats products --json',
78
+ '$ aio app db col stats inventory'
79
+ ]
80
+
81
+ StatsCollection.args = {
82
+ collection: Args.string({
83
+ name: 'collection',
84
+ description: 'The name of the collection to get stats for',
85
+ required: true,
86
+ parse: input => isNonEmptyString(input, 'Collection name')
87
+ })
88
+ }
89
+
90
+ StatsCollection.flags = {
91
+ ...DBBaseCommand.flags
92
+ }
93
+
94
+ StatsCollection.aliases = ['app:db:col:stats']
@@ -0,0 +1,89 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { DBBaseCommand } from '../../../DBBaseCommand.js'
14
+ import chalk from 'chalk'
15
+ import { Flags } from '@oclif/core'
16
+ import { DB_STATUS } from '../../../constants/db.js'
17
+ import { isProductionNamespace } from '../../../utils/inputValidation.js'
18
+
19
+ export class DeleteDb extends DBBaseCommand {
20
+ async run () {
21
+ const namespace = this.rtNamespace
22
+
23
+ try {
24
+ // Check if the namespace is a production namespace
25
+ if (isProductionNamespace(namespace)) {
26
+ this.error('A production database may not be deleted directly. Please contact the App Builder team to have this database deleted.')
27
+ }
28
+
29
+ // eslint-disable-next-line node/no-unsupported-features/es-syntax
30
+ const { input } = await import('@inquirer/prompts')
31
+
32
+ if (!this.flags.force) {
33
+ process.stderr.write(chalk.red('❌ CAUTION, This action cannot be reverted and all stored data will be lost.') + '\n')
34
+
35
+ const res = await input({
36
+ message: chalk.yellow(`confirm deletion by typing: '${namespace}'`)
37
+ })
38
+ if (res !== namespace) {
39
+ return this.error('confirmation did not match, aborted')
40
+ }
41
+ }
42
+
43
+ this.log(chalk.blue(`Proceeding to delete the database for the namespace: '${namespace}'...`))
44
+
45
+ const deleteResult = await this.db.deleteDatabase()
46
+ this.debugLogger?.info?.('Delete request result:', deleteResult)
47
+
48
+ const deleteStatus = deleteResult?.status?.toUpperCase() || DB_STATUS.UNKNOWN
49
+
50
+ if (deleteStatus === DB_STATUS.DELETED) {
51
+ this.log(chalk.green('Database deleted successfully'))
52
+ this.log(chalk.dim('Check database status: aio app db status'))
53
+ } else {
54
+ this.warn(`Delete request returned status '${deleteStatus}'`)
55
+ this.warn('If the issue persists, please contact the App Builder team.')
56
+ }
57
+
58
+ const result = {
59
+ status: deleteStatus,
60
+ namespace,
61
+ timestamp: new Date().toISOString(),
62
+ details: deleteResult
63
+ }
64
+
65
+ return result
66
+ } catch (error) {
67
+ this.debugLogger?.error?.('Delete command error:', error)
68
+ this.error(`Database deletion failed: ${error.message}`)
69
+ }
70
+ }
71
+ }
72
+
73
+ DeleteDb.description = 'Delete the database for your App Builder application (non-production only)'
74
+
75
+ DeleteDb.examples = [
76
+ '$ aio app db delete',
77
+ '$ aio app db delete --force',
78
+ '$ aio app db delete --json'
79
+ ]
80
+
81
+ DeleteDb.flags = {
82
+ ...DBBaseCommand.flags,
83
+ force: Flags.boolean({
84
+ description: '[use with caution!] force delete, skips confirmation safety prompt',
85
+ default: false
86
+ })
87
+ }
88
+
89
+ DeleteDb.args = {}
@@ -0,0 +1,96 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { DBBaseCommand } from '../../../../DBBaseCommand.js'
14
+ import { Args } from '@oclif/core'
15
+ import chalk from 'chalk'
16
+ import { asObject, isNonEmptyString } from '../../../../utils/inputValidation.js'
17
+
18
+ export class Count extends DBBaseCommand {
19
+ async run () {
20
+ const { collection, query } = this.args
21
+
22
+ try {
23
+ this.log(chalk.blue(`Counting documents in collection '${collection}'...`))
24
+
25
+ if (query) {
26
+ this.log(chalk.dim(` Using query filter: ${JSON.stringify(query)}`))
27
+ }
28
+
29
+ const client = await this.db.connect()
30
+ const coll = client.collection(collection)
31
+
32
+ // Count documents
33
+ const count = await coll.countDocuments(query || {}, {})
34
+
35
+ this.debugLogger?.info?.('Document count:', count)
36
+
37
+ const response = {
38
+ collection,
39
+ query: query || {},
40
+ count,
41
+ namespace: this.rtNamespace,
42
+ timestamp: new Date().toISOString()
43
+ }
44
+
45
+ this.log(chalk.green(`Found ${count} document(s) in collection '${collection}'`))
46
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
47
+
48
+ if (query && Object.keys(query).length > 0) {
49
+ this.log(chalk.dim(' Query filter applied: Yes'))
50
+ }
51
+
52
+ this.log(chalk.dim(` Counted: ${new Date().toLocaleString()}`))
53
+
54
+ return response
55
+ } catch (error) {
56
+ this.debugLogger?.error?.('Error counting documents:', error)
57
+
58
+ const errorMessage = `Failed to count documents in collection '${collection}': ${error.message}`
59
+
60
+ this.log(chalk.red('Failed to count documents'))
61
+ this.log(chalk.dim(` Collection: ${collection}`))
62
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
63
+ this.error(errorMessage)
64
+ }
65
+ }
66
+ }
67
+
68
+ Count.description = 'Count documents in a collection'
69
+
70
+ Count.examples = [
71
+ '$ aio app db document countDocuments users',
72
+ '$ aio app db document countDocuments users \'{"age": {"$gte": 21}}\'',
73
+ '$ aio app db document countDocuments products \'{"category": "electronics"}\' --json',
74
+ '$ aio app db doc count orders \'{"status": "shipped"}\''
75
+ ]
76
+
77
+ Count.args = {
78
+ collection: Args.string({
79
+ name: 'collection',
80
+ description: 'The name of the collection',
81
+ required: true,
82
+ parse: input => isNonEmptyString(input, 'Collection name')
83
+ }),
84
+ query: Args.string({
85
+ name: 'query',
86
+ description: 'The query filter document (JSON string). If not provided, counts all documents.',
87
+ required: false,
88
+ parse: input => asObject(input, 'Query')
89
+ })
90
+ }
91
+
92
+ Count.flags = {
93
+ ...DBBaseCommand.flags
94
+ }
95
+
96
+ Count.aliases = ['app:db:doc:count']
@@ -0,0 +1,95 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { DBBaseCommand } from '../../../../DBBaseCommand.js'
14
+ import { Args } from '@oclif/core'
15
+ import chalk from 'chalk'
16
+ import { asObject, isNonEmptyString } from '../../../../utils/inputValidation.js'
17
+
18
+ export class Delete extends DBBaseCommand {
19
+ async run () {
20
+ const { collection, filter } = this.args
21
+
22
+ try {
23
+ this.log(chalk.blue(`Deleting document from collection '${collection}'...`))
24
+
25
+ const client = await this.db.connect()
26
+ const coll = client.collection(collection)
27
+
28
+ // Delete the document
29
+ const result = await coll.deleteOne(filter)
30
+
31
+ this.debugLogger?.info?.('Document deleted successfully:', result)
32
+
33
+ const response = {
34
+ collection,
35
+ filter,
36
+ deletedCount: result.deletedCount,
37
+ acknowledged: result.acknowledged,
38
+ namespace: this.rtNamespace,
39
+ timestamp: new Date().toISOString(),
40
+ result
41
+ }
42
+
43
+ if (result.deletedCount > 0) {
44
+ this.log(chalk.green(`Document deleted successfully from collection '${collection}'`))
45
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
46
+ } else {
47
+ this.log(chalk.yellow(`No document found in collection '${collection}' matching the filter`))
48
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
49
+ }
50
+
51
+ this.log(chalk.dim(` Deleted: ${new Date().toLocaleString()}`))
52
+
53
+ return response
54
+ } catch (error) {
55
+ this.debugLogger?.error?.('Error deleting document:', error)
56
+
57
+ const errorMessage = `Failed to delete document from collection '${collection}': ${error.message}`
58
+
59
+ this.log(chalk.red('Failed to delete document'))
60
+ this.log(chalk.dim(` Collection: ${collection}`))
61
+ this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
62
+
63
+ this.error(errorMessage)
64
+ }
65
+ }
66
+ }
67
+
68
+ Delete.description = 'Delete a single document from a collection'
69
+
70
+ Delete.examples = [
71
+ '$ aio app db document delete users \'{"name": "John"}\'',
72
+ '$ aio app db document delete products \'{"id": "123"}\' --json',
73
+ '$ aio app db doc delete posts \'{"status": "draft"}\''
74
+ ]
75
+
76
+ Delete.args = {
77
+ collection: Args.string({
78
+ name: 'collection',
79
+ description: 'The name of the collection',
80
+ required: true,
81
+ parse: input => isNonEmptyString(input, 'Collection name')
82
+ }),
83
+ filter: Args.string({
84
+ name: 'filter',
85
+ description: 'The filter document (JSON string)',
86
+ required: true,
87
+ parse: input => asObject(input, 'Filter')
88
+ })
89
+ }
90
+
91
+ Delete.flags = {
92
+ ...DBBaseCommand.flags
93
+ }
94
+
95
+ Delete.aliases = ['app:db:doc:delete']