BijouDB 1.0.0

Additional Details

prior version has a bug where the first record ever created has an invalid id and thus doesn't get properly created.

There is a newer version of this package available.
See the version list below for details.
dotnet add package BijouDB --version 1.0.0
NuGet\Install-Package BijouDB -Version 1.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BijouDB" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add BijouDB --version 1.0.0
#r "nuget: BijouDB, 1.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install BijouDB as a Cake Addin
#addin nuget:?package=BijouDB&version=1.0.0

// Install BijouDB as a Cake Tool
#tool nuget:?package=BijouDB&version=1.0.0

BijouDB

A small C# database

Note

Currently this utilizes preview features so to use this you must enable preview features in your project.

<PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <LangVersion>preview</LangVersion>
    <EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup>

Features

DataTypes ⇒ Synonymous Wrapper

                              BigInteger => @bint

                                  byte[] => @blob

                                    bool => @bool

                                    byte => @byte

                                    char => @char

                                DateTime => @date

                                 decimal => @decimal

                                   float => @float

                                     int => @int

                                    long => @long

                      R : BijouDB.Record => @record<R>

                                   sbyte => @sbyte

                                   short => @short

                                  string => @string

                                    uint => @uint

                                   ulong => @ulong

                                  ushort => @ushort

                           Tuple<T1, T2> => @tuple<D1, D2>

                       Tuple<T1, T2, T3> => @tuple<D1, D2, D3>

                   Tuple<T1, T2, T3, T4> => @tuple<D1, D2, D3, D4>

               Tuple<T1, T2, T3, T4, T5> => @tuple<D1, D2, D3, D4, D5>

           Tuple<T1, T2, T3, T4, T5, T6> => @tuple<D1, D2, D3, D4, D5, D6>

       Tuple<T1, T2, T3, T4, T5, T6, T7> => @tuple<D1, D2, D3, D4, D5, D6, D7>

Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> => @tuple<D1, D2, D3, D4, D5, D6, D7, DRest>

Nullable Types:

                              BigInteger? => @bint.nullable

                                  byte[]? => @blob.nullable

                                    bool? => @bool.nullable

                                    byte? => @byte.nullable

                                    char? => @char.nullable

                                DateTime? => @date.nullable

                                 decimal? => @decimal.nullable

                                   float? => @float.nullable

                                     int? => @int.nullable

                                    long? => @long.nullable

                      R? : BijouDB.Record => @record<R>.nullable

                                   sbyte? => @sbyte.nullable

                                   short? => @short.nullable

                                  string? => @string.nullable

                                    uint? => @uint.nullable

                                   ulong? => @ulong.nullable

                                  ushort? => @ushort.nullable

                           Tuple<T1, T2>? => @tuple<D1, D2>.nullable

                       Tuple<T1, T2, T3>? => @tuple<D1, D2, D3>.nullable

                   Tuple<T1, T2, T3, T4>? => @tuple<D1, D2, D3, D4>.nullable

               Tuple<T1, T2, T3, T4, T5>? => @tuple<D1, D2, D3, D4, D5>.nullable

           Tuple<T1, T2, T3, T4, T5, T6>? => @tuple<D1, D2, D3, D4, D5, D6>.nullable

       Tuple<T1, T2, T3, T4, T5, T6, T7>? => @tuple<D1, D2, D3, D4, D5, D6, D7>.nullable

Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>? => @tuple<D1, D2, D3, D4, D5, D6, D7, DRest>.nullable

Constraints

Unique Ensures that a column has all unique values

Default Specifies a default for any values that arent set

Check Specifies a condition for a value to be set

NotNull is the default, use a IDataType.nullable to explicitly use null

PRIMARY KEY and FOREIGN KEY is replicated loosely with References

Custom DataTypes

You can create your own data types by implementing the interface BijouDB.IDataType

