Yaml to Aptify Entities

[NOTE: This is a development environment tool only! It’s meant to greatly simpilfy the initial create entity process for developers.]{.lead}

One annoying thing about meta-based systems is that some times you need to enter a lot of data for things that seem simple. With Aptify it’s Entities as the UI interface isn’t designed for speed entry. So when you need to create multiple entities for a project it can be a big pain.

As I do a lot of create, wipe the DB and re-create/modify this was getting super annoying. Yes, anyone who know Aptify I could have packed up the Entities and un-packed them… but I didn’t because I was always changing things, haha.

One day I was fiddling with dbdiagram.io and tried it’s export feature which gives you the raw create table statements for multiple DB types. Then I had it, why couldn’t I have something like this for Aptify Entities? I could easily plan out my entities in my own structured content and then just run that through a parser that would create the entities.

For the structured content I chose Yaml. I’d wanting to play around with it more and as I started a rough draft I fell in love with Yaml. JSON your awesome when I’m not physically typing you out, haha. If I’m typing it out, I think Yaml is king now.

Ok, we have Yaml structure now we need a parser. For that I chose a .Net Framework 4.8 Console Application (note: Aptify 7 is still on Framework 4.8). Added in all the bits I needed, add a bunch of my own opinionated entity best practices not only to standardize it but also make the Yaml as simple to type as possible. Things like:

It also has the basic concept of field templates. For example when you need to create a new Type style entity which using is just Name and Description, I didn’t want to write that every single time so, templates.

Example

Here is the Yaml for my AMFA project. It’s roughly 57 entities and it takes roughly 3 min to fully process! To do this manually would probably be also 2 hours.

// VIDEO EXAMPLE COMING SOON //

prefix: null
suffix: _amfa
applicationEntities:
  mode: all
  name: Anime/Manga Fans Association_amfa
  display: _ AMFA _
entities:
# STAND-ALONE START

  - name: PersonAnimeMangaType
    display: Person Anime/Manga Types
    baseView: PersonAnimeMangaTypes
    template: Amfa Type Table

  - name: PersonAnimeMangaStatus
    display: Person Anime/Manga Statuses
    template: Amfa Type Table

  - name: CompanyType
    template: Amfa Type Table

  - name: Country
    fields:
      - name: Name
        sqlFieldSize: 100
        isRequired: true

      - name: IsoCode
        sqlFieldSize: 3
        isRequired: true

  - name: Genre
    template: Amfa Type Table

  - name: AnimeSource
    template: Amfa Type Table

  - name: AnimeMediaRating
    template: Amfa Type Table

  - name: AnimeMangaMediaType
    display: Anime/Manga Media Types
    template: Amfa Type Table

  - name: AnimeMangaRelationType
    display: Anime/Manga Relation Types
    template: Amfa Type Table

  - name: AnimeMangaReleaseStatus
    display: Anime/Manga Release Statuses
    template: Amfa Type Table

  - name: ForumCategory
    template: Amfa Type Table

  - name: ForumPostLevel
    template: Amfa Type Table

  - name: GroupType
    template: Amfa Type Table

  - name: GroupTermMemberRole
    template: Amfa Type Table

  - name: AnimeMangaRelationType
    display: Anime/Manga Relation Types
    template: Amfa Type Table

  - name: EventType
    template: Amfa Type Table

  - name: JobCategory
    template: Amfa Type Table

  - name: JobType
    template: Amfa Type Table

  - name: JobCareerLevel
    template: Amfa Type Table

  - name: JobWageType
    template: Amfa Type Table

  - name: JobExperienceLevel
    template: Amfa Type Table

  - name: CourseLevel
    template: Amfa Type Table

  - name: CourseCategory
    template: Amfa Type Table

  - name: CourseModulePartType
    template: Amfa Type Table

  - name: ProductCategory
    template: Amfa Type Table

  - name: ProductType
    template: Amfa Type Table

  - name: ProductAvailableType
    template: Amfa Type Table

  - name: ProductQualityLevel
    template: Amfa Type Table

  - name: Person
    fields:
      - name: Email
        sqlFieldSize: 250
        isRequired: true
        isUnique: true

      - name: FirstLast
        calcCompType: Computed
        calcCompSql: "RTRIM(FirstName) + ' ' + LTRIM(LastName)"

      - name: LastName
        sqlFieldSize: 25
        isRequired: true

      - name: FirstName
        sqlFieldSize: 25
        isRequired: true

      - name: MalUsername
        sqlFieldSize: 150

      - name: AvatarUrl
        sqlFieldSize: 500

      - name: Bio
        sqlFieldSize: 1000

  - name: Company
    fields:
      - name: Name
        sqlFieldSize: 250
        isRequired: true

      - name: CompanyTypeID
        linkedEntity: CompanyType_amfa
        isRequired: true
        joinedFields:
          - joinedField: Name

      - name: CountryID
        linkedEntity: Country_amfa
        isRequired: true
        joinedFields:
          - joinedField: Name

      - name: Description
        sqlFieldSize: 4000

      - name: Directions
        sqlFieldSize: 500

      - name: MapLink
        sqlFieldSize: 250

      - name: Website
        sqlFieldSize: 250


