Skip to content

Commit 9240950

Browse files
committed
Need still to fix ListTreeTest
1 parent 91f3bb4 commit 9240950

File tree

10 files changed

+391
-43
lines changed

10 files changed

+391
-43
lines changed

DataModel.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,7 @@ The constructor will look like this:
263263
```csharp
264264
public DefaultValuePropertyClass(string name, string defaultValueProperty = "NoName", bool isStoring = true) {
265265
```
266-
Note:
267-
The properties arguments in the constructor are in the same sequence like the properties in the data class. Once
266+
**Note:** The properties arguments in the constructor are in the same sequence like the properties in the data class. Once
268267
an argument has a default value, all following arguments must have a default value too. The same applies for
269268
the property definitions in the data class: once one property has a default value, all following properties must
270269
have a default value too.
@@ -391,7 +390,7 @@ public class OrderItem {
391390
public Item Item;
392391
}
393392
```
394-
Note: Order is a *data class* defined somewhere else in the *Data Model*
393+
`Order` is a *data class* defined somewhere else in the *Data Model*
395394

396395

397396
# Parent with single child, 1:c or c:c
@@ -417,8 +416,7 @@ Note that the `Manager` property in the `Department` must be *nullable*.
417416

418417
# One to one relationships cannot be implemented, 1:1
419418

420-
Example:
421-
A country has exactly one capital, a capital belongs exactly to one country. This would actually be
419+
**Example:** A country has exactly one capital, a capital belongs exactly to one country. This would actually be
422420
a 1:1 relationship. A 1:1 relationship cannot be created, because one item cannot
423421
exist without the other item. However, *StorageLib* can read and create only one instance at a time.
424422

@@ -435,7 +433,7 @@ required, the 1:1 relationship gets replaced by 1:c.
435433
public Country? CountryCapital;
436434
}
437435
```
438-
Note: It is difficult to find a good 1:1 relationship example. In actual fact, each City would
436+
**Note:** It is difficult to find a good 1:1 relationship example. In actual fact, each City would
439437
belong to one country and each country would have one capital. However, *StorageLib* does not
440438
support 2 classes being a child of each other. Instead, defining a `Capital` class would be a
441439
better idea.
@@ -544,7 +542,7 @@ For this reason all children must be released before the parent can be released.
544542

545543
Sometimes a parent can have several collections for the same child type.
546544

547-
Example: A flight (=child) has a departure airport and a destination airport. An airport
545+
**Example:** A flight (=child) has a departure airport and a destination airport. An airport
548546
(=parent) has a collection for departing flights and arriving flights.
549547

