Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 184 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# Copilot Instructions for Lasy

## Project Overview

**Lasy** is a C# database abstraction library that provides a unified interface for multiple database backends. It targets **.NET Framework 4.0** and enables code to be written against clean interfaces (`IReadable`, `IWriteable`, `IReadWrite`) that can be backed by a real SQL Server database, an in-memory fake database, or a file-based database — making unit testing straightforward.

---

## Repository Structure

```
/
├── .github/
│ └── copilot-instructions.md # This file
├── lib/
│ └── nunit.framework.dll # NUnit 2.5.10 test runner (checked in)
├── src/ # Main library source (~21 C# files)
│ ├── Core Interfaces
│ │ ├── IReadable.cs # Read operations contract
│ │ ├── IWriteable.cs # Write operations contract
│ │ ├── IReadWrite.cs # Combined read/write interface
│ │ ├── ITransaction.cs # Transaction contract (Commit/Rollback)
│ │ └── IDBAnalyzer.cs # Database metadata contract
│ ├── SQL Server Implementation
│ │ ├── RealDB.cs # SqlConnection-backed implementation
│ │ ├── RealDBTransaction.cs # Wraps SqlTransaction
│ │ ├── SQLAnalyzer.cs # Abstract base for SQL metadata
│ │ ├── SQL2000DBAnalyzer.cs # SQL Server 2000 metadata queries
│ │ └── SQL2005DBAnalyzer.cs # SQL Server 2005+ metadata queries
│ ├── In-Memory Fake Implementation
│ │ ├── FakeDB.cs # Dictionary-backed in-memory store
│ │ ├── FakeDBTable.cs # Per-table storage and operations
│ │ ├── FakeDBTransaction.cs # Simulated transaction
│ │ └── FakeDBAnalyzer.cs # Metadata for fake database
│ ├── File-Based Implementation
│ │ └── FileDB.cs # Reads SQL Management Studio .rpt files
│ ├── Utilities & Extensions
│ │ ├── IReadableExtensions.cs
│ │ ├── IWritableExtensions.cs
│ │ ├── IReadWriteExtensions.cs
│ │ ├── SqlExtensions.cs
│ │ ├── SqlTypeConversion.cs
│ │ └── LasyExceptions.cs # KeyNotSetException, ThisSadlyHappenedException
│ ├── Lasy.csproj
│ └── Properties/AssemblyInfo.cs
└── test/ # NUnit test project (~8 C# files)
├── FakeDBTests.cs
├── FileDBTests.cs
├── RealDBTests.cs # Requires live SQL Server connection
├── FakeDBTableTests.cs
├── IReadWriteExtensionTests.cs
├── SqlTypeConversionTests.cs
├── Person.cs # Test model
├── Organization.cs # Test model
├── FileDBData/ # .rpt test data files
│ ├── simple.rpt
│ ├── variableWidth.rpt
│ └── withNull.rpt
├── Lasy.Tests.csproj
└── Properties/AssemblyInfo.cs
```

---

## Tech Stack

| Concern | Technology |
|---------|-----------|
| Language | C# |
| Runtime | .NET Framework 4.0 |
| Build | MSBuild (via .csproj files, ToolsVersion 4.0) |
| Tests | NUnit 2.5.10 (DLL checked in at `lib/nunit.framework.dll`) |
| SQL Backend | SQL Server (via `System.Data.SqlClient`) |
| Key Dependency | **Nvelope** — expected at `../../Nvelope/src/Nvelope.csproj` |

---

## Building the Project

```bash
# Build main library
msbuild src/Lasy.csproj /p:Configuration=Debug

# Build test project
msbuild test/Lasy.Tests.csproj /p:Configuration=Debug
```

Output assemblies are placed in `bin/Debug/` or `bin/Release/` relative to each project.

**Important**: The project depends on **Nvelope**, a sibling repository that must be cloned at `../../Nvelope/` (relative to this repo root) before the build will succeed. If Nvelope is missing, you will see project reference resolution errors.

---

## Running Tests

Tests use **NUnit 2.5.10**. After building the test project:

```bash
# Run with NUnit console runner (path to runner may vary)
nunit-console test/bin/Debug/Lasy.Tests.dll

# Or use the NUnit GUI runner against the compiled DLL
```

