Copilot Generate Types for HotBuild (BETA v17.02)
These are the conventions we're striving for in the new HotBuild system.
Goals
- To provide a simple, type-safe object for everything in an app, eg
BlogPost.Tags
which would return anIEnumerable<Tag>
. - Standards based an simple
- very transparent
- Extensible / customizable, without having to create a very complex code generator.
Setup
The Copilot will generate classes into an /AppCode/Data
folder, so that the classes are in the AppCode.Data
namespace.
If you don't configure anything, then this folder will be in the root of your app.
But you can also configure multiple editions, so that you could build into /staging/AppCode/Data
and /live/AppCode/Data
etc.
This is done in the app.json
file. See instructions here.
How it Works
Let's assume we have the content-type BlogPost
The plan is to generate a auto-generated file /AppCode/Data/BlogPostAutoGenerated.cs
which would look like this:
// DO NOT MODIFY THIS FILE - IT IS AUTO-GENERATED
// See also: https://go.2sxc.org/hotbuild-autogen
// To extend it, create a "BlogPost.cs" with this contents:
/*
namespace AppCode.Data
{
public partial class BlogPost
{
// Add your own properties and methods here
}
}
*/
// Generator: DataModelGenerator v17.01.08
// User: 2sichost
// Edition: /staging
// When: 2024-01-31 17:59:00
namespace AppCode.Data
{
// This is a generated class for BlogPost
// If you wish to modify it, create a partial class for "BlogPost" in a separate "BlogPost.cs" file.
/// <summary>
/// BlogPost Data.
/// Default properties such as `.Title` or `.Id` are provided in the base class.
/// Most properties have a simple access, such as `.TermsAndGdprCombined`.
/// For other properties or uses, the common method such as
/// `IsNotEmpty("FieldName")`, `String("FieldName")`, `Children(...)`, `Picture(...)`, `.Html(...)` and more can be used.
/// </summary>
public partial class BlogPost: AppCode.Data.AutoGen.ZagBlogPostAutoGenerated
{
}
}
namespace AppCode.Data.AutoGen
{
/// <summary>
/// Auto-Generated base class for BlogPost.
/// </summary>
public abstract class ZagBlogPostAutoGenerated : Custom.Data.Item16
{
public bool TermsAndGdprCombined => Bool("TermsAndGdprCombined");
public bool TermsEnabled => Bool("TermsEnabled");
public bool GdprEnabled => Bool("GdprEnabled");
public string Description => String("Description", fallback: "");
public string Link => Url("Link");
public ToSic.Sxc.Adam.IFile LinkFile => File("File");
public ToSic.Sxc.Adam.IFolder LinkFolder => Folder("Folder");
}
}
Thoughts about this structure:
- AutoGenerated Class
- The auto-generated class is the base class for the real class
- It is in a sub namespace - atm
AutoGen
to avoid it being access by mistake - It has a special prefix like
Zag...
(Z to be at the end of a list, andag
for auto-generated) to make it very clear that it's auto-generated and should not be used directly. This should help ensure that it's not usually recommended in intellisense (it would, if it just had a suffix). - We need to have a complicated-named class like
BlogPostAutoGenerated
to avoid name clashes with properties in the content type. Otherwise a class calledBlogPost
couldn't have a propertyBlogPost
, but this way it works. - The auto generated needs a weird name - we recommend
Zag...AutoGenerated
to make it very clear and almost impossible to clash with property names. - The AutoGenerated should also be
abstract
so that it can't be instantiated directly. - For now it must inherit from
Custom.Data.CustomItem
- a class which is provided by 2sxc
- Real Class
- We then need the real class with the name matching the ContentType (where possible, see below)
- In same cases this is not possible - eg we have a
App-Resources
type which is a legacy problem, which should be calledAppResources
- We need to have a
partial
class so that the user can extend it with their own properties and methods, without touching the auto-generated file.
- Comments
- We need special comments on top of the file, the real class and the autogenerated to guide the user
- The exact text will be worked out later on
Specs for the Docs
- File Intro
- This file is auto-generated by "
2sichost
" for "/staging
" at2024-01-31 17:59:00
Replace with the actual user, path and date - If you need to extend it, create a partial class for "
BlogPost
" in a separate file.
Replace with the actual content type name - See also: https://go.2sxc.org/hotbuild-autogen
- This file is auto-generated by "
- Class Intro
- This is a generated class for
BlogPost
Replace with the actual content type name - If you wish to modify it, create a partial class for "
BlogPost
" in a separate "BlogPost.cs
" file.
Replace with the actual content type name
- This is a generated class for
- Class Description
BlogPost
Data.
Replace with the actual content type name- Default properties such as
.Title
or.Id
are provided in the base class.
leave as is - Most properties have a simple access, such as
.TermsAndGdprCombined
.
Replace with the first found property - if any, otherwise skip this line - For other properties or uses, the common method such as
String("FieldName")
,Children(...)
,Picture(...)
,.Html(...)
and more can be used available.
leave as is
How Properties are auto-generated
Boolean
is clear, the normal fallback isfalse
, so that's typical- if the developer needs a
bool?
he will have to use theGet<bool?>()
method
- if the developer needs a
String
is clear defaults to""
and notnull
DateTime
is treated asSystem.DateTime
Empty
is ignoredHyperlink
fields should probably default to theUrl(...)
method.string
using theUrl(...)
method is the defaultIFile
is also generated on the[original-name]File
property using theFile(...)
methodIFolder
is also generated on the[original-name]Folder
property using theFolder(...)
method- Note: Since it generates additional names, it may clash with existing fields. In this case, the main field has precedence.
Entity
properties returnITypedItem
If it's configured to have only one itemIEnumerable<ITypedItem>
if it's configured to have multiple items[App-Content-Type]
if it's configured to only allow one specific content-type which is also generatedIEnumerable<[App-Content-Type]>
if it's configured to have multiple specific content-types which are also generated
Number
could be int, float, double, decimalint
is the default, and the type used if 0 decimals are configureddecimal
is used, if it's configured to have 1 or more decimal
Custom
- if
custom-gps
then ideally it would create aGps
class withLatitude
andLongitude
properties - others should probably be ignored for now
- if
Note that the property will always call the base.Something(...)
to auto-generate.
This is to ensure that new names don't break the code - eg. if there is a property called Child
, then base.Child(...)
will still work.
Another note: You could think that we could also make the Presentation
object typed, but this is not possible.
Reason is that different views could use the same Content-Type (eg. a Location type) with different presentation settings,
so the type Location would need to have a Presentation of MapSettings in one place, and AddressSettings in another.
Shortlink: https://go.2sxc.org/copilot-data