550548
```charp
@@ -693,7 +691,7 @@ like all items which were created on the same day. In a Dictionary, no 2 items c
693691
same key value. In SortedBucketCollection, only the combination of first and second key must
694692
be unique.
695693

696-
Example: A simplicistic financial application might have accounts, like Cash or Expenses and
694+
**Example:** A simplicistic financial application might have accounts, like Cash or Expenses and
697695
AccountsItem, stating on which date for which account a certain amount needs to be stored.
698696

699697
```csharp
@@ -710,7 +708,7 @@ public class AccountItem {
710708
}
711709
```
712710

713-
Note: If StorageClassGenerator cannot find any int property in the child class of the data model, it will
711+
**Note:** If StorageClassGenerator cannot find any int property in the child class of the data model, it will
714712
take the autogenerated Key property. In this example, the AccountItems get first sorted
715713
by Date. If there are two AccountItems with the same Date value, Key is a usefull property to uniquly identify them.
716714

ParserTest/ParserTest.csproj

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
11+
<!--<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
1212
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
1313
<PackageReference Include="MSTest.TestAdapter" Version="2.2.7" />
1414
<PackageReference Include="MSTest.TestFramework" Version="2.2.7" />
15-
<PackageReference Include="coverlet.collector" Version="3.1.0" />
15+
<PackageReference Include="coverlet.collector" Version="3.1.0" />-->
16+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
17+
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
18+
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
19+
<PackageReference Include="coverlet.collector" Version="3.1.2" />
20+
1621
</ItemGroup>
1722

1823
<ItemGroup>

StorageClassGenerator/ClassInfo.cs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ private void writeCsvConstructor(StreamWriter sw, string context) {
935935
sw.WriteLine(" /// <summary>");
936936
sw.WriteLine($" /// Constructor for {ClassName} read from CSV file");
937937
sw.WriteLine(" /// </summary>");
938-
sw.WriteLine($" private {ClassName}(int key, CsvReader csvReader){{");
938+
sw.WriteLine($" private {ClassName}(int key, CsvReader csvReader, DataStoreCSV<{ClassName}> dataStore){{");
939939
sw.WriteLine(" Key = key;");
940940
//var isVarNeeded = true;
941941
//var isVarNullableNeeded = true;
@@ -961,11 +961,19 @@ MemberTypeEnum.ParentMultipleChildrenDictionary or
961961
if (mi.IsNullable) {
962962
sw.WriteLine($" var {mi.LowerMemberName}Key = csvReader.ReadIntNull();");
963963
sw.WriteLine($" if ({mi.LowerMemberName}Key.HasValue) {{");
964-
sw.WriteLine($" {mi.MemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem({mi.LowerMemberName}Key.Value)?? {mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
964+
if (mi.IsSelfReferencing) {
965+
sw.WriteLine($" {mi.MemberName} = dataStore.GetItem({mi.LowerMemberName}Key.Value)?? {mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
966+
} else {
967+
sw.WriteLine($" {mi.MemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem({mi.LowerMemberName}Key.Value)?? {mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
968+
}
965969
sw.WriteLine(" }");
966970
} else {
967971
sw.WriteLine($" var {mi.LowerMemberName}Key = csvReader.ReadInt();");
968-
sw.WriteLine($" {mi.MemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem({mi.LowerMemberName}Key)?? {mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};"); //if (isVarNeeded) {
972+
if (mi.IsSelfReferencing) {
973+
sw.WriteLine($" {mi.MemberName} = dataStore.GetItem({mi.LowerMemberName}Key)?? {mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
974+
} else {
975+
sw.WriteLine($" {mi.MemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem({mi.LowerMemberName}Key)?? {mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
976+
}
969977
}
970978
} else {
971979
//enum, simple data type
@@ -1002,8 +1010,8 @@ MemberTypeEnum.ParentMultipleChildrenDictionary or
10021010
sw.WriteLine(" /// <summary>");
10031011
sw.WriteLine($" /// New {ClassName} read from CSV file");
10041012
sw.WriteLine(" /// </summary>");
1005-
sw.WriteLine($" internal static {ClassName} Create(int key, CsvReader csvReader) {{");
1006-
sw.WriteLine($" return new {ClassName}(key, csvReader);");
1013+
sw.WriteLine($" internal static {ClassName} Create(int key, CsvReader csvReader, DataStoreCSV<{ClassName}> dataStore) {{");
1014+
sw.WriteLine($" return new {ClassName}(key, csvReader, dataStore);");
10071015
sw.WriteLine(" }");
10081016
}
10091017

@@ -1372,7 +1380,7 @@ private void writeUpdateCsv(StreamWriter sw, string context) {
13721380
sw.WriteLine(" /// <summary>");
13731381
sw.WriteLine($" /// Updates this {ClassName} with values from CSV file");
13741382
sw.WriteLine(" /// </summary>");
1375-
sw.WriteLine($" internal static void Update({ClassName} {LowerClassName}, CsvReader csvReader){{");
1383+
sw.WriteLine($" internal static void Update({ClassName} {LowerClassName}, CsvReader csvReader, DataStoreCSV<{ClassName}> dataStore){{");
13761384

13771385
sw.WriteLine(" //read first all property values into local variables");
13781386
var isFirst = true;
@@ -1398,11 +1406,19 @@ private void writeUpdateCsv(StreamWriter sw, string context) {
13981406
sw.WriteLine($" if ({mi.LowerMemberName}Key is null) {{");
13991407
sw.WriteLine($" {mi.LowerMemberName} = null;");
14001408
sw.WriteLine(" } else {");
1401-
sw.WriteLine($" {mi.LowerMemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem({mi.LowerMemberName}Key.Value)??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1409+
if (mi.IsSelfReferencing) {
1410+
sw.WriteLine($" {mi.LowerMemberName} = dataStore.GetItem({mi.LowerMemberName}Key.Value)??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1411+
} else {
1412+
sw.WriteLine($" {mi.LowerMemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem({mi.LowerMemberName}Key.Value)??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1413+
}
14021414
sw.WriteLine(" }");
14031415

14041416
} else {
1405-
sw.WriteLine($" var {mi.LowerMemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem(csvReader.ReadInt())??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1417+
if (mi.IsSelfReferencing) {
1418+
sw.WriteLine($" var {mi.LowerMemberName} = dataStore.GetItem(csvReader.ReadInt())??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1419+
} else {
1420+
sw.WriteLine($" var {mi.LowerMemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem(csvReader.ReadInt())??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1421+
}
14061422
}
14071423

14081424
} else {
@@ -1425,10 +1441,18 @@ private void writeUpdateCsv(StreamWriter sw, string context) {
14251441
sw.WriteLine($" if ({mi.LowerMemberName}Key is null) {{");
14261442
sw.WriteLine($" {mi.LowerMemberName} = null;");
14271443
sw.WriteLine( " } else {");
1428-
sw.WriteLine($" {mi.LowerMemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem({mi.LowerMemberName}Key.Value)??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1444+
if (mi.IsSelfReferencing) {
1445+
sw.WriteLine($" {mi.LowerMemberName} = dataStore.GetItem({mi.LowerMemberName}Key.Value)??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1446+
} else {
1447+
sw.WriteLine($" {mi.LowerMemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem({mi.LowerMemberName}Key.Value)??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1448+
}
14291449
sw.WriteLine( " }");
14301450
} else {
1431-
sw.WriteLine($" var {mi.LowerMemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem(csvReader.ReadInt())??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1451+
if (mi.IsSelfReferencing) {
1452+
sw.WriteLine($" var {mi.LowerMemberName} = dataStore.GetItem(csvReader.ReadInt())??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1453+
} else {
1454+
sw.WriteLine($" var {mi.LowerMemberName} = {context}.Data._{mi.ParentClassInfo!.PluralName}.GetItem(csvReader.ReadInt())??{mi.TypeStringNotNullable}.No{mi.TypeStringNotNullable};");
1455+
}
14321456
}
14331457

14341458
} else if (mi.MemberType<MemberTypeEnum.LinkToParent) {

StorageClassGenerator/Compiler.cs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -327,14 +327,28 @@ public void AnalyzeDependencies() {
327327
//parent and children, while the second loop (LinkToParent only) verifies that every child has a parent.
328328
foreach (var ci in classes.Values) {
329329
foreach (var mi in ci.Members.Values) {
330-
if (mi.ChildTypeName==ci.ClassName) {
331-
throw new GeneratorException($"In the class {ci}, the property '{mi}' references its own class, " +
332-
$"which StorageLib cannot support. The reason is that 2 instances of {ci.ClassName} reference " +
333-
"each other. When the data gets read from a file, the first instance needs to get created with a " +
334-
"reference to the other instance, which does not exist yet. A not existing reference throws " +
335-
"an exception." + Environment.NewLine +
336-
mi.MemberText);
330+
if (mi.MemberType==MemberTypeEnum.LinkToParent) {
331+
if (mi.TypeStringNotNullable==ci.ClassName) {
332+
//a property referencing its own class, of which it is a property
333+
if (!mi.IsNullable) {
334+
throw new GeneratorException(ci, mi, $"Property {mi.MemberName} is linking to the class it belongs to, " +
335+
$"which is useful for tree shaped data structures. {mi.MemberName} must be nullable, because at least " +
336+
$"for the very first instance of {mi.ClassInfo.ClassName} (= tree trunk), no other instance exists that " +
337+
$"can be linked too.");
338+
}
339+
mi.IsSelfReferencing = mi.TypeStringNotNullable==ci.ClassName;
340+
}
341+
} else if (mi.ChildTypeName==ci.ClassName) {
342+
//a child collection referencing its own class, of which it is a property
343+
if (mi.MemberType==MemberTypeEnum.ParentMultipleChildrenList) {
344+
mi.IsSelfReferencing = true;
345+
} else {
346+
throw new GeneratorException(ci, mi, $"In the class {ci}, the property '{mi}' references its own class, " +
347+
$"which StorageLib currently does not support. Hierachical tree functionality is presently only supported " +
348+
$"where the children collection is a list. ");
349+
}
337350
}
351+
338352
if (mi.MemberType>=MemberTypeEnum.ToLower) {
339353
var isFound = false;
340354
switch (mi.MemberType) {
@@ -1037,7 +1051,12 @@ private static void setupParentClassChildClassLinks(
10371051
parentCI.Children.Add(childCI);
10381052
childCI.ParentsAll.Add(parentCI);
10391053
childCI.HasParents = true;
1040-
topClasses.Remove(childCI.ClassName);
1054+
if (parentCI==childCI) {
1055+
//a self referencing class (isListTree==true). It is not just a child, but at the same time also a parent
1056+
//and should therefore not yet get removed from topClasses
1057+
} else {
1058+
topClasses.Remove(childCI.ClassName);
1059+
}
10411060
}
10421061

10431062

@@ -1229,7 +1248,7 @@ private void addToParentChildTree(ClassInfo classInfo) {
12291248

12301249
private static bool allParentsAreAddedToParentChildTree(ClassInfo childClass) {
12311250
foreach (var parentClass in childClass.ParentsAll) {
1232-
if (!parentClass.IsAddedToParentChildTree) return false;
1251+
if (!parentClass.IsAddedToParentChildTree && parentClass!=childClass) return false;
12331252
}
12341253
return true;
12351254
}

StorageClassGenerator/MemberInfo.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ public class MemberInfo {
4848
public readonly string? PrecissionComment;
4949
public readonly string? Rounding;
5050
public readonly string? DefaultValue;
51-
public readonly bool IsLookupOnly = false;
52-
public readonly bool NeedsDictionary = false;
51+
public readonly bool IsLookupOnly;
52+
public readonly bool NeedsDictionary;
53+
public bool IsSelfReferencing; //this parent property links to the class it belongs to. This is typically used in a tree structure.
5354
public readonly int MaxStorageSize;
5455
public readonly string? ChildTypeName; //used by ParentMultipleChildrenXxx: List, HashSet, Dictionary, SortedList and SortedBucketCollection
5556
public readonly string? LowerChildTypeName; //used by ParentMultipleChildrenXxx
@@ -155,7 +156,7 @@ public MemberInfo(
155156
NoValue = "DateTime.MinValue";
156157
}
157158
ToStringFunc = "";
158-
PrecissionComment = "Stores date and time with minute preclusion.";
159+
PrecissionComment = "Stores date and time with minute precision.";
159160
Rounding = ".Round(Rounding.Minutes)";
160161
break;
161162

StorageClassGenerator/StorageClassGenerator.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
10+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" />
1111
</ItemGroup>
1212

1313
</Project>

StorageLib/DataStoreCSV.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ public class DataStoreCSV<TItemCSV>: DataStore<TItemCSV>
8686
#region Constructor
8787
// ------------
8888

89-
Func<int, CsvReader, TItemCSV?> create;
89+
Func<int, CsvReader, DataStoreCSV<TItemCSV>, TItemCSV?> create;
9090
Func<TItemCSV, bool>? verify;
91-
Action<TItemCSV, CsvReader>? update;
91+
Action<TItemCSV, CsvReader, DataStoreCSV<TItemCSV>>? update;
9292
Action<TItemCSV, CsvWriter>? write;
9393
Action<TItemCSV>? disconnect;
9494

@@ -131,9 +131,9 @@ public DataStoreCSV(
131131
int maxLineLenght,
132132
string[] headers,
133133
Action<IStorageItem, int, /*isRollback*/bool> setKey,
134-
Func<int, CsvReader, TItemCSV> create,
134+
Func<int, CsvReader, DataStoreCSV<TItemCSV>, TItemCSV> create,
135135
Func<TItemCSV, bool>? verify,
136-
Action<TItemCSV, CsvReader>? update,
136+
Action<TItemCSV, CsvReader, DataStoreCSV<TItemCSV>>? update,
137137
Action<TItemCSV, CsvWriter> write,
138138
Action<TItemCSV>? disconnect,
139139
Action<IStorageItem> rollbackItemNew,
@@ -277,7 +277,7 @@ private void readFromCsvFile(CsvReader csvReader) {
277277
IsReadFromBakFile = true;
278278
var key = csvReader.ReadInt();
279279
var item = this[key];
280-
update!(item, csvReader);
280+
update!(item, csvReader, this);
281281
csvReader.ReadEndOfLine();
282282

283283
} else {
@@ -307,9 +307,9 @@ private void readFromCsvFile(CsvReader csvReader) {
307307
private void addItem(CsvReader csvReader, StringBuilder errorStringBuilder) {
308308
TItemCSV? item;
309309
if (IsReadOnly) {
310-
item = create(LastItemIndex+1, csvReader);
310+
item = create(LastItemIndex+1, csvReader, this);
311311
} else {
312-
item = create(csvReader.ReadInt(), csvReader);
312+
item = create(csvReader.ReadInt(), csvReader, this);
313313
}
314314
if (errorStringBuilder.Length==0) {
315315
AddProtected(item!);

0 commit comments

Comments
 (0)