public interface IDataType
{
    // The size in bytes of the serialized datatype, set to 0 if not a fixed size
    public static abstract long Length { get; }
    // The logic to convert from bytes
    public void Deserialize(Stream stream);
    // The logic to convert to bytes
    public void Serialize(Stream stream);
    // The logic to represent the datatype in a human readable string
    public string ToString();
}

Usage

To get started simply create a new class which inherits from BijouDB.Record.

Create a static readonly field to act as a column, specify a BijouDB datatype.

As a convention, the column should end in Column.

Create a new property with the respectice type of the column.

The get accessor should call the column you just made's Get() method, passing in this as an argument.

The set accessor should call the column's Set() method, passing in this and value as arguments.

Create a static contructor, its needed to instantiate the columns.

Use the SchemaBuilder to generate the columns via the Add() method.

Do this for each of your columns and finally at the end call the Build() method.

Example

using BijouDB;
using BijouDB.DataTypes;

public class MyRecord : Record
{
    public static readonly Column<@int> AgeColumn;
    public int Age { get => AgeColumn.Get(this); set => AgeColumn.Set(this, value); }

    static MyRecord() => SchemaBuilder<MyRecord>
        .Add(out AgeColumn)
        .Build();
}

Specifying Constraints

Use the SchemaBuilder to add constraints to your columns.

Place the constraints on any column by using the Add() method.

Provide the label for the constraint Unique: or Default: or Check: followed by the value for the constraint.

The order does't matter and you don't have to provide every constraint.

using BijouDB;
using BijouDB.DataTypes;

public class MyRecord : Record
{
    public static readonly Column<@int> AgeColumn;
    public int Age { get => AgeColumn.Get(this); set => AgeColumn.Set(this, value); }

    static MyRecord() => SchemaBuilder<MyRecord>
        // Specify that the column is NOT unique
        // Specify that valid values must be 18 or larger
        // Specify that the default value is 18
        .Add(out AgeColumn, Unique: false, Check: value => value >= 18, Default: () => 18)
        .Build();
}

References

In SQL we have the notion of PRIMARY KEY and FOREIGN KEY to link relationships between tables.

Here we have the concept of References. Its very similar in concept.

References prevent a Record from being deleted if it has references.

You can create a Reference specifying the Record it references and the generic type of that column.

As a convention you should end the field with References.

Create a property with the type of the referenced Record. This property should be an array [].

Use the For() method passing in this.

You then use an overload for the Add() method for References. References do NOT have contraints.

Instead you have to specifically point it to the column in the referenced Record.

using BijouDB;
using BijouDB.DataTypes;

public class Employee : Record
{
    public static readonly Column<@int> AgeColumn;
    public int Age { get => AgeColumn.Get(this); set => AgeColumn.Set(this, value); }

    // A Reference to 'Computer' Record
    public static readonly References<Computer, @record<Employee>> ComputerReferences;
    public Computer[] Computers => ComputerReferences.For(this);

    static Employee() => SchemaBuilder<Employee>
        .Add(out AgeColumn, Unique: false, Check: value => value >= 18, Default: () => 18)
        // Generates the Referennce, and points it to the 'EmployeeColumn' in 'Computer' Record
        .Add(out ComputerReferences, () => Computer.EmployeeColumn)
        .Build();
}

public class Computer : Record
{
    public static readonly Column<@record<Employee>> EmployeeColumn;
    public Employee Employee { get => EmployeeColumn.Get(this); set => EmployeeColumn.Set(this, value); }

    static Computer() => SchemaBuilder<Computer>
        .Add(out EmployeeColumn)
        .Build();
}

To access references of a record, call its respective property.

Employee employee = new()
{
    Age = 30
};

Computer comp1 = new()
{
    Employee = employee
};

foreach (Computer computer in employee.Computers)
{
    // Manipulate the record here
}

Removing Records

All Records have the following methods to be removed from the database.

