Table of Contents

Copilot Generate Types for HotBuild (BETA v17.02)

These are the conventions we're striving for in the new HotBuild system.

Goals

  1. To provide a simple, type-safe object for everything in an app, eg BlogPost.Tags which would return an IEnumerable<Tag>.
  2. Standards based an simple
  3. very transparent
  4. 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:

  1. AutoGenerated Class
    1. The auto-generated class is the base class for the real class
    2. It is in a sub namespace - atm AutoGen to avoid it being access by mistake
    3. It has a special prefix like Zag... (Z to be at the end of a list, and ag 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).
    4. We need to have a complicated-named class like BlogPostAutoGenerated to avoid name clashes with properties in the content type. Otherwise a class called BlogPost couldn't have a property BlogPost, but this way it works.
    5. The auto generated needs a weird name - we recommend Zag...AutoGenerated to make it very clear and almost impossible to clash with property names.
    6. The AutoGenerated should also be abstract so that it can't be instantiated directly.
    7. For now it must inherit from Custom.Data.CustomItem - a class which is provided by 2sxc
  2. Real Class
    1. We then need the real class with the name matching the ContentType (where possible, see below)
    2. In same cases this is not possible - eg we have a App-Resources type which is a legacy problem, which should be called AppResources
    3. 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.
  3. Comments
    1. We need special comments on top of the file, the real class and the autogenerated to guide the user
    2. The exact text will be worked out later on

Specs for the Docs

  1. File Intro
    1. This file is auto-generated by "2sichost" for "/staging" at 2024-01-31 17:59:00
      Replace with the actual user, path and date
    2. If you need to extend it, create a partial class for "BlogPost" in a separate file.
      Replace with the actual content type name
    3. See also: https://go.2sxc.org/hotbuild-autogen
  2. Class Intro
    1. This is a generated class for BlogPost
      Replace with the actual content type name
    2. 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
  3. Class Description
    1. BlogPost Data.
      Replace with the actual content type name
    2. Default properties such as .Title or .Id are provided in the base class.
      leave as is
    3. Most properties have a simple access, such as .TermsAndGdprCombined.
      Replace with the first found property - if any, otherwise skip this line
    4. 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

  1. Boolean is clear, the normal fallback is false, so that's typical
    1. if the developer needs a bool? he will have to use the Get<bool?>() method
  2. String is clear defaults to "" and not null
  3. DateTime is treated as System.DateTime
  4. Empty is ignored
  5. Hyperlink fields should probably default to the Url(...) method.
    1. string using the Url(...) method is the default
    2. IFile is also generated on the [original-name]File property using the File(...) method
    3. IFolder is also generated on the [original-name]Folder property using the Folder(...) method
    4. Note: Since it generates additional names, it may clash with existing fields. In this case, the main field has precedence.
  6. Entity properties return
    1. ITypedItem If it's configured to have only one item
    2. IEnumerable<ITypedItem> if it's configured to have multiple items
    3. [App-Content-Type] if it's configured to only allow one specific content-type which is also generated
    4. IEnumerable<[App-Content-Type]> if it's configured to have multiple specific content-types which are also generated
  7. Number could be int, float, double, decimal
    1. int is the default, and the type used if 0 decimals are configured
    2. decimal is used, if it's configured to have 1 or more decimal
  8. Custom
    1. if custom-gps then ideally it would create a Gps class with Latitude and Longitude properties
    2. others should probably be ignored for now

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