Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested Type Annotations #385

Closed
yesteryearer opened this issue Apr 2, 2024 · 9 comments
Closed

Nested Type Annotations #385

yesteryearer opened this issue Apr 2, 2024 · 9 comments

Comments

@yesteryearer
Copy link

Good day,

I'm pretty new to Pkl, and despite perusing the docs, can't find a working solution for the following:

I'm trying to generate a template for an object of the following form:

table String {
    mapping String {
            gp_table: String
            gp_field: String
            bc_table: String
            bc_field: String
    }
}

In the above scenario, any table instances, must be able to contain any number of mappings.

The solution I designed got as far as, a mapping.pkl file:

module Mapping

class Mapping{
    gp_table: String
    gp_field: String
    bc_table: String
    bc_field: String
}

And an instance as follows:

import "mappings.pkl"

salesInvoices {
    documentNo_to_invoiceNumber: Mapping = new {
        ["gp_table"] = "RM20101"
        ["gp_field"] = "DOCNUMBR"
        ["bc_table"] = "salesInvoices"
        ["bc_field"] = "externalDocumentNumber"
    }
}

The above only works when the mapping isn't contained within the larger salesInvoices object, and either way, I will only be able to have a single mapping in this manner.

Is there a clever work around that I'm missing? Or rather, what is the best way to go about this? I saw the following, but in this instance I think the object only required a single instance of the nested object.

@yesteryearer
Copy link
Author

Even if there was a solution as the original poster said here, but with an undefined number of internal objects of the declared type, that would be wonderful. Not looking for an elegant solution.

@holzensp
Copy link
Contributor

holzensp commented Apr 2, 2024

I'm not too sure what

table String {
    mapping String {
            gp_table: String
            gp_field: String
            bc_table: String
            bc_field: String
    }
}

means. If you know the field names ahead of time, you don't want a Mapping, but rather a class that defines properties. Only when you don't know the names ahead of time do you tend to use a Mapping.

Be weary that import "mappings.pkl" doesn't actually do anything (you don't use mappings anywhere); at the moment, Pkl only checks that salesInvoices.documentNo_to_invoiceNumber is indeed a Mapping, but nothing else.

@yesteryearer
Copy link
Author

yesteryearer commented Apr 2, 2024

Mapping in this case is not as per the Pkl definition, but rather a mapping between two databases. Hence the different tables and fields.

The first code block was supposed to just illustrate the general form of the object I'm trying to create.

Does the second code block not define a class with specific properties?

And finally, the final code doesn't even run, it throws an error saying: annotated types can't be applied to non-local objects or something along those lines.

All I'm trying to do is enforce a specific form on to the objects of type 'table', where any one table can have one or many objects contained within it of the form:

class Mapping{
    gp_table: String
    gp_field: String
    bc_table: String
    bc_field: String
}

Where each gp_table, gp_field, etc, variables will have varying values attributing to them.

@translatenix
Copy link
Contributor

I guess you want something like the following:

mappings.pkl:

tables: Mapping<String, DbTable>

typealias DbTable = Mapping<String, DbMapping>

class DbMapping {
  gp_table: String
  gp_field: String
  bc_table: String
  bc_field: String
}
amends "mappings.pkl"

tables {
  ["salesInvoices"] {
    ["documentNo_to_invoiceNumber"] {
      gp_table = "RM20101"
      gp_field = "DOCNUMBR"
      bc_table = "salesInvoices"
      bc_field = "externalDocumentNumber"
    }
  }
}

PS: This is a better fit for "Discussions" than "Issues".

@yesteryearer
Copy link
Author

yesteryearer commented Apr 2, 2024

@translatenix

Thank you so much, this is excellent + exactly what I was looking for.

I understand the code off the bat, but if you are willing to give a better explanation of your thought process, I'm all ears. Does mapping instantiate a many-to-one relationship? The only thing I don't really get is the distinction between using the variable name such as tables and the keyword typealias, but I guess this is due to the fact that there is only a single tables object and many DbTables.

Also, I wasn't even aware of the "Discussions" section, so thanks again. First time I've made a forum post on GitHub.

@translatenix
Copy link
Contributor

translatenix commented Apr 2, 2024

The type alias only improves readability and reusability.
Otherwise it's the same as tables: Mapping<String, Mapping<String, DbMapping>>.
A Pkl Mapping is often called "map" or "dictionary" in other programming languages.

@StefMa
Copy link
Contributor

StefMa commented Apr 3, 2024

There is also a Map type in Pkl with an richer API 🤓

@holzensp
Copy link
Contributor

holzensp commented Apr 3, 2024

Entirely with @translatenix's suggestions (both code and Discussion; but now that it's here, that's alright... do please close this Issue when you're fully satisfied, @yesteryearer).

Since you're talking about database tables and fields, I bet there are restrictions on the names of those things. It depends entirely on which database you're using what those restrictions are, but just for the example, I'm assuming names may not contain whitespace. This is to demonstrate type constraints and to further illustrate @translatenix's point about typealiases:

tables: Mapping<String, DbTable>

typealias DbTable = Mapping<String, DbMapping>

/// The database can't take arbitrary strings as names, so names must be restricted.
typealias DbName = String(!contains(" "))

class DbMapping {
  gp_table: DbName
  gp_field: DbName
  bc_table: DbName
  bc_field: DbName
}

@yesteryearer
Copy link
Author

So to clarify, the reason I originally posted this here was because of the following error:

–– Pkl Error ––
A non-local object property cannot have a type annotation.

At which point I didn't know a workaround exists.

Thanks for the help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants