Code Examples

Data Model - EmployeeProps Click to view data model used in all examples
Tag with priority for categorization.
/// <summary>
/// Tag with priority for categorization.
/// </summary>
public class Tag
{
    public string Name { get; set; } = string.Empty;
    public int Priority { get; set; }
    public string? Description { get; set; }
}

/// <summary>
/// Project metrics for analytics.
/// </summary>
[RedbScheme("ProjectMetrics")]
public class ProjectMetricsProps
{
    public long ProjectId { get; set; }
    public long? TasksCompleted { get; set; }
    public long? TasksTotal { get; set; }
    public long? BugsFixed { get; set; }
    public double? Budget { get; set; }
    public long? TeamSize { get; set; }
    public Tag[]? Tags { get; set; }
    public string[]? Technologies { get; set; }
}

/// <summary>
/// Address with city, street and building details.
/// </summary>
public class Address
{
    public string City { get; set; } = string.Empty;
    public string Street { get; set; } = string.Empty;
    public BuildingInfo? Building { get; set; }
}

/// <summary>
/// Building information with floor and amenities.
/// </summary>
public class BuildingInfo
{
    public int Floor { get; set; }
    public string Name { get; set; } = string.Empty;
    public string[]? Amenities { get; set; }
    public int[]? AccessCodes { get; set; }
    public string[]? ParkingSpots { get; set; }
    public int[]? ElevatorFloors { get; set; }
}

/// <summary>
/// Contact detail key-value pair.
/// </summary>
public class ContactDetail
{
    public string Label { get; set; } = string.Empty;
    public string Value { get; set; } = string.Empty;
}

/// <summary>
/// Contact information (email, phone, etc).
/// </summary>
public class Contact
{
    public string Type { get; set; } = string.Empty;
    public string Value { get; set; } = string.Empty;
    public bool IsVerified { get; set; }
    public int[]? NotificationHours { get; set; }
    public ContactDetail[]? Metadata { get; set; }
}

/// <summary>
/// Department info with tags, metrics and nested budget data.
/// </summary>
public class Department
{
    public string Name { get; set; } = string.Empty;
    public int HeadCount { get; set; }
    public string[] Projects { get; set; } = [];
    public Tag[] Leaders { get; set; } = [];
    public Dictionary<string, int>? BudgetByYear { get; set; }
}

/// <summary>
/// Employee props - main model for examples.
/// Demonstrates all supported types:
/// - Simple types (int, string, DateTime, long, decimal)
/// - Arrays (string[], int[])
/// - Business classes (Address with nested BuildingInfo)
/// - Array of business classes (Contact[])
/// - RedbObject references (CurrentProject, PastProjects[])
/// - Dictionary types (various key and value types)
/// </summary>
[RedbScheme("Employee")]
public class EmployeeProps
{
    // Basic info
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public int Age { get; set; }
    public DateTime HireDate { get; set; }
    public string Position { get; set; } = string.Empty;
    public decimal Salary { get; set; }
    public string Department { get; set; } = string.Empty;
    public string? EmployeeCode { get; set; }

    // Skills and certifications (arrays)
    public string[]? Skills { get; set; }
    public int[]? SkillLevels { get; set; }
    public string[]? Certifications { get; set; }
    public int[]? CertificationYears { get; set; }

    // Addresses (business classes)
    public Address? HomeAddress { get; set; }
    public Address? WorkAddress { get; set; }
    public Address? EmergencyAddress { get; set; }

    // Contacts (array of business classes)
    public Contact[]? Contacts { get; set; }

    // Project references (RedbObject)
    public RedbObject<ProjectMetricsProps>? CurrentProject { get; set; }
    public RedbObject<ProjectMetricsProps>[]? PastProjects { get; set; }

    // Phone directory: extension -> phone number
    public Dictionary<string, string>? PhoneDirectory { get; set; }

    // Office locations by city
    public Dictionary<string, Address>? OfficeLocations { get; set; }

    // Bonus history by year
    public Dictionary<int, decimal>? BonusByYear { get; set; }

    // Department details with complex nested data (Pro)
    public Dictionary<string, Department>? DepartmentHistory { get; set; }

    // Composite key: (year, quarter) -> performance score (Pro)
    public Dictionary<(int Year, string Quarter), string>? PerformanceReviews { get; set; }

    // Project metrics by code (Pro)
    public Dictionary<string, RedbObject<ProjectMetricsProps>>? ProjectMetrics { get; set; }
}

/// <summary>
/// Department props for tree examples (corporate hierarchy).
/// Used with TreeRedbObject for organizational structure.
/// Similar to CategoryTestProps in ConsoleTest.
/// </summary>
[RedbScheme("Department")]
public class DepartmentProps
{
    /// <summary>Department name (e.g. "IT Department Moscow").</summary>
    public string Name { get; set; } = string.Empty;

    /// <summary>Description (e.g. "Software development team").</summary>
    public string Description { get; set; } = string.Empty;

    /// <summary>Is department active?</summary>
    public bool IsActive { get; set; } = true;

    /// <summary>Budget in USD.</summary>
    public decimal Budget { get; set; }

    /// <summary>Department code (e.g. "IT-MSK-DEV").</summary>
    public string Code { get; set; } = string.Empty;
}