# STAND-ALONE END

# ANIME/MANGA START

  - name: AnimeManga
    display: Anime/Manga
    baseView: AnimeManga
    fields:
      - name: ReferenceId
        display: Reference Id
        isRequired: true
        sqlFieldSize: 25
        isUnique: true

      - name: Type
        values:
          - Anime
          - Manga
        isRequired: true

      - name: Title
        sqlFieldSize: 150
        isRequired: true

      - name: MediaTypeID
        linkedEntity: AnimeMangaMediaType_amfa
        isRequired: true

      - name: ReleaseStatusID
        linkedEntity: AnimeMangaReleaseStatus_amfa
        isRequired: true

      - name: Description
        sqlFieldSize: 500

      - name: StartDate
        sqlDataType: date

      - name: EndDate
        sqlDataType: date

      - name: SyncDate
        sqlDataType: datetime

      - name: CoverImageUrl
        sqlFieldSize: 500

      - name: BannerUrl
        sqlFieldSize: 500

      - name: Nsfw
        values:
          - white
          - gray
          - black
        default: white

      - name: EpisodesChapters
        sqlDataType: int

      - name: AnimeSourceId
        linkedEntity: AnimeSource_amfa

      - name: MediaRatingId
        linkedEntity: AnimeMediaRating_amfa

      - name: AnimeYear
        sqlDataType: int

      - name: AnimeSeason
        sqlFieldSize: 6
        values:
          - Winter
          - Spring
          - Summer
          - Fall

      - name: AnimeEpAvgDuration
        sqlDataType:  int

      - name: AnimeBroadcastDayOfWeek
        sqlFieldSize: 10
        values:
          - Sunday
          - Monday
          - Tuesday
          - Wednesday
          - Thursday
          - Friday
          - Saturday

      - name: MangaVolumes
        sqlDataType:  int

  - name: AnimeMangaSynonym
    display: Synonyms
    parent: AnimeManga_amfa
    fields:
      - name: Synonym
        isRequired: true

  - name: AnimeMangaRelation
    display: Relations
    parent: AnimeManga_amfa
    fields:
      - name: RelatedID
        linkedEntity: AnimeManga_amfa
        isRequired: true

      - name: RelationTypeID
        linkedEntity: AnimeMangaRelationType_amfa
        isRequired: true

  - name: AnimeMangaStudio
    display: Studios
    parent: AnimeManga_amfa
    fields:
      - name: CompanyID
        linkedEntity: Company_amfa
        isRequired: true

  - name: AnimeMangaGenre
    display: Genres
    parent: AnimeManga_amfa
    fields:
      - name: GenreID
        linkedEntity: Genre_amfa
        isRequired: true

  - name: PersonAnimeManga
    display: Anime/Manga
    parent: Person_amfa
    fields:
      - name: AnimeMangaID
        linkedEntity: AnimeManga_amfa
        isRequired: true

      - name: TypeID
        linkedEntity: PersonAnimeMangaType_amfa
        isRequired: true

      - name: StatusID
        linkedEntity: PersonAnimeMangaStatus_amfa
        isRequired: true

      - name: Progression
        sqlDataType: int
        isRequired: true

      - name: Rating
        sqlDataType: int
        values: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

      - name: IsRe
        sqlDataType: bit

# ANIME/MANGA END

