{"id":18009837,"url":"https://github.com/kekyo/flyflint","last_synced_at":"2025-06-20T00:04:25.873Z","repository":{"id":84090120,"uuid":"445493657","full_name":"kekyo/FlyFlint","owner":"kekyo","description":"Lightweight static O/R mapping builder at compile time.","archived":false,"fork":false,"pushed_at":"2022-04-30T03:00:35.000Z","size":1684,"stargazers_count":3,"open_issues_count":6,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-27T17:18:34.682Z","etag":null,"topics":["aot","compile-time","database","dotnet","lightweight","orm","static"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kekyo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-07T11:10:03.000Z","updated_at":"2024-04-24T16:00:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"a1dbd290-cab9-44da-9086-75a50edd5ce0","html_url":"https://github.com/kekyo/FlyFlint","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/kekyo/FlyFlint","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FFlyFlint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FFlyFlint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FFlyFlint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FFlyFlint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kekyo","download_url":"https://codeload.github.com/kekyo/FlyFlint/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FFlyFlint/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260852095,"owners_count":23072587,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aot","compile-time","database","dotnet","lightweight","orm","static"],"created_at":"2024-10-30T02:11:13.163Z","updated_at":"2025-06-20T00:04:20.857Z","avatar_url":"https://github.com/kekyo.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FlyFlint\n\n![FlyFlint](Images/FlyFlint.100.png)\n\nFlyFlint - Lightweight static O/R mapping builder at compile time.\n\n[![Project Status: WIP – Initial development is in progress, but there has not yet been a stable, usable release suitable for the public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostatus.org/#wip)\n\n## NuGet\n\n|Package|NuGet|\n|:--|:--|\n|FlyFlint|[![NuGet FlyFlint](https://img.shields.io/nuget/v/FlyFlint.svg?style=flat)](https://www.nuget.org/packages/FlyFlint)|\n|FlyFlint.Dynamic|[![NuGet FlyFlint.Dynamic](https://img.shields.io/nuget/v/FlyFlint.Dynamic.svg?style=flat)](https://www.nuget.org/packages/FlyFlint.Dynamic)|\n\n## CI\n\n|main|develop|\n|:--|:--|\n|[![FlyFlint CI build (main)](https://github.com/kekyo/FlyFlint/workflows/.NET/badge.svg?branch=main)](https://github.com/kekyo/FlyFlint/actions?query=branch%3Amain)|[![FlyFlint CI build (develop)](https://github.com/kekyo/FlyFlint/workflows/.NET/badge.svg?branch=develop)](https://github.com/kekyo/FlyFlint/actions?query=branch%3Adevelop)|\n\n---\n\n[![Japanese is here](Images/Japanese.256.png)](https://github.com/kekyo/FlyFlint/blob/main/README_ja.md)\n\n## What is this?\n\nIn short word: Lightweight static O/R mapping builder at compile time.\n\nFlyFlint will generate data accessors infrastructure at that compile time\nand there are not use any runtime reflection.\nThat means, It is an AOT friendly, faster and lightweight O/R mapper.\n\nTo use it, you just need to define a record type (often called entity, record or model type)\nas a vessel for your records.\nAnd then simply install [FlyFlint NuGet package](https://www.nuget.org/packages/FlyFlint).\nNo additional work is required at all!\n\n```csharp\nusing FlyFlint;\nusing System;\nusing System.Data.SQLite;\nusing System.Threading.Tasks;\n\n// Requires using `ToArrayAsync` or install `System.Linq.Async`.\nusing FlyFlint.Collections;\n\npublic static class Program\n{\n    // You can write record type with\n    // any class/struct/field/property combination...\n    private sealed class Target\n    {\n        public int Id;\n        public string? Name;    // Yes, FlyFlint covered nullable types.\n        public DateTime? Birth;\n    }\n\n    public static async Task Main()\n    {\n        using var connection = new SQLiteConnection(\n            \"Data Source=:memory:\");\n        await connection.OpenAsync();\n\n        // Build the query.\n        var query = connection.Query\u003cTarget\u003e(\n            $\"SELECT * FROM target\");\n\n        // Execute query and got enumerable results on asynchronously.\n        // (And enabled fast prefetcher.)\n        Target[] targets = await query.\n            ExecuteAsync().\n            ToArrayAsync();\n    }\n}\n```\n\nFlyFlint can store record data into record type instance **except using ANY reflection**.\nThe record data will be stored directly from `DbDataReader`\nby compile-time generated code.\n\nThis is achieved by automatically inserting code that is almost equivalent\nto manually calling `DbDataReader.GetInt32()` or like.\n\n---\n\n## Features\n\nNote: This is still a work in progress and does not cover all features.\n\n* Fully static injecting accessor (getter and setter) code at compile time.\n* Only installing NuGet package.\n* Totally unused reflection API.\n* Simple and faster.\n* Type safe query construction interface.\n* Free from DBNull and support for Nullable types.\n* Build parameterized query with string interpolation syntax.\n* Supported all ADO.NET driver by common interface type.\n* Easy hook up with dynamic query solution when using un-injected types.\n* Possible define your own type conversion.\n* Supported F# friendly API set.\n\n---\n\n## Environment\n\n### Target platforms\n\n* .NET 6/5\n* .NET Core 3.1/3.0/2.1/2.0\n* .NET Standard 2.1/2.0\n* .NET Framework 4.8/4.6.1/4.6/4.5/4.0/3.5\n* ADO.NET database driver that provides all `DbConnection` type.\n  * SQL Server, Oracle, SQLite and etc...\n\n#### Limitation\n\n* Lesser than .NET Framework 4.6.1: Could not use asynchronous iteration (`IAsyncEnumerable\u003cT\u003e`).\n* .NET Framework 4.0: Package has dependency `Microsoft.Bcl.Async`.\n* .NET Framework 3.5: Package has dependency `AsyncBridge`.\n\n### Development environments\n\nMaybe you have to develop with newer MSBuild infrastructure:\n\n* Visual Studio 2021/2019/2017\n* Rider with .NET 6/5/.NET Core SDK\n\n---\n\n## Basic usage\n\n[Install package via NuGet](https://www.nuget.org/packages/FlyFlint).\n\nWe can make safer code using string interpolated query in FlyFlint:\n\n```csharp\n    // Query parameters on the variables:\n    var id = 123;\n\n    // Build the parameterized query with string interpolation syntax.\n    var query = connection.Query\u003cTarget\u003e(\n        $\"SELECT * FROM target WHERE Id = {id}\");\n\n    Target[] targets = await query.\n        ExecuteAsync().\n        ToArrayAsync();\n```\n\nIt is naturally code, readable and writable. The FlyFlint will interpret\nand construct parameterized query, it is **not RAW STRING**.\n\nI understood maybe you already use major lightweight O/R mapper `Dapper`,\nFlyFlint can receive `Dapper` like query code:\n\n```csharp\n    // Build the parameterized query likes Dapper:\n    var query = connection.Query\u003cTarget\u003e(\n        \"SELECT * FROM target WHERE Id = @id\").\n        Parameter(new { id = 123 });\n\n    Target[] targets = await query.\n        ExecuteAsync().\n        ToArrayAsync();\n```\n\nYes, in general, that case will be used reflection API.\nBut FlyFlint will generate getter code at compile-time.\n\nAnd more, construction for any parameterized query is required additional cost.\nWe can build `prepared query` before using it:\n\n```csharp\n    // Build the prepared query:\n    var prepared = Query.Prepare\u003cTarget\u003e(\n        () =\u003e $\"SELECT * FROM target WHERE Id = {id}\");\n\n    // Use prepared query:\n    var query = connection.Query(prepared);\n\n    Target[] targets = await query.\n        ExecuteAsync().\n        ToArrayAsync();\n```\n\nThis `prepared query` is delayed to examine query expression.\nSince it does not depend on the database connection (`DbConnection`),\nif you generate it in advance, you can use it as many times as you like.\n\n## Database traits\n\nThe `Database` class has some database characteristic definitions,\nYou can use this to make database-specific definitions.\nThis definition is called `Trait`:\n\n```csharp\npublic static class Database\n{\n    // Default definition\n    public static readonly Trait Default;\n\n    // SQL Server definition\n    public static readonly Trait SQLServer;\n\n    // ORACLE definiton\n    public static readonly Trait Oracle;\n\n    // SQLite definition\n    public static readonly Trait SQLite;\n\n    // MySQL definition\n    public static readonly Trait MySQL;\n\n    // Postgresql definition\n    public static readonly Trait Postgresql;\n}\n```\n\nThe default definition is common to all databases except ORACLE.\n\nIf you want to use it in your own database, you can define `Trait` yourself:\n\n```csharp\n// Definition of Trait\nvar customTrait = Database.CreateTrait(\n    ConversionContext.Default,           // Custom type conversion method\n    StringComparer.OrdinalIgnoreCase,    // Field name matching method\n    \"@\");                                // Prefix for parameterized query\n\n// Use Trait explicitly\nvar query1 = customTrait.Query\u003cTarget\u003e(\n    connection,\n    $\"SELECT * FROM [persons] WHERE id = {id}\");\n\n// Changed to use Trait implicitly\nQuery.DefaultTrait = customTrait;\n\n// (using the implicitly specified Trait)\nvar query2 = connection.Query\u003cTarget\u003e(\n    $\"SELECT * FROM [persons] WHERE id = {id}\");\n```\n\n## Dynamic query (IL emitter)\n\nTODO:\n\n### Fallback usage\n\nTODO:\n\n## Deeper FlyFlint\n\nTODO: injected type case\n\n---\n\n## License\n\nApache-v2.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkekyo%2Fflyflint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkekyo%2Fflyflint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkekyo%2Fflyflint/lists"}