**Notes on test categories**:
- `FakeDBTests`, `FakeDBTableTests`, `IReadWriteExtensionTests`, `SqlTypeConversionTests`, `FileDBTests` — run without any external dependencies.
- `RealDBTests` — requires a live SQL Server instance with a connection string. These tests will fail or be skipped in environments without a database.

---

## Linting

There is no dedicated linting tool configured. The build uses `<WarningLevel>4</WarningLevel>` so compiler warnings serve as the primary code-quality signal. Run the build and inspect compiler output for warnings.

---

## Core Design Patterns

### 1. Interface-Based Abstraction
All consumers code to `IReadable`, `IWriteable`, or `IReadWrite`. Swap implementations without changing consumer code:

```csharp
// Production
IReadWrite db = new RealDB(connectionString, new SQL2005DBAnalyzer(connectionString));

// Unit tests (no database required)
IReadWrite db = new FakeDB();

// Integration tests from snapshot data
IReadable db = new FileDB("test/FileDBData");
```

### 2. Dictionary-Based Data Model
There is no ORM or entity class generation. All rows are represented as `Dictionary<string, object>` where keys are column names. This keeps the library flexible but means consumers must handle type conversions themselves (see `SqlTypeConversion`).

### 3. Analyzer Pattern (Metadata Abstraction)
The `IDBAnalyzer` interface decouples the library from the specific way each database exposes metadata (primary keys, auto-number columns, field lists). Each DB implementation pairs with an analyzer:
- `RealDB` → `SQL2005DBAnalyzer` or `SQL2000DBAnalyzer`
- `FakeDB` → `FakeDBAnalyzer`

### 4. Extension Methods
Heavy use of extension methods to add functionality without modifying core classes. When adding operations that apply across multiple implementations, prefer extension methods in the appropriate `I*Extensions.cs` file.

### 5. Metadata Caching
`SQLAnalyzer` uses Nvelope's `.Memoize()` to cache metadata lookups (primary keys, field lists) for 10 minutes. This avoids repeated round-trips to system tables at runtime.

---

## Key Conventions

- **Private fields**: Underscore prefix (`_db`, `_conn`, `_dbAnalyzer`)
- **Methods & Properties**: PascalCase
- **Parameters & local variables**: camelCase
- **Interfaces**: `I` prefix (`IReadable`, `IWriteable`)
- **Test classes**: NUnit `[TestFixture]` attribute, test methods with `[Test]`
- **No solution (.sln) file** — build each `.csproj` directly with MSBuild

---

## Known Issues & Workarounds

1. **Nvelope dependency**: The project references Nvelope via a relative path (`../../Nvelope/src/Nvelope.csproj`). If this sibling repo is not present, the build fails with project reference errors. Clone Nvelope into the parent directory to resolve this.

2. **No CI/CD pipeline**: There are no GitHub Actions workflows, no AppVeyor, and no other CI configuration. Tests must be run locally.

3. **RealDB tests require SQL Server**: `RealDBTests.cs` will fail without a SQL Server instance. Skip or isolate these tests in environments without a database.

4. **README is empty**: The `README` file at the repo root has no content. Refer to this file for onboarding information instead.

5. **NUnit version**: The project uses NUnit 2.5.10 (very old). The DLL is checked in under `lib/`. Do not upgrade NUnit without updating all test attributes — NUnit 3.x has breaking API changes.

6. **FileDB reads SQL Management Studio `.rpt` files**: These are fixed-width text exports. The parser in `FileDB.cs` is sensitive to column alignment; any `.rpt` files added to `test/FileDBData/` must preserve the fixed-width format.

---

## Adding New Features — Checklist

When adding a new database operation:
1. Add the method signature to the appropriate interface (`IReadable`, `IWriteable`, or `IReadWrite`).
2. Implement the method in `RealDB` (SQL Server).
3. Implement the method in `FakeDB` and `FakeDBTable` (in-memory).
4. Add a convenience overload in the corresponding `I*Extensions.cs` file if needed.
5. Add `FakeDBTests` coverage — these can run without a live database.
6. Add `RealDBTests` coverage if the behavior differs from the fake (optional; requires SQL Server).