# FORUMS START

  - name: Forum
    fields:
      - name: Name
        isRequired: true
        isUnique: true

      - name: Description
        sqlFieldSize: 500
        isRequired: true

      - name: CategoryID
        linkedEntity: ForumCategory_amfa
        isRequired: true

      - name: PostLevelID
        linkedEntity: ForumPostLevel_amfa
        isRequired: true

      - name: StartDate
        sqlDataType: date
        isRequired: true

      - name: EndDate
        sqlDataType: date

      - name: ThumbnailUrl
        sqlFieldSize: 500

      - name: BannerUrl
        sqlFieldSize: 500

  - name: ForumModerator
    display: Moderators
    parent: Forum_amfa
    fields:
      - name: PersonID
        linkedEntity: Persons_amfa
        isRequired: true

  - name: ForumPost
    display: Posts
    parent: Forum_amfa
    fields:
      - name: PersonID
        linkedEntity: Persons_amfa
        isRequired: true

      - name: ParentID
        linkedEntity: this

      - name: Subject
        sqlFieldSize: 250
        isRequired: true

      - name: Post
        sqlFieldSize: 500
        isRequired: true

  - name: ForumPostWatcher
    display: Watchers
    parent: Forum_amfa
    fields:
      - name: PersonID
        linkedEntity: Persons_amfa
        isRequired: true

      - name: StartDate
        sqlDataType: datetime
        isRequired: true

      - name: EndDate
        sqlDataType: datetime

  - name: ForumPinnedPost
    display: Pinned Posts
    parent: Forum_amfa
    fields:
      - name: StartDate
        sqlDataType: datetime
        isRequired: true

      - name: EndDate
        sqlDataType: datetime

# FORUMS END

# COUSES START

  - name: Course
    fields:
      - name: Title
        sqlFieldSize: 250
        isRequired: true

      - name: ProductID
        linkedEntity: Products_amfa

      - name: CategoryID
        linkedEntity: CourseCategory_amfa
        isRequired: true

      - name: LevelID
        linkedEntity: CourseLevel_amfa

      - name: Summary
        sqlFieldSize: 500
        isRequired: true

      - name: Description
        sqlFieldSize: 500

      - name: ContentInfo
        sqlFieldSize: 500

      - name: WhatYouLearn
        sqlFieldSize: 500

      - name: Rating
        sqlDataType: decimal
        sqlDecimalPrecisionLength: 6
        sqlDecimalPrecisionPoints: 2

      - name: ThumbnailUrl
        sqlFieldSize: 500

  - name: CourseGenre
    display: Genres
    parent: Course_amfa
    fields:
      - name: GenreID
        linkedEntity: Genre_amfa
        isRequired: true

  - name: CourseInstructor
    display: Instructors
    parent: Course_amfa
    fields:
      - name: PersonID
        linkedEntity: Person_amfa
        isRequired: true

      - name: StartDate
        sqlDataType: date
        isRequired: true

      - name: EndDate
        sqlDataType: date

  - name: CourseImage
    display: Images
    parent: Course_amfa
    fields:
      - name: Url
        sqlFieldSize: 500
        isRequired: true

      - name: Ordinal
        sqlDataType: int
        default: 100

  - name: CourseOffering
    display: Offerings
    parent: Course_amfa
    fields:
      - name: StartDate
        sqlDataType: date
        isRequired: true

      - name: EndDate
        sqlDataType: date

  - name: CourseReview
    display: Reviews
    parent: Course_amfa
    fields:
      - name: PersonID
        linkedEntity: Person_amfa
        isRequired: true

      - name: Review
        sqlFieldSize: 500
        isRequired: true

      - name: Rating
        sqlDataType: decimal
        sqlDecimalPrecisionLength: 6
        sqlDecimalPrecisionPoints: 2
        isRequired: true

      - name: SubmittedDate
        sqlDataType: datetime
        isRequired: true

  - name: CourseModule
    display: Modules
    parent: Course_amfa
    fields:
      - name: Title
        sqlFieldSize: 250
        isRequired: true

  - name: CourseModulePart
    display: Parts
    parent: CourseModule_amfa
    fields:
      - name: Title
        sqlFieldSize: 250
        isRequired: true

      - name: TypeID
        linkedEntity: CourseModulePartType_amfa
        isRequired: true

      - name: Description
        sqlFieldSize: 500

      - name: ContentLengthSeconds
        sqlDataType: int

# COURSES END

# EVENTS START

  - name: EventOrganizer
    fields:
      - name: Name
        sqlFieldSize: 150
        isRequired: true

      - name: Description
        sqlFieldSize: 500

      - name: LogoUrl
        sqlFieldSize: 250

      - name: Website
        sqlFieldSize: 250

  - name: Event
    fields:
      - name: Title
        sqlFieldSize: 150
        isRequired: true

      - name: TypeID
        linkedEntity: EventType_amfa

      - name: Description
        sqlFieldSize: 500
        isRequired: true

      - name: VenueID
        linkedEntity: Company_amfa
        allowNull: true

      - name: StartDate
        sqlDataType: datetime
        isRequired: true

      - name: EndDate
        sqlDataType: datetime

      - name: OrganizerID
        linkedEntity: EventOrganizer_amfa

      - name: LogoUrl
        sqlFieldSize: 250

      - name: RegistrationUrl
        sqlFieldSize: 250

