{"id":25254979,"url":"https://github.com/2sky/recordcommander","last_synced_at":"2025-08-22T03:11:52.805Z","repository":{"id":275476909,"uuid":"926192510","full_name":"2sky/RecordCommander","owner":"2sky","description":"RecordCommander is a lightweight C# library that empowers you to seed, import, and manage records using simple, command-based syntax.","archived":false,"fork":false,"pushed_at":"2025-07-24T22:32:54.000Z","size":272,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-14T02:54:29.560Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/2sky.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":"2025-02-02T19:09:05.000Z","updated_at":"2025-07-24T22:32:58.000Z","dependencies_parsed_at":"2025-03-02T15:25:57.603Z","dependency_job_id":"658797be-afcf-4ea3-9067-e6df695252bf","html_url":"https://github.com/2sky/RecordCommander","commit_stats":null,"previous_names":["stevehansen/recordcommander","2sky/recordcommander"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/2sky/RecordCommander","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sky%2FRecordCommander","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sky%2FRecordCommander/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sky%2FRecordCommander/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sky%2FRecordCommander/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/2sky","download_url":"https://codeload.github.com/2sky/RecordCommander/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2sky%2FRecordCommander/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271578517,"owners_count":24784051,"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","status":"online","status_checked_at":"2025-08-22T02:00:08.480Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-02-12T05:51:17.331Z","updated_at":"2025-08-22T03:11:52.791Z","avatar_url":"https://github.com/2sky.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RecordCommander\n\n[![RecordCommander Logo](https://raw.githubusercontent.com/2sky/RecordCommander/main/logo-128x128.png)](https://github.com/2sky/RecordCommander)\n[![NuGet Version](https://img.shields.io/nuget/v/RecordCommander)](https://www.nuget.org/packages/RecordCommander/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/2sky/RecordCommander/blob/main/LICENSE)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/RecordCommander)](https://www.nuget.org/packages/RecordCommander/)\n\nRecordCommander is a C# library that enables you to create, update, and manage records using a command-line–inspired interface. With a focus on simplicity and flexibility, RecordCommander allows you to register your data types, define unique keys and property mappings, and use both positional and named arguments to seed data or integrate with import/export systems.\n\n## Features\n\n- **Command-Based Record Management:** Create or update records using single-line commands (e.g., `add language nl Dutch`).\n- **Flexible Configuration:** Register classes by specifying unique keys, positional property order, and named property assignments.\n- **Data Seeding \u0026 Import/Export:** Ideal for seeding data, providing sample data for documentation, or integrating with external systems.\n- **JSON–Like Parsing:** Supports complex property values (including arrays) with JSON–like syntax.\n- **No External Dependencies:** Uses only the default Microsoft libraries.\n- **Aliases \u0026 Short Names:** Apply `[Alias]` on classes or properties to use shorter command tokens.\n- **Custom Commands \u0026 Method Calls:** Extend the registry with `RegisterCommand` or call object methods via `--Method:arg=value`.\n- **Usage Generation:** Generate commands, usage examples and prompts for custom commands.\n- **Custom Converters \u0026 Enum/Flags Support:** Register converters for your types and work with enums or flag combinations.\n\n## Getting Started\n\n### Installation\n\nSimply clone the repository and include the source code in your project. Since RecordCommander relies solely on standard .NET libraries, no additional NuGet packages are required.\n\nOr install the library via NuGet Package Manager Console:\n```\nInstall-Package RecordCommander\n```\n\n### Configuration\n\nBefore running commands, register your record types with the library. For example, suppose you have the following domain classes:\n\n```csharp\npublic class MyData\n{\n    public List\u003cLanguage\u003e Languages { get; set; } = new List\u003cLanguage\u003e();\n    public List\u003cCountry\u003e Countries { get; set; } = new List\u003cCountry\u003e();\n}\n\npublic class Language\n{\n    public string Key { get; set; }\n    public string Name { get; set; }\n}\n\npublic class Country\n{\n    public string Code { get; set; }\n    public string Name { get; set; }\n    public string[] SpokenLanguages { get; set; } = Array.Empty\u003cstring\u003e();\n}\n```\n\nYou would register them as follows:\n\n```csharp\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing RecordCommander;\n\n// Register the Language record.\nRecordCommandRegistry.Register\u003cMyData, Language\u003e(\n    name: \"language\",\n    collectionAccessor: ctx =\u003e ctx.Languages,\n    uniqueKeySelector: x =\u003e x.Key,\n    positionalPropertySelectors: new Expression\u003cFunc\u003cLanguage, object\u003e\u003e[] { x =\u003e x.Name }\n);\n\n// Register the Country record.\nRecordCommandRegistry.Register\u003cMyData, Country\u003e(\n    name: \"country\",\n    collectionAccessor: ctx =\u003e ctx.Countries,\n    uniqueKeySelector: x =\u003e x.Code,\n    positionalPropertySelectors: new Expression\u003cFunc\u003cCountry, object\u003e\u003e[] { x =\u003e x.Name, x =\u003e x.SpokenLanguages }\n);\n```\n\nThe AliasAttribute can be used on classes and properties to provide alternative names for the command and properties. For example:\n```csharp\n[Alias(\"lang\")]\npublic class Language\n{\n    public string Key { get; set; }\n    [Alias(\"n\")]\n    public string Name { get; set; }\n}\n```\n\n### Running Commands\n\nAfter registration, you can execute commands that create or update records in your data context. For example:\n\n```csharp\n// Create a context instance.\nvar context = new MyData();\n\n// Run commands to seed or update data.\nRecordCommandRegistry.Run(context, \"add language nl Dutch\");\nRecordCommandRegistry.Run(context, \"add language fr French\");\nRecordCommandRegistry.Run(context, \"add country be Belgium\");\n// Update an existing record using named arguments:\nRecordCommandRegistry.Run(context, \"add country be --SpokenLanguages=['nl','fr']\");\n// Or using the aliases:\nRecordCommandRegistry.Run(context, \"add lang de --n=German\");\n```\n\n### Example Output\n\nAfter executing the commands above, you might see output like:\n\n```\nLanguages:\nKey: nl, Name: Dutch\nKey: fr, Name: French\n\nCountries:\nCode: be, Name: Belgium, SpokenLanguages: nl, fr\n```\n\n## How It Works\n\n1. **Registration:**  \n   You register each record type with a command name, a lambda to access the target collection from your context, and expressions that define the unique key and positional properties.\n\n2. **Command Parsing:**  \n   The `Run` method tokenizes the input command. It supports quoted strings, simple escape sequences, and recognizes tokens prefixed with `--` as named property assignments.\n   Likewise the `RunMany` method supports multiple commands in a single string, separated by newlines, ignoring empty lines and lines starting with `#`.\n\n3. **Record Updating/Creation:**  \n   The library searches for an existing record using the unique key. If found, it updates the record’s properties; otherwise, it creates a new record and adds it to the collection.\n\n4. **Type Conversion:**  \n   Values are converted to the target property types using built-in conversion mechanisms. Array values can be provided in a JSON–like syntax for easy parsing.\n\n## Features\n\n### Named Arguments\n\nYou can use named arguments to update properties of an existing record. For example:\n```csharp\nRecordCommandRegistry.Run(context, \"add country be --SpokenLanguages=['nl','fr']\");\n```\n\n### Multiple Commands\n\nYou can run multiple commands in a single string, separated by newlines. For example:\n```csharp\nRecordCommandRegistry.RunMany(context, @\"\nadd language nl Dutch\nadd language fr French\nadd country be Belgium\nadd country be --SpokenLanguages=['nl','fr']\n\");\n```\n\n### Comments\n\nYou can add comments to your command strings by starting a line with `#`. For example:\n```csharp\nRecordCommandRegistry.RunMany(context, @\"\nadd language nl Dutch\nadd language fr French\n# Add Belgium with Dutch and French as spoken languages\nadd country be --SpokenLanguages=['nl','fr']\n\");\n```\n\n### Alias Attribute\n\nYou can use the `AliasAttribute` to provide alternative names for the command and properties. For example:\n```csharp\n[Alias(\"lang\")]\npublic class Language\n{\n    public string Key { get; set; }\n    [Alias(\"n\")]\n    public string Name { get; set; }\n}\n```\n\n### Custom Commands\n\nYou can create custom commands by calling the RegisterCommand method. For example:\n```csharp\nRecordCommandRegistry\u003cMyData\u003e.RegisterCommand(\"clear\", (MyData ctx) =\u003e ctx.Languages.Clear());\nRecordCommandRegistry.Run(context, \"clear\");\n```\n\n### Custom Commands with optional arguments\n\nYou can create custom commands with optional arguments by calling the RegisterCommand method. For example:\n```csharp\nRecordCommandRegistry\u003cMyData\u003e.RegisterCommand(\"clear\", (MyData ctx, string argument, int optionalArg = 10) =\u003e ctx.Languages.Clear());\nRecordCommandRegistry.Run(context, \"clear arg1\");\nRecordCommandRegistry.Run(context, \"clear arg1 20\");\n```\n\n### Custom Conversions\n\nYou can register custom converters for the types. For example:\n```csharp\nRecordCommandRegistry\u003cTestContext\u003e.RegisterCustomConverter((ctx, code) =\u003e ctx.Countries.Find(c =\u003e c.Code == code));\n```\n\n### Generating Commands\n\nYou can generate commands from existing records. For example:\n```csharp\nvar lang = new Language { Key = \"en\", Name = \"English Language\" };\nvar cmd = RecordCommandRegistry\u003cTestContext\u003e.GenerateCommand(lang);\nAssert.Equal(\"add language en \\\"English Language\\\"\", cmd);\n```\n\n### Method Mapping\n\nYou can call methods on your objects using the `--Property:Argument=Value` syntax. For example:\n\n```csharp\n// Assuming Language has a method SetLabel(string culture, string label)\nRecordCommandRegistry.Run(context, \"add language en English --SetLabel:de=Englisch\");\n```\n\nThis will find or create a language with key \"en\", set its Name to \"English\", and then call the SetLabel method with arguments \"de\" and \"Englisch\".\n\n### Command Generation Options\n\nWhen generating commands from existing objects, you can control the output format using `CommandGenerationOptions`:\n\n```csharp\n// Generate with aliases instead of full property names\nvar options = new CommandGenerationOptions(preferAliases: true);\nvar cmd = RecordCommandRegistry\u003cMyData\u003e.GenerateCommand(record, options);\n\n// Generate with named arguments instead of positional properties\nvar options = new CommandGenerationOptions(usePositionalProperties: false);\nvar cmd = RecordCommandRegistry\u003cMyData\u003e.GenerateCommand(record, options);\n\n// Include default values in the generated command\nvar options = new CommandGenerationOptions(ignoreDefaultValues: false);\nvar cmd = RecordCommandRegistry\u003cMyData\u003e.GenerateCommand(record, options);\n```\n\n### Generating Usage Examples\n\nRecordCommander can generate usage examples for your registered commands:\n\n```csharp\n// Get a basic usage example\nstring example = RecordCommandRegistry\u003cMyData\u003e.GetUsageExample\u003cCountry\u003e();\n// Output: \"add country \u003cCode\u003e \u003cName\u003e \u003cSpokenLanguages\u003e\"\n\n// Get a detailed usage example with parameter descriptions\nstring detailed = RecordCommandRegistry\u003cMyData\u003e.GetDetailedUsageExample\u003cCountry\u003e();\n// Output includes parameter types and descriptions\n```\n\nThis is particularly useful for documentation or CLI help text.\n\n### Custom Command Prompts\n\n`GetCustomCommandPrompt` can generate usage text for a custom command and even include parameter descriptions:\n\n```csharp\nstring prompt = RecordCommandRegistry\u003cTestContext\u003e.GetCustomCommandPrompt(\"log4\");\n// log4 \u003clog\u003e \u003cx\u003e \u003cy\u003e \u003cz\u003e \u003cts\u003e \u003cg\u003e\n\nstring detailed = RecordCommandRegistry\u003cTestContext\u003e.GetCustomCommandPrompt(\"log4\", true);\n/*\nlog4 \u003clog\u003e \u003cx\u003e \u003cy\u003e \u003cz\u003e \u003cts\u003e \u003cg\u003e\n#   log : string (quoted if contains spaces) - Message to log\n#   x : date (format yyyy-MM-dd)\n#   y : date (format yyyy-MM-dd)\n#   z : number\n#   ts : timespan\n#   g : guid\n*/\n```\n\nThis is helpful when building CLI help text for custom operations.\n\n### Enum and Flags Support\n\nRecordCommander handles both regular enums and flags enums:\n\n```csharp\n// Using a regular enum\nRecordCommandRegistry.Run(context, \"add book 978-1234567890 \\\"My Book\\\" \\\"Jane Doe\\\" --Status=Borrowed\");\n\n// Using a flags enum (combine multiple values with commas)\nRecordCommandRegistry.Run(context, \"add book 978-1234567890 \\\"My Book\\\" \\\"Jane Doe\\\" --Flags=Fiction,Mystery,Romance\");\n```\n\n### Default Value Handling\n\nRecordCommander respects the `DefaultValueAttribute` on properties:\n\n```csharp\npublic class SampleRecord\n{\n    public string Id { get; set; }\n    \n    [DefaultValue(-1)]\n    public int Age { get; set; } = -1;\n    \n    [DefaultValue(true)]\n    public bool IsActive { get; set; } = true;\n}\n```\n\nWhen generating commands, properties with default values can be omitted:\n\n```csharp\nvar record = new SampleRecord { Id = \"123\", Name = \"Alice\" };\nvar cmd = RecordCommandRegistry\u003cMyData\u003e.GenerateCommand(record);\n// Age and IsActive won't appear in the command if they have default values\n```\n\n## Use Cases\n\n### AI\n\nOnce you have a simple set of commands, you can use AI models to let you generate the data for you, for example giving the following propmt to GPT-4o:\n```\nadd country BE \"Belgium\" --SpokenLanguages=['nl','fr']\nadd country DE \"Germany\" --SpokenLanguages=[\"de\"]\nadd country FR \"France\" --SpokenLanguages=[\"fr\"]\n\ncan you extend the list with all the EU countries in the same format as above\n```\n\nIt will then generate the following output:\n```\nadd country AT \"Austria\" --SpokenLanguages=[\"de\"]\nadd country BE \"Belgium\" --SpokenLanguages=['nl','fr']\nadd country BG \"Bulgaria\" --SpokenLanguages=[\"bg\"]\nadd country HR \"Croatia\" --SpokenLanguages=[\"hr\"]\nadd country CY \"Cyprus\" --SpokenLanguages=[\"el\"]\nadd country CZ \"Czech Republic\" --SpokenLanguages=[\"cs\"]\nadd country DK \"Denmark\" --SpokenLanguages=[\"da\"]\nadd country EE \"Estonia\" --SpokenLanguages=[\"et\"]\nadd country FI \"Finland\" --SpokenLanguages=[\"fi\", \"sv\"]\nadd country FR \"France\" --SpokenLanguages=[\"fr\"]\nadd country DE \"Germany\" --SpokenLanguages=[\"de\"]\nadd country EL \"Greece\" --SpokenLanguages=[\"el\"]\nadd country HU \"Hungary\" --SpokenLanguages=[\"hu\"]\nadd country IE \"Ireland\" --SpokenLanguages=[\"en\", \"ga\"]\nadd country IT \"Italy\" --SpokenLanguages=[\"it\"]\nadd country LV \"Latvia\" --SpokenLanguages=[\"lv\"]\nadd country LT \"Lithuania\" --SpokenLanguages=[\"lt\"]\nadd country LU \"Luxembourg\" --SpokenLanguages=[\"lb\", \"fr\", \"de\"]\nadd country MT \"Malta\" --SpokenLanguages=[\"mt\", \"en\"]\nadd country NL \"Netherlands\" --SpokenLanguages=[\"nl\"]\nadd country PL \"Poland\" --SpokenLanguages=[\"pl\"]\nadd country PT \"Portugal\" --SpokenLanguages=[\"pt\"]\nadd country RO \"Romania\" --SpokenLanguages=[\"ro\"]\nadd country SK \"Slovakia\" --SpokenLanguages=[\"sk\"]\nadd country SI \"Slovenia\" --SpokenLanguages=[\"sl\"]\nadd country ES \"Spain\" --SpokenLanguages=[\"es\"]\nadd country SE \"Sweden\" --SpokenLanguages=[\"sv\"]\n```\n\n### Dev Data\n\nYou can use this library to seed data for your development environment.\n\n### Bug Reproduction\n\nYou can use this library to reproduce bugs in your application by creating the same data that caused the bug.\n\n### Documentation\n\nYou can use this library to generate sample data for your documentation. So that the user reading your documentation can copy and paste the commands to seed the data.\n\n### Generating commands\n\nYou can use this library to generate commands from existing records. Check the following test:\n\n```csharp\n[Fact]\npublic void Generation_UsingSpaces()\n{\n    var lang = new Language { Key = \"en\", Name = \"English Language\" };\n    var cmd = RecordCommandRegistry\u003cTestContext\u003e.GenerateCommand(lang);\n    Assert.Equal(\"add language en \\\"English Language\\\"\", cmd);\n}\n```\n\nThis could be used for exporting data from your application.\n\n## Limitations (at the moment)\n\n- **No Validation:**  \n  The library does not perform any validation on the input data. You should validate the data before using it in your application.\n- **Performance:**  \n  The library is not optimized for performance. It is designed to be simple and easy to use.\n\n## Contributing\n\nContributions are welcome! If you have suggestions or improvements, please open an issue or submit a pull request.\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2sky%2Frecordcommander","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F2sky%2Frecordcommander","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2sky%2Frecordcommander/lists"}