collectProjectedTypes builds a projected type for every user type found when recursing through the attributes. The projected types live in the views package and support the marshaling and unmarshalling of result types that make use of views. We need to build projected types for all user types - not
(projected, att *expr.AttributeExpr, viewspkg string, scope, viewScope *codegen.NameScope, seen map[string]*ProjectedTypeData)
| 1829 | // just result types - because user types may contain result types and thus may |
| 1830 | // need to be marshalled in different ways depending on the view being used. |
| 1831 | func collectProjectedTypes(projected, att *expr.AttributeExpr, viewspkg string, scope, viewScope *codegen.NameScope, seen map[string]*ProjectedTypeData) []*ProjectedTypeData { |
| 1832 | collect := func(projected, att *expr.AttributeExpr) []*ProjectedTypeData { |
| 1833 | return collectProjectedTypes(projected, att, viewspkg, scope, viewScope, seen) |
| 1834 | } |
| 1835 | var data []*ProjectedTypeData |
| 1836 | switch pt := projected.Type.(type) { |
| 1837 | case expr.UserType: |
| 1838 | dt := att.Type.(expr.UserType) |
| 1839 | if pd, ok := seen[dt.ID()]; ok { |
| 1840 | // a projected type is already created for this user type. We change the |
| 1841 | // attribute type to this seen projected type. The seen projected type |
| 1842 | // can be nil if the attribute type has a circular type definition in |
| 1843 | // which case we don't change the attribute type until the projected type |
| 1844 | // is created during the recursion. |
| 1845 | if pd != nil { |
| 1846 | projected.Type = pd.Type |
| 1847 | } |
| 1848 | return data |
| 1849 | } |
| 1850 | seen[dt.ID()] = nil |
| 1851 | pt.Rename(pt.Name() + "View") |
| 1852 | // We recurse before building the projected type so that user types within |
| 1853 | // a projected type is also converted to their respective projected types. |
| 1854 | types := collect(pt.Attribute(), dt.Attribute()) |
| 1855 | pd := buildProjectedType(projected, att, viewspkg, scope, viewScope) |
| 1856 | seen[dt.ID()] = pd |
| 1857 | data = append(data, pd) |
| 1858 | data = append(data, types...) |
| 1859 | case *expr.Array: |
| 1860 | dt := att.Type.(*expr.Array) |
| 1861 | types := collect(pt.ElemType, dt.ElemType) |
| 1862 | data = append(data, types...) |
| 1863 | case *expr.Map: |
| 1864 | dt := att.Type.(*expr.Map) |
| 1865 | types := collect(pt.KeyType, dt.KeyType) |
| 1866 | data = append(data, types...) |
| 1867 | types = collect(pt.ElemType, dt.ElemType) |
| 1868 | data = append(data, types...) |
| 1869 | case *expr.Object: |
| 1870 | dt := att.Type.(*expr.Object) |
| 1871 | for _, n := range *pt { |
| 1872 | types := collect(n.Attribute, dt.Attribute(n.Name)) |
| 1873 | data = append(data, types...) |
| 1874 | } |
| 1875 | case *expr.Union: |
| 1876 | dt := att.Type.(*expr.Union) |
| 1877 | for i, n := range pt.Values { |
| 1878 | types := collect(n.Attribute, dt.Values[i].Attribute) |
| 1879 | data = append(data, types...) |
| 1880 | } |
| 1881 | } |
| 1882 | return data |
| 1883 | } |
| 1884 | |
| 1885 | // hasResultType returns true if the given attribute has a result type recursively. |
| 1886 | func hasResultType(att *expr.AttributeExpr, seens ...map[string]struct{}) bool { |