JSON file-based storage implementation for the Birko data layer.
C:\Source\Birko.Data.JSON\
- Simple file-based data persistence
- No database required
- Good for testing, small applications, and configuration
JsonStore<T>- Synchronous JSON file storeJsonBulkStore<T>- Bulk operations JSON storeAsyncJsonStore<T>- Asynchronous JSON file storeAsyncJsonBulkStore<T>- Async bulk operations JSON store
JsonRepository<T>- JSON repositoryJsonBulkRepository<T>- Bulk JSON repositoryAsyncJsonRepository<T>- Async JSON repositoryAsyncJsonBulkRepository<T>- Async bulk JSON repository
Data is stored as JSON array:
[
{
"Id": "123e4567-e89b-12d3-a456-426614174000",
"Name": "Item 1",
"Created": "2024-01-01T00:00:00Z"
},
{
"Id": "123e4567-e89b-12d3-a456-426614174001",
"Name": "Item 2",
"Created": "2024-01-02T00:00:00Z"
}
]using Birko.Data.JSON.Stores;
public class CustomerStore : JsonStore<Customer>
{
public CustomerStore(string filePath) : base(filePath)
{
}
// Override methods for custom behavior
}var settings = new JsonSettings
{
FilePath = "data/customers.json"
};
store.SetSettings(settings);public override IEnumerable<KeyValuePair<Customer, Guid>> CreateAll(IEnumerable<Customer> items)
{
var fileData = ReadFromFile();
var results = new List<KeyValuePair<Customer, Guid>>();
foreach (var item in items)
{
item.Id = NewGuid();
fileData.Add(item);
results.Add(new KeyValuePair<Customer, Guid>(item, item.Id));
}
WriteToFile(fileData);
return results;
}public override async Task<Guid> CreateAsync(Customer item)
{
var fileData = await ReadFromFileAsync();
item.Id = NewGuid();
fileData.Add(item);
await WriteToFileAsync(fileData);
return item.Id;
}File locking ensures safe concurrent access.
Changes are written immediately to disk.
JSON output can be formatted for readability.
Automatic backup before writes (optional).
- Birko.Data.Core
- Birko.Data.Stores
- System.Text.Json (or Newtonsoft.Json)
- No database setup required
- Human-readable data files
- Easy to backup and version control
- Simple to debug
- Not suitable for large datasets
- No efficient querying (loads entire file)
- No ACID guarantees
- Concurrent access limited
- Configuration storage
- Small application data
- Testing and development
- Prototyping
- Single-user applications
Store data in a dedicated directory:
app/
├── data/
│ ├── customers.json
│ ├── products.json
│ └── orders.json
Handle file I/O errors:
try
{
store.Create(item);
}
catch (IOException ex)
{
// Handle file access errors
}Regular backups of JSON files are essential.
// Create store
var store = new JsonStore<Customer>("data/customers.json");
// Create
var customer = new Customer { Name = "John Doe" };
var id = store.Create(customer);
// Read
customer.Id = id;
store.Read(customer);
// Update
customer.Name = "Jane Doe";
store.Update(customer);
// Read all
var customers = store.ReadAll();
// Delete
store.Delete(customer);This is an excellent reference for understanding store patterns due to its simplicity.
When making changes that affect the public API, features, or usage patterns of this project, update the README.md accordingly. This includes:
- New classes, interfaces, or methods
- Changed dependencies
- New or modified usage examples
- Breaking changes
When making major changes to this project, update this CLAUDE.md to reflect:
- New or renamed files and components
- Changed architecture or patterns
- New dependencies or removed dependencies
- Updated interfaces or abstract class signatures
- New conventions or important notes
Every new public functionality must have corresponding unit tests. When adding new features:
- Create test classes in the corresponding test project
- Follow existing test patterns (xUnit + FluentAssertions)
- Test both success and failure cases
- Include edge cases and boundary conditions