Skip to content

Commit 4ea2734

Browse files
Refactor Schema Library Documentation and Examples
- Updated architecture documentation to reflect changes in the Schema class structure, including the removal of file management responsibilities and the introduction of new CRUD operations. - Revised basic schema example to align with the new API, including changes to member type assignments and serialization methods. - Enhanced schema editor documentation by streamlining features and improving clarity on user interface elements and functionalities. - Adjusted getting started guide to accommodate updates in library usage, including NuGet installation instructions and schema serialization. - Improved consistency in code examples across documentation, ensuring usage of new methods and types introduced in recent updates.
1 parent 9e5d8d5 commit 4ea2734

5 files changed

Lines changed: 355 additions & 654 deletions

File tree

README.md

Lines changed: 59 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -42,33 +42,34 @@ using ktsu.Schema.Models;
4242
using ktsu.Schema.Models.Names;
4343
using ktsu.Schema.Models.Types;
4444
using ktsu.Semantics.Strings;
45+
using SchemaTypes = ktsu.Schema.Models.Types;
4546

4647
// Create a new schema
47-
var schema = new Schema();
48+
Schema schema = new();
4849

4950
// Add an enum
50-
var roleEnum = schema.AddEnum("UserRole".As<EnumName>());
51+
SchemaEnum? roleEnum = schema.AddEnum("UserRole".As<EnumName>());
5152
roleEnum?.TryAddValue("Admin".As<EnumValueName>());
5253
roleEnum?.TryAddValue("User".As<EnumValueName>());
5354
roleEnum?.TryAddValue("Guest".As<EnumValueName>());
5455

5556
// Add a class with typed members
56-
var userClass = schema.AddClass("User".As<ClassName>());
57+
SchemaClass? userClass = schema.AddClass("User".As<ClassName>());
5758
if (userClass != null)
5859
{
59-
var id = userClass.AddMember("Id".As<MemberName>());
60+
SchemaMember? id = userClass.AddMember("Id".As<MemberName>());
6061
id?.SetType(new SchemaTypes.Int());
6162

62-
var name = userClass.AddMember("Name".As<MemberName>());
63+
SchemaMember? name = userClass.AddMember("Name".As<MemberName>());
6364
name?.SetType(new SchemaTypes.String());
6465

65-
var email = userClass.AddMember("Email".As<MemberName>());
66+
SchemaMember? email = userClass.AddMember("Email".As<MemberName>());
6667
email?.SetType(new SchemaTypes.String());
6768

68-
var role = userClass.AddMember("Role".As<MemberName>());
69+
SchemaMember? role = userClass.AddMember("Role".As<MemberName>());
6970
role?.SetType(new SchemaTypes.Enum { EnumName = "UserRole".As<EnumName>() });
7071

71-
var createdAt = userClass.AddMember("CreatedAt".As<MemberName>());
72+
SchemaMember? createdAt = userClass.AddMember("CreatedAt".As<MemberName>());
7273
createdAt?.SetType(new SchemaTypes.DateTime());
7374
}
7475
```
@@ -77,22 +78,22 @@ if (userClass != null)
7778

7879
```csharp
7980
// Add a Project class
80-
var projectClass = schema.AddClass("Project".As<ClassName>());
81-
var projectId = projectClass?.AddMember("Id".As<MemberName>());
81+
SchemaClass? projectClass = schema.AddClass("Project".As<ClassName>());
82+
SchemaMember? projectId = projectClass?.AddMember("Id".As<MemberName>());
8283
projectId?.SetType(new SchemaTypes.Int());
83-
var projectName = projectClass?.AddMember("Name".As<MemberName>());
84+
SchemaMember? projectName = projectClass?.AddMember("Name".As<MemberName>());
8485
projectName?.SetType(new SchemaTypes.String());
8586

8687
// Add an array of projects to the User class
87-
var projects = userClass?.AddMember("Projects".As<MemberName>());
88+
SchemaMember? projects = userClass?.AddMember("Projects".As<MemberName>());
8889
projects?.SetType(new SchemaTypes.Array
8990
{
9091
ElementType = new SchemaTypes.Object { ClassName = "Project".As<ClassName>() },
9192
Container = "vector".As<ContainerName>()
9293
});
9394

