feat: implement GraphQL write interface with mutations (issue #10)
Some checks failed
Test Suite / performance-tests (push) Has been cancelled
Test Suite / unit-tests (3.11) (push) Has been cancelled
Test Suite / unit-tests (3.12) (push) Has been cancelled
Test Suite / integration-tests (push) Has been cancelled
Test Suite / e2e-tests (push) Has been cancelled
Test Suite / code-quality (push) Has been cancelled
Test Suite / security-scan (push) Has been cancelled
Test Suite / test-summary (push) Has been cancelled

Added comprehensive GraphQL mutations for CRUD operations on markdown files and schemas.

Key features:
- Complete mutation schema with structured payload types
- Markdown file mutations: add, update with front matter support
- Schema mutations: add, update, delete with JSON validation
- CLI integration with `graphql-mutate` command
- Comprehensive error handling and validation
- Full test coverage with 24 test cases
- Updated documentation with mutation examples and API usage

Resolves issue #10: Expose a GraphQL Write Interface

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-03 16:48:03 +02:00
parent d4e5992213
commit 2a15dde228
6 changed files with 2084 additions and 8 deletions

View File

@@ -5678,11 +5678,123 @@ markitect graphql-serve --port 5000
# Query running server
markitect graphql-query "{ markdownFiles { filename } }" \\
--endpoint http://localhost:5000/graphql
🛠️ Mutation Examples (Write Operations):
# Add a new markdown file
markitect graphql-mutate \\
'mutation { addMarkdownFile(filename: "new-doc.md", content: "# New Document\\n\\nContent here") { success markdownFile { id filename } errors } }' \\
--local
# Update existing file
markitect graphql-mutate \\
'mutation { updateMarkdownFile(id: 1, content: "# Updated\\n\\nNew content") { success errors } }' \\
--local
# Add a JSON schema
markitect graphql-mutate \\
'mutation { addSchema(filename: "user-schema.json", schemaContent: "{\\"type\\": \\"object\\", \\"properties\\": {\\"name\\": {\\"type\\": \\"string\\"}}}") { success schema { id title } errors } }' \\
--local
# Delete a schema
markitect graphql-mutate \\
'mutation { deleteSchema(filename: "old-schema.json") { success deletedFilename errors } }' \\
--local
💡 Access GraphQL Playground at http://localhost:5000/graphql when server is running
"""
click.echo(examples)
@cli.command(name='graphql-mutate')
@click.argument('mutation', required=True)
@click.option('--variables', default='{}', help='JSON string of mutation variables')
@click.option('--endpoint', default='http://localhost:5000/graphql', help='GraphQL endpoint URL')
@click.option('--local', is_flag=True, help='Execute mutation locally without HTTP')
@click.option('--format', 'output_format', type=click.Choice(['json', 'yaml', 'table']),
default='json', help='Output format')
@pass_config
def graphql_mutate(config, mutation, variables, endpoint, local, output_format):
"""Execute GraphQL mutations for write operations.
Execute GraphQL mutations to add, update, or delete data in MarkiTect.
Supports both local and remote execution modes.
Examples:
# Add a new markdown file locally
markitect graphql-mutate 'mutation { addMarkdownFile(filename: "test.md", content: "# Test\\nContent") { success markdown_file { id filename } } }' --local
# Update an existing file
markitect graphql-mutate 'mutation { updateMarkdownFile(id: 1, content: "# Updated\\nContent") { success errors } }' --local
# Add a schema with variables
markitect graphql-mutate 'mutation($filename: String!, $content: JSONString!) { addSchema(filename: $filename, schemaContent: $content) { success schema { id title } } }' --variables '{"filename": "test.json", "content": "{\\"type\\": \\"object\\"}"}' --local
"""
import sys
import json
import yaml
try:
# Parse variables
try:
mutation_variables = json.loads(variables) if variables != '{}' else {}
except json.JSONDecodeError:
click.echo("❌ Invalid JSON in variables parameter", err=True)
sys.exit(1)
if local:
# Execute locally using the GraphQL client
try:
from .graphql import GraphQLClient
client = GraphQLClient()
result = client.execute_local(mutation, variables=mutation_variables)
except ImportError as e:
click.echo(f"❌ Missing dependency: {e}", err=True)
sys.exit(1)
else:
# Execute remotely
try:
from .graphql import GraphQLClient
client = GraphQLClient(endpoint)
result = client.execute(mutation, variables=mutation_variables)
except ImportError as e:
click.echo(f"❌ Missing dependency: {e}", err=True)
sys.exit(1)
# Format and display output
if output_format == 'json':
click.echo(json.dumps(result, indent=2))
elif output_format == 'yaml':
click.echo(yaml.dump(result, default_flow_style=False))
elif output_format == 'table':
# For mutations, simple table output
if result.get('data'):
click.echo("Mutation Result:")
for key, value in result['data'].items():
if isinstance(value, dict):
click.echo(f" {key}:")
for sub_key, sub_value in value.items():
click.echo(f" {sub_key}: {sub_value}")
else:
click.echo(f" {key}: {value}")
if result.get('errors'):
click.echo("Errors:")
for error in result['errors']:
click.echo(f" - {error.get('message', error)}")
except ImportError as e:
click.echo(f"❌ Missing dependency: {e}", err=True)
sys.exit(1)
except Exception as e:
click.echo(f"❌ Failed to execute mutation: {e}", err=True)
if config.get('verbose'):
import traceback
click.echo(traceback.format_exc(), err=True)
sys.exit(1)
# Register issue management commands
cli.add_command(issues_group)