Skip to main content
Thank you for your interest in contributing to Queryly! This guide will help you get started with development and submit your first contribution.

Ways to Contribute

There are many ways to contribute to Queryly:

Report Bugs

Open an issue with details and reproduction steps

Suggest Features

Share your ideas for new functionality

Submit Pull Requests

Fix bugs or add features

Improve Documentation

Help make the docs clearer

Getting Started

Prerequisites

Before you begin, ensure you have the following installed:
  • .NET 8.0 SDK or later - Download
  • Git - Download
  • A code editor - Visual Studio, VS Code, or Rider recommended

Development Setup

1
Fork the repository
2
Visit github.com/Ayine-nongre/queryly and click the “Fork” button.
3
Clone your fork
4
git clone https://github.com/YOUR-USERNAME/queryly.git
cd queryly
5
Add upstream remote
6
git remote add upstream https://github.com/Ayine-nongre/queryly.git
7
Restore dependencies
8
dotnet restore
9
Build the project
10
dotnet build
11
You should see a successful build output.
12
Run tests
13
dotnet test
14
Ensure all tests pass before making changes.
15
Run Queryly
16
dotnet run --project src/Queryly.CLI/Queryly.CLI.csproj
17
You should see the Queryly CLI output.

Development Workflow

1. Create a Feature Branch

Always create a new branch for your work:
git checkout -b feature/your-feature-name
Branch naming conventions:
  • feature/ - New features
  • fix/ - Bug fixes
  • docs/ - Documentation changes
  • refactor/ - Code refactoring

2. Make Your Changes

Edit the code, following our coding standards.

3. Test Your Changes

Run tests frequently during development:
# Run all tests
dotnet test

# Run specific test file
dotnet test --filter "FullyQualifiedName~SqliteConnectionProviderTests"

# Run with verbose output
dotnet test -v detailed

4. Commit Your Changes

Write clear, concise commit messages:
git add .
git commit -m "Add support for MySQL connection pooling"
Good commit messages:
  • Add support for table indexes in schema view
  • Fix connection leak in PostgreSQL provider
  • Update documentation for connection strings
Avoid:
  • Fixed stuff
  • WIP
  • Update

5. Keep Your Branch Updated

Regularly sync with the upstream repository:
git fetch upstream
git rebase upstream/main

6. Push Your Branch

git push origin feature/your-feature-name

7. Create a Pull Request

Go to your fork on GitHub and click “New Pull Request”. Pull Request Guidelines:
  • Provide a clear title and description
  • Reference any related issues (e.g., “Fixes #123”)
  • Include screenshots for UI changes
  • Ensure all tests pass
  • Wait for code review feedback

Coding Standards

C# Style Guide

We follow standard C# conventions:

Naming Conventions

// Classes and interfaces - PascalCase
public class ConnectionManager { }
public interface IConnectionProvider { }

// Methods - PascalCase
public async Task OpenConnectionAsync() { }

// Properties - PascalCase
public string ConnectionString { get; set; }

// Private fields - camelCase with underscore
private string _connectionString;

// Local variables - camelCase
var tableName = "users";

// Constants - PascalCase
public const int MaxRetries = 3;

File Organization

// 1. Using statements
using System.Data.Common;
using Microsoft.Data.Sqlite;

// 2. Namespace
namespace Queryly.Providers.Sqlite;

// 3. Class definition
public class SqliteConnectionProvider : IConnectionProvider
{
    // 4. Fields
    private readonly string _connectionString;
    
    // 5. Properties
    public DatabaseType Type => DatabaseType.SQLite;
    
    // 6. Constructors
    public SqliteConnectionProvider(string connectionString)
    {
        _connectionString = connectionString;
    }
    
    // 7. Public methods
    public async Task<DbConnection> OpenConnectionAsync()
    {
        // Implementation
    }
    
    // 8. Private methods
    private void ValidateConnectionString()
    {
        // Implementation
    }
}

Async/Await

Always use async/await for I/O operations:
// Good
public async Task<List<TableInfo>> GetTablesAsync(DbConnection connection)
{
    var tables = new List<TableInfo>();
    using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        // Process data
    }
    return tables;
}

// Avoid
public List<TableInfo> GetTables(DbConnection connection)
{
    // Synchronous database access
}

Error Handling

Provide meaningful error messages:
// Good
try
{
    await connection.OpenAsync();
}
catch (SqliteException ex)
{
    throw new ConnectionException(
        $"Failed to open SQLite database at '{filePath}': {ex.Message}", 
        ex
    );
}

// Avoid
catch (Exception ex)
{
    throw new Exception("Error", ex);
}

Resource Management

Always dispose of resources:
// Good
using var connection = new SqliteConnection(connectionString);
await connection.OpenAsync();

// Also good
using (var connection = new SqliteConnection(connectionString))
{
    await connection.OpenAsync();
    // Use connection
}

Code Documentation

Document public APIs with XML comments:
/// <summary>
/// Opens a connection to the database using the provided connection string.
/// </summary>
/// <param name="connectionString">The database connection string.</param>
/// <returns>An open database connection.</returns>
/// <exception cref="ArgumentException">Thrown when connection string is null or empty.</exception>
/// <exception cref="ConnectionException">Thrown when connection fails.</exception>
public async Task<DbConnection> OpenConnectionAsync(string connectionString)
{
    // Implementation
}