// Removes the Record from the database with no exception handling (you have to do so manually)
public void Remove();
// Tries the remove the Record from the database while suppressing any exceptions.
// true if successfully removed, otherwise false.
public bool TryRemove(); 
// Tries the remove the Record from the database.
// Exposes any Exception that might've thrown.
// true if successfully removed, otherwise false.
public bool TryRemove(out Exception? exception); 

Getting Records

If you know the Type and Id (represented as a Guid) use the BijouDB.Record.TryGet<R>( ... ) method.

public static bool TryGet<R>(Guid id, out R? record) { }
public static bool TryGet<R>(string id, out R? record) { }

// Example
// Get a single record via its Id
if (BijouDB.Record.TryGet("0e758669-33ee-847e-d0e8-f5e89cc2b5c2", out Employee? employee))
{
    // Manipulate the record here
}

If you know only the Type and wish to get all Records of that type you can use BijouDB.Record.GetAll<R>() method.

public static R[] GetAll<R>() { }

// Example
// Gets all Employee records
foreach (Employee employee in BijouDB.Record.GetAll<Employee>())
{
    // Manipulate the record here
}

If you know the Type of the Record and the value to one of its columns you can call the Column's RecordsWithValue<R>( .. ) method.

public R[] RecordsWithValue<R>(D data) { }

// Example
// Gets all Employee records where the age is 19
foreach (Employee employee in Employee.AgeColumn.RecordsWithValue<Employee>(19))
{
    // Manipulate the record here
}

Logging

There was very minimal effor put into logging. It is disabled by default.

To turn on logging, set BijouDB.Globals.Logging to true.

Operations Complexity

Getting a Record via its Id O(1)

Getting all Records of a Type O(1) - O(n)

Getting all Records of a Type by value O(1) - O(n)

Adding a Record O(1)

Removing a Record O(1) - O(n)

Getting References O(1) - O(n)

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.1.1.1 344 11/9/2022
4.1.1 333 11/9/2022
4.1.0.3 416 7/26/2022
4.1.0.2 402 7/19/2022
4.1.0.1 399 7/11/2022
4.1.0 420 7/9/2022
4.0.1.10 405 7/5/2022
4.0.1.9-preview.0.0.2 144 7/4/2022
4.0.1.9-preview 169 7/3/2022
4.0.1.8 406 6/29/2022
4.0.1.7 399 6/29/2022
4.0.1.6 419 6/23/2022
4.0.1.5 411 6/23/2022
4.0.1.4 432 6/22/2022
4.0.1.3 424 6/22/2022
4.0.1.2 409 6/22/2022
4.0.1.1 403 6/21/2022
4.0.1 401 6/20/2022
4.0.0.8 405 6/20/2022
4.0.0.7 404 6/20/2022
4.0.0.6 396 6/19/2022
4.0.0.5 392 6/19/2022
4.0.0.4 398 6/19/2022
4.0.0.3 398 6/19/2022
4.0.0.2 418 6/19/2022
4.0.0.1 397 6/18/2022
4.0.0 392 6/15/2022
3.2.3 420 6/4/2022
3.2.2.2 449 5/30/2022
3.2.1.2 448 5/29/2022
3.2.1.1 429 5/29/2022
3.2.1 466 5/29/2022
3.2.0 486 5/27/2022
3.1.0 461 5/26/2022
3.0.0 457 5/22/2022
2.5.1 477 5/19/2022
2.5.0 452 5/18/2022
2.4.0 449 5/18/2022
2.3.2.1 453 5/18/2022
2.3.1.1 458 5/17/2022
2.3.1 458 5/17/2022
2.3.0 453 5/17/2022
2.2.0 470 5/16/2022
2.1.0 477 5/15/2022
2.0.0.1 459 5/15/2022
2.0.0 468 5/15/2022
1.1.1 506 5/14/2022
1.1.0 485 5/14/2022
1.0.0 498 5/14/2022