/// <summary>
/// City props for list examples (linked objects).
/// Used as target object for RedbListItem.Object reference.
/// </summary>
[RedbScheme("City")]
public class CityProps
{
    /// <summary>City name.</summary>
    public string Name { get; set; } = string.Empty;
    
    /// <summary>Population count.</summary>
    public int Population { get; set; }
    
    /// <summary>Region or district.</summary>
    public string Region { get; set; } = string.Empty;
    
    /// <summary>Is capital city?</summary>
    public bool IsCapital { get; set; }
    
    /// <summary>GPS coordinates [lat, lon].</summary>
    public double[] Coordinates { get; set; } = [];
}

/// <summary>
/// Person props demonstrating ListItem fields.
/// Shows single ListItem and List of ListItems usage.
/// </summary>
[RedbScheme("Person")]
public class PersonProps
{
    /// <summary>Person name.</summary>
    public string Name { get; set; } = string.Empty;
    
    /// <summary>Age in years.</summary>
    public int Age { get; set; }
    
    /// <summary>Email address.</summary>
    public string Email { get; set; } = string.Empty;
    
    /// <summary>Single ListItem field (e.g. status from dictionary).</summary>
    public RedbListItem? Status { get; set; }
    
    /// <summary>Array of ListItems (e.g. roles from dictionary).</summary>
    public List<RedbListItem>? Roles { get; set; }
}

/// <summary>
/// Product with a unique business key (V4 [RedbUnique]): the SKU is unique per scheme,
/// enforced by the database over the hash of the canonical value. Used by E003.
/// </summary>
public class ProductProps
{
    /// <summary>Unique business key. NULL never participates in uniqueness.</summary>
    [RedbUnique]
    public string? Sku { get; set; }

    /// <summary>Display name (not unique).</summary>
    public string Title { get; set; } = string.Empty;

    /// <summary>Price in USD.</summary>
    public decimal Price { get; set; }
}

WhereRedb - Narrow by Parent First

WhereRedb narrows first. A condition on the object's own columns (here the parent) is checked
on _objects before any Props field is read, so the query reads the fields of the few objects
that pass and nothing else. The same Props filter and page over the whole scheme reads every
employee. This is the shape of "the points of one route sorted by their number" or "the lines
of one order": a narrow parent, a Props filter, a page sorted by a Props field.
var sw = Stopwatch.StartNew();
await redb.SyncSchemeAsync<EmployeeProps>();

// A team lead and twenty employees under it: the parent is a system column (_id_parent),
// no Props field is needed to tell the team apart.
var lead = new RedbObject<EmployeeProps>
{
    name = "e206-team-lead",
    Props = new EmployeeProps { FirstName = "E206", LastName = "Lead", Department = "Sales", Salary = 150000m, Age = 45 },
};
var leadId = await redb.SaveAsync(lead);

var team = Enumerable.Range(0, 20).Select(i => (IRedbObject)new RedbObject<EmployeeProps>
{
    name = $"e206-member-{i}",
    parent_id = leadId,
    Props = new EmployeeProps
    {
        FirstName = $"E206-{i}",
        LastName = "Member",
        Department = "Sales",
        Age = 25 + i,
        Salary = 60000m + i * 2500m,
    },
}).ToList();
var memberIds = await redb.SaveAsync(team);

// The same Props filter and page, once over the whole scheme and once under the parent.
var whole = Stopwatch.StartNew();
var anywhere = await redb.Query<EmployeeProps>()
    .Where(e => e.Salary > 70000m && e.Age >= 30)
    .OrderByDescending(e => e.Salary)
    .Take(10)
    .ToListAsync();
var wholeMs = whole.ElapsedMilliseconds;

var underLead = redb.Query<EmployeeProps>()
    .WhereRedb(o => o.ParentId == leadId)
    .Where(e => e.Salary > 70000m && e.Age >= 30)
    .OrderByDescending(e => e.Salary)
    .Take(10);

var narrow = Stopwatch.StartNew();
var teamPage = await underLead.ToListAsync();
var narrowMs = narrow.ElapsedMilliseconds;

// The SQL shows where the parent goes: into the scan of _objects that drives the query,
// ahead of every Props field.
var sql = await underLead.ToSqlStringAsync();
var drivingScan = sql.Split('\n').FirstOrDefault(l => l.Contains("_id_parent"))?.Trim() ?? "<parent condition not found>";

sw.Stop();

// Cleanup: the example leaves no residue behind.
await redb.DeleteAsync(memberIds.Append(leadId).ToList());
WhereRedbParentIdPerformanceCompositeIRedbQueryable.WhereRedbIRedbQueryable.WhereIRedbQueryable.ToSqlStringAsync
PG Pro 250ms(10)
postgres.ef 1963ms(10)
postgres.pro.repeat 254ms(10)
postgres.pro.cache 250ms(10)
postgres.ef.repeat 2051ms(10)
MS Pro 330ms(10)
mssql.pro.repeat 270ms(10)
mssql.pro.cache 180ms(10)
sqlite.pro 213ms(10)
sqlite.pro.repeat 39ms(10)
sqlite.pro.cache 166ms(10)