Testing Guidelines

Writing Tests

We use xUnit for testing. Place tests in tests/Queryly.Tests/.

Test Structure

using Xunit;
using FluentAssertions;

namespace Queryly.Tests.Providers;

public class SqliteConnectionProviderTests
{
    [Fact]
    public async Task OpenConnectionAsync_WithValidConnectionString_ReturnsOpenConnection()
    {
        // Arrange
        var provider = new SqliteConnectionProvider();
        var connectionString = "Data Source=:memory:";
        
        // Act
        var connection = await provider.OpenConnectionAsync(connectionString);
        
        // Assert
        connection.Should().NotBeNull();
        connection.State.Should().Be(ConnectionState.Open);
        
        // Cleanup
        await connection.DisposeAsync();
    }
    
    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public async Task OpenConnectionAsync_WithInvalidConnectionString_ThrowsException(
        string connectionString)
    {
        // Arrange
        var provider = new SqliteConnectionProvider();
        
        // Act & Assert
        await Assert.ThrowsAsync<ArgumentException>(
            () => provider.OpenConnectionAsync(connectionString)
        );
    }
}

Test Naming Convention

Use the pattern: MethodName_Scenario_ExpectedResult Examples:
  • GetTablesAsync_WithEmptyDatabase_ReturnsEmptyList
  • TestConnectionAsync_WithInvalidHost_ReturnsFalse
  • GetColumnsAsync_WithValidTable_ReturnsColumnList

Running Specific Tests

# Run all tests in a class
dotnet test --filter "FullyQualifiedName~SqliteConnectionProviderTests"

# Run a specific test
dotnet test --filter "FullyQualifiedName~OpenConnectionAsync_WithValidConnectionString"

# Run tests with coverage
dotnet test /p:CollectCoverage=true

Project Structure

Understand the codebase organization:
queryly/
├── src/
│   ├── Queryly.CLI/              # CLI interface
│   │   ├── Commands/             # Command implementations
│   │   │   ├── ConnectCommands/  # Connection commands
│   │   │   ├── SchemaCommands/   # Schema commands
│   │   │   └── DataCommands/     # Data commands
│   │   ├── Configuration/        # Config helpers
│   │   └── Program.cs            # Entry point
│   ├── Queryly.Core/             # Business logic
│   │   ├── Models/               # Data models
│   │   ├── Connections/          # Connection interfaces
│   │   ├── Query/                # Query execution
│   │   └── Exceptions/           # Custom exceptions
│   └── Queryly.Providers/        # Database providers
│       ├── Sqlite/               # SQLite
│       ├── SqlServer/            # SQL Server
│       ├── PostgreSql/           # PostgreSQL
│       └── MySql/                # MySQL
├── tests/
│   └── Queryly.Tests/            # Unit tests
├── docs/                         # Documentation
└── README.md                     # Main readme

Finding Issues to Work On

Good First Issues

Look for issues labeled good-first-issue on GitHub: View Good First Issues

Help Wanted

Issues labeled help-wanted are ready for contributions: View Help Wanted Issues

Suggesting New Features

Before suggesting a feature:
  1. Check existing issues to avoid duplicates
  2. Clearly describe the use case
  3. Explain why it benefits Queryly users

Pull Request Process

1
Submit your PR
2
Create a pull request from your fork to the main repository.
3
Automated checks
4
GitHub Actions will run:
5
  • Build verification
  • Unit tests
  • Code style checks
  • 6
    Code review
    7
    A maintainer will review your code and may request changes.
    8
    Address feedback
    9
    Make requested changes and push to your branch:
    10
    git add .
    git commit -m "Address review feedback"
    git push origin feature/your-feature-name
    
    11
    Approval and merge
    12
    Once approved, a maintainer will merge your PR.

    Build Commands Reference

    Essential Commands

    # Restore dependencies
    dotnet restore
    
    # Build entire solution
    dotnet build
    
    # Build specific project
    dotnet build src/Queryly.CLI/Queryly.CLI.csproj
    
    # Run all tests
    dotnet test
    
    # Run with detailed output
    dotnet test -v detailed
    
    # Run CLI
    dotnet run --project src/Queryly.CLI/Queryly.CLI.csproj
    
    # Clean build artifacts
    dotnet clean
    

    Publishing

    # Publish for current platform
    dotnet publish -c Release
    
    # Publish for specific platform
    dotnet publish -c Release -r win-x64
    dotnet publish -c Release -r linux-x64
    dotnet publish -c Release -r osx-x64
    

    Getting Help

    If you need help or have questions:

    GitHub Discussions

    Ask questions in GitHub Discussions

    GitHub Issues

    Report bugs or request features at GitHub Issues

    Contact the Maintainer

    Code of Conduct

    Be Respectful

    Treat all contributors with respect and kindness.

    Be Collaborative

    Work together to improve Queryly.

    Be Constructive

    Provide helpful feedback in code reviews.

    License

    By contributing to Queryly, you agree that your contributions will be licensed under the MIT License.

    Recognition

    All contributors are recognized in:
    • GitHub contributor list
    • Release notes
    • Project documentation
    Thank you for contributing to Queryly!

    Build docs developers (and LLMs) love