9495
// Use a keyed collection (map)
95-
var projectsMap = userClass?.AddMember("ProjectsById".As<MemberName>());
96+
SchemaMember? projectsMap = userClass?.AddMember("ProjectsById".As<MemberName>());
9697
projectsMap?.SetType(new SchemaTypes.Array
9798
{
9899
ElementType = new SchemaTypes.Object { ClassName = "Project".As<ClassName>() },
@@ -108,21 +109,34 @@ projectsMap?.SetType(new SchemaTypes.Array
108109
schema.AddClass(typeof(MyExistingClass));
109110
```
110111

112+
### Serialize and Deserialize
113+
114+
```csharp
115+
// Serialize to JSON
116+
string json = SchemaSerializer.Serialize(schema);
117+
118+
// Deserialize from JSON (automatically calls Reassociate())
119+
if (SchemaSerializer.TryDeserialize(json, out Schema? loaded))
120+
{
121+
Console.WriteLine($"Loaded {loaded.Classes.Count} classes");
122+
}
123+
```
124+
111125
### Query the Schema
112126

113127
```csharp
114128
// Retrieve classes and enums
115-
if (schema.TryGetClass("User".As<ClassName>(), out var userClass))
129+
if (schema.TryGetClass("User".As<ClassName>(), out SchemaClass? foundClass))
116130
{
117-
foreach (var member in userClass.Members)
131+
foreach (SchemaMember member in foundClass.Members)
118132
{
119133
Console.WriteLine($" {member.Name}: {member.Type.DisplayName}");
120134
}
121135
}
122136

123-
if (schema.TryGetEnum("UserRole".As<EnumName>(), out var roleEnum))
137+
if (schema.TryGetEnum("UserRole".As<EnumName>(), out SchemaEnum? foundEnum))
124138
{
125-
foreach (var value in roleEnum.Values)
139+
foreach (EnumValueName value in foundEnum.Values)
126140
{
127141
Console.WriteLine($" {value}");
128142
}
@@ -163,39 +177,43 @@ Convert strings using the `.As<T>()` extension method: `"User".As<ClassName>()`
163177

164178
## JSON Serialization
165179

166-
Schemas serialize to JSON using `System.Text.Json` with polymorphic type discrimination. The `TypeName` property identifies concrete types:
180+
Use `SchemaSerializer` for JSON serialization with `System.Text.Json`. The serializer uses camelCase property names and polymorphic type discrimination via the `TypeName` discriminator:
167181

168182
```json
169183
{
170-
"Classes": [
184+
"classes": [
185+
{
186+
"name": "User",
187+
"description": "",
188+
"members": [
171189
{
172-
"Name": "User",
173-
"Members": [
174-
{
175-
"Name": "Id",
176-
"Type": { "TypeName": "Int" }
177-
},
178-
{
179-
"Name": "Role",
180-
"Type": { "TypeName": "Enum", "EnumName": "UserRole" }
181-
}
182-
]
183-
}
184-
],
185-
"Enums": [
190+
"name": "Id",
191+
"description": "",
192+
"type": { "TypeName": "Int" },
193+
"memberDescription": ""
194+
},
186195
{
187-
"Name": "UserRole",
188-
"Values": [
189-
{ "Name": "Admin" },
190-
{ "Name": "User" },
191-
{ "Name": "Guest" }
192-
]
196+
"name": "Role",
197+
"description": "",
198+
"type": { "TypeName": "Enum", "enumName": "UserRole" },
199+
"memberDescription": ""
193200
}
194-
]
201+
]
202+
}
203+
],
204+
"enums": [
205+
{
206+
"name": "UserRole",
207+
"description": "",
208+
"values": ["Admin", "User", "Guest"]
209+
}
210+
],
211+
"dataSources": [],
212+
"codeGenerators": []
195213
}
196214
```
197215

198-
After deserialization, call `schema.Reassociate()` to re-establish parent-child relationships.
216+
`SchemaSerializer.TryDeserialize()` automatically calls `Reassociate()` to re-establish parent-child relationships after deserialization.
199217

200218
## Schema Editor
201219

@@ -228,15 +246,6 @@ dotnet test
228246
dotnet build Schema/Schema.csproj
229247
```
230248

231-
## Documentation
232-
233-
Detailed documentation is available in the [docs/](docs/) folder:
234-
235-
- [Getting Started](docs/getting-started.md) - Installation and first schema
236-
- [Basic Schema Example](docs/examples/basic-schema.md) - Complete walkthrough
237-
- [Architecture](docs/development/architecture.md) - Design patterns and data flow
238-
- [Schema Editor Guide](docs/features/schema-editor.md) - Visual editor usage
239-
240249
## License
241250

242251
This project is licensed under the MIT License. See [LICENSE.md](LICENSE.md) for details.

docs/development/architecture.md

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -75,64 +75,64 @@ This document provides a high-level overview of the Schema library architecture,
7575
### Schema (Root Container)
7676

7777
```csharp
78-
public partial class Schema
78+
public class Schema
7979
{
80-
// Collections of schema elements
80+
// Collections of schema elements (read-only public API)
8181
public IReadOnlyCollection<SchemaClass> Classes { get; }
8282
public IReadOnlyCollection<SchemaEnum> Enums { get; }
8383
public IReadOnlyCollection<DataSource> DataSources { get; }
84-
85-
// File management
86-
public AbsoluteFilePath FilePath { get; }
87-
public SchemaPaths RelativePaths { get; }
84+
public IReadOnlyCollection<SchemaCodeGenerator> CodeGenerators { get; }
8885

8986
// CRUD operations
9087
public SchemaClass? AddClass(ClassName name);
9188
public bool TryGetClass(ClassName name, out SchemaClass? schemaClass);
92-
// ... similar for Enums, DataSources
89+
// ... similar for Enums, DataSources, CodeGenerators
9390
}
9491
```
9592

9693
**Responsibilities:**
9794

9895
- Container for all schema elements
99-
- File I/O operations (load/save)
100-
- Element lifecycle management
101-
- Cross-reference validation
96+
- Element lifecycle management (add, get, remove)
97+
- Parent-child relationship management via `Reassociate()`
98+
- Type queries across all classes
10299

103100
### Schema Elements Hierarchy
104101

105102
```
106-
SchemaChild<T> (Abstract Base)
103+
SchemaChild<T> (Abstract Base - has Name, Description, ParentSchema)
107104
├── SchemaClass : SchemaChild<ClassName>
108105
├── SchemaEnum : SchemaChild<EnumName>
109106
├── DataSource : SchemaChild<DataSourceName>
110107
└── SchemaCodeGenerator : SchemaChild<CodeGeneratorName>
111108
112-
SchemaMemberChild<T> (Abstract Base)
113-
└── SchemaTypes.BaseType : SchemaMemberChild<BaseTypeName>
114-
├── Primitive Types (Int, String, Bool, etc.)
115-
├── Vector Types (Vector2, Vector3, etc.)
116-
├── Complex Types (Array, Object, Enum)
117-
└── System Types (DateTime, TimeSpan)
109+
SchemaClassChild<T> : SchemaChild<T> (adds ParentClass)
110+
└── SchemaMember : SchemaClassChild<MemberName>
111+
└── Contains: BaseType (via Type property, set with SetType())
118112
119-
SchemaMember : SchemaMemberChild<MemberName>
120-
└── Contains: SchemaTypes.BaseType
113+
BaseType : IEquatable<BaseType?> (standalone hierarchy, not SchemaChild)
114+
├── Primitive Types: Int, Long, Float, Double, String, Bool
115+
├── Temporal Types: DateTime, TimeSpan
116+
├── Vector Types: Vector2, Vector3, Vector4, ColorRGB, ColorRGBA
117+
├── Complex Types: Array, Object, Enum
118+
└── Special: None
121119
```
122120

123121
### Type System Architecture
124122

125-
The type system is built around a polymorphic hierarchy:
123+
The type system is built around a polymorphic hierarchy using `System.Text.Json`:
126124

127125
```csharp
128126
[JsonPolymorphic(TypeDiscriminatorPropertyName = "TypeName")]
129-
public abstract class BaseType : SchemaMemberChild<BaseTypeName>
127+
[JsonDerivedType(typeof(Int), nameof(Int))]
128+
// ... derived type registrations for all types
129+
public abstract class BaseType : IEquatable<BaseType?>
130130
{
131-
// Core type functionality
132-
public abstract string DisplayName { get; }
133-
public bool IsBuiltIn { get; }
134-
public bool IsPrimitive { get; }
135-
// ... type classification properties
131+
public SchemaMember? ParentMember { get; } // [JsonIgnore]
132+
public string DisplayName { get; } // [JsonIgnore]
133+
public bool IsBuiltIn { get; } // [JsonIgnore]
134+
public bool IsPrimitive { get; } // [JsonIgnore]
135+
// ... type classification properties (all JsonIgnore)
136136
}
137137
```
138138

@@ -142,20 +142,23 @@ public abstract class BaseType : SchemaMemberChild<BaseTypeName>
142142
- **Type Classification**: Properties like `IsBuiltIn`, `IsPrimitive` for runtime decisions
143143
- **Extensibility**: New types can be added by inheriting from `BaseType`
144144

145-
### Strong String Types
145+
### Semantic String Types
146+
147+
Uses `ktsu.Semantics.Strings` for type-safe identifiers:
146148

147149
```csharp
148-
public sealed record class ClassName : StrongStringAbstract<ClassName> { }
149-
public sealed record class MemberName : StrongStringAbstract<MemberName> { }
150-
public sealed record class EnumName : StrongStringAbstract<EnumName> { }
151-
// ... etc
150+
// Name types implement SemanticString<T> and marker interfaces
151+
// ClassName, MemberName, EnumName, EnumValueName, etc.
152+
153+
// Convert strings using the .As<T>() extension
154+
ClassName name = "User".As<ClassName>();
152155
```
153156

154157
**Benefits:**
155158

156159
- Compile-time prevention of parameter confusion
157-
- Implicit conversion from strings via `.As<T>()` extension
158-
- JSON serialization as plain strings
160+
- Conversion from strings via `.As<T>()` extension
161+
- JSON serialization as plain strings (via `RoundTripStringJsonConverterFactory`)
159162
- IntelliSense and refactoring support
160163

161164
## Design Patterns
@@ -190,20 +193,20 @@ public bool IsNumeric => this switch
190193
};
191194
```
192195

193-
### Observer Pattern (Parent-Child Relationships)
196+
### Parent-Child Association Pattern
194197

195198
```csharp
196199
public abstract class SchemaChild<TName>
197200
{
198-
protected Schema? ParentSchema { get; private set; }
201+
[JsonIgnore]
202+
public Schema? ParentSchema { get; private set; }
199203

200-
public void AssociateWith(Schema schema)
201-
{
202-
ParentSchema = schema;
203-
}
204+
public void AssociateWith(Schema schema) => ParentSchema = schema;
204205
}
205206
```
206207

208+
After deserialization, `Schema.Reassociate()` re-establishes all parent references. `SchemaSerializer.TryDeserialize()` calls this automatically.
209+
207210
## Data Flow
208211

209212
### Schema Creation Flow
@@ -264,9 +267,9 @@ Schema (Root)
264267
**Key Points:**
265268

266269
- Schema holds strong references to all elements
267-
- Elements hold weak references back to schema (via interface)
268-
- JSON serialization creates temporary object graphs
269-
- No circular reference issues due to careful design
270+
- Elements hold direct references back to schema (via `ParentSchema`)
271+
- Parent references are marked `[JsonIgnore]` to prevent circular serialization
272+
- `Reassociate()` restores parent references after deserialization
270273

271274
### Performance Considerations
272275

@@ -404,7 +407,6 @@ Schema.Test/
404407

405408
## See Also
406409

407-
- [Project Structure](project-structure.md) - Detailed code organization
408-
- [API Reference](../api/) - Public API documentation
409-
- [Contributing](contributing.md) - Development workflow
410-
- [Performance](performance.md) - Performance optimization guide
410+
- [Getting Started](../getting-started.md) - Basic setup and concepts
411+
- [Basic Schema Example](../examples/basic-schema.md) - Complete walkthrough
412+
- [Schema Editor](../features/schema-editor.md) - Visual editor usage

0 commit comments

Comments
 (0)