# EVENTS END

# JOBS START

  - name: Job
    fields:
      - name: Title
        sqlFieldSize: 150
        isRequired: true

      - name: CategoryID
        linkedEntity: JobCategory_amfa
        isRequired: true

      - name: TypeID
        linkedEntity: JobType_amfa
        isRequired: true

      - name: CareerLevelID
        linkedEntity: JobCareerLevel_amfa
        isRequired: true

      - name: WageTypeID
        linkedEntity: JobWageType_amfa
        isRequired: true

      - name: ExperienceLevelID
        linkedEntity: JobExperienceLevel_amfa
        isRequired: true

      - name: CompanyID
        linkedEntity: Company_amfa
        isRequired: true

      - name: CountryID
        linkedEntity: Country_amfa
        isRequired: true

      - name: City
        sqlFieldSize: 150
        isRequired: true

      - name: StateProvince
        sqlFieldSize: 150

      - name: PostalCode
        sqlFieldSize: 15
        isRequired: true

      - name: AllowRemote
        sqlDataType: bit

      - name: WageMin
        sqlDataType: money
        isRequired: true

      - name: WageMax
        sqlDataType: money
        isRequired: true

      - name: DateCreated
        sqlDataType: datetime
        isRequired: true

      - name: Description
        sqlFieldSize: 2000
        isRequired: true

  - name: JobPosting
    fields:
      - name: JobID
        linkedEntity: Job_amfa
        isRequired: true

      - name: StartDate
        sqlDataType: datetime
        isRequired: true

      - name: EndDate
        sqlDataType: datetime

# JOBS END

# PRODUCTS START

  - name: Product
    description: These are the products we sell
    fields:
      - name: Title
        sqlFieldSize: 150
        isRequired: true
        isNameField: true

      - name: Description
        sqlFieldSize: 500

      - name: CategoryID
        display: Category
        linkedEntity: ProductCategory_amfa
        isRequired: true
        joinedFields:
            - joinedField: Name

      - name: ProductTypeID
        display: Product Type
        linkedEntity: ProductType_amfa
        isRequired: true
        joinedFields:
            - joinedField: Name

      - name: AvailableID
        display: Availability
        linkedEntity: ProductAvailableType_amfa
        joinedFields:
            - joinedField: Name

      - name: QualityLevelID
        display: Quality
        linkedEntity: ProductQualityLevel_amfa
        joinedFields:
            - joinedField: Name

      - name: Price
        sqlDataType: decimal
        sqlDecimalPrecisionLength: 8
        sqlDecimalPrecisionPoints: 2

      - name: ReleaseDate
        sqlDataType: datetime

      - name: Weight
        sqlDataType: decimal
        sqlDecimalPrecisionLength: 8
        sqlDecimalPrecisionPoints: 2

      - name: Width
        sqlDataType: decimal
        sqlDecimalPrecisionLength: 8
        sqlDecimalPrecisionPoints: 2

      - name: Height
        sqlDataType: decimal
        sqlDecimalPrecisionLength: 8
        sqlDecimalPrecisionPoints: 2

      - name: PackageWeight
        sqlDataType: decimal
        sqlDecimalPrecisionLength: 8
        sqlDecimalPrecisionPoints: 2

      - name: PackageWidth
        sqlDataType: decimal
        sqlDecimalPrecisionLength: 8
        sqlDecimalPrecisionPoints: 2

      - name: PackageHeight
        sqlDataType: decimal
        sqlDecimalPrecisionLength: 8
        sqlDecimalPrecisionPoints: 2

      - name: AnimeMangaID
        display: Anime/Manga
        linkedEntity: AnimeManga_amfa
        joinedFields:
            - joinedField: Title

  - name: ProductImages
    parent: Product_amfa
    fields:
      - name: Name
        isRequired: true
        isNameField: true

      - name: Url
        isRequired: true
        sqlFieldSize: 250

      - name: Ordinal
        isRequired: true
        sqlDataType: int
        default: 100

  - name: ProductGenre
    parent: Product_amfa
    fields:
      - name: GenreID
        linkedEntity: Genre_amfa
        isRequired: true
        joinedFields:
            - joinedField: Name
              isNameField: true

  - name: ProductAttribute
    parent: Product_amfa
    fields:
      - name: Name
        sqlFieldSize: 250
        isRequired: true
        isNameField: true

      - name: Value
        sqlFieldSize: 500

# PRODUCTS END