3
0
corteza/server/codegen/server.store.cue

252 lines
6.8 KiB
CUE

package codegen
import (
"strings"
"list"
"github.com/cortezaproject/corteza/server/app"
"github.com/cortezaproject/corteza/server/codegen/schema"
)
_StoreResource: {
res = "res": schema.#Resource
typePkg = "typePkg": string
pkAttrNames: [string, ...]
hasPrimaryKey: res.model.indexes.primary != _|_
if hasPrimaryKey {
// primary key flag is no longer explicitly set on
// the attribute but via model.indexes.primary
pkAttrNames: [
for f in res.model.indexes.primary.fields { f.attribute }
]
}
result: {
ident: res.store.ident
identPlural: res.store.identPlural
expIdent: res.store.expIdent
expIdentPlural: res.store.expIdentPlural
modelIdent: res.model.ident
goType: "\(typePkg).\(res.expIdent)"
goSetType: "\(typePkg).\(res.expIdent)Set"
goFilterType: "\(typePkg).\(res.filter.expIdent)"
struct: [ for attr in res.model.attributes if attr.store {
"ident": attr.ident
"expIdent": attr.expIdent
"storeIdent": attr.storeIdent
"name": attr.name
"primaryKey": list.Contains(pkAttrNames, attr.name)
"ignoreCase": attr.ignoreCase
"goType": strings.Replace(attr.goType, "types.", "\(typePkg).", 1)
}]
filter: {
// query fields as defined in struct
"query": [ for name in res.filter.query {res.model.attributes[name]}],
// filter by nil state as defined in filter
"byNilState": [ for name in res.filter.byNilState {res.filter.struct[name]}]
// filter by false as defined in filter
"byFalseState": [ for name in res.filter.byFalseState {res.filter.struct[name]}]
// filter by value as defined in filter
// @todo this should be pulled from the struct
"byValue": [ for name in res.filter.byValue {res.filter.struct[name]}]
"byLabel": res.features.labels
"byFlag": res.features.flags
}
auxIdent: "aux\(expIdent)"
auxStruct: struct
features: {
paging: res.features.paging
sorting: res.features.sorting
checkFn: res.features.checkFn
}
api: {
if res.store.api != _|_ {
_base: {
"ident": res.store.ident
"expStoreIdent": res.store.expIdentPlural
"goType": goType
"goFilterType": goFilterType
"auxIdent": auxIdent
}
if hasPrimaryKey {
deleteByPK: {
"pkAttrNames": pkAttrNames,
attributes: [ for attr in pkAttrNames { res.model.attributes[attr] } ]
_expIdents: strings.Join([ for attr in pkAttrNames { res.model.attributes[attr].expIdent } ], "")
"expFnIdent": "Delete\(res.store.expIdent)By\(_expIdents)"
}
}
lookups: [
for l in res.store.api.lookups {
_base
"expFnIdent": l.expIdent
if (l.description != _|_) {
description: "// \(l.expIdent) " + strings.Join(strings.Split(l.description, "\n"), "\n// ")
}
// Copy all relevant fields from the struct
"args": [
for name in l.fields {
let attr = res.model.attributes[name]
"ident": attr.ident
"storeIdent": attr.storeIdent
"goType": attr.goType
"ignoreCase": attr.ignoreCase
},
]
"nullConstraint": l.nullConstraint
"returnType": "\(goType)"
"collectionFnIdent": "\(res.store.ident)Collection"
},
]
// all additional store functions we need for this resource
functions: [
for f in res.store.api.functions {
_base
"expFnIdent": f.expIdent
if (f.description != _|_) {
description: "// \(f.expIdent) " + strings.Join(strings.Split(f.description, "\n"), "\n// ")
}
"args": [ for a in f.args {
"ident": a.ident
"goType": strings.Replace(a.goType, "types.", "\(typePkg).", 1)
"spread": a.spread
}]
"return": [ for r in f.return {strings.Replace(r, "types.", "\(typePkg).", 1)}]
},
]
sortableFields: {
_base
"fnIdent": "sortable\(expIdent)Fields"
fields: {
for attr in res.model.attributes if attr.sortable || attr.unique || list.Contains(pkAttrNames, attr.name) {
{
"\(strings.ToLower(attr.name))": attr.name
"\(strings.ToLower(attr.ident))": attr.name
}
}
}
}
collectCursorValues: {
_base
"fnIdent": "collect\(expIdent)CursorValues"
fields: [ for attr in res.model.attributes if attr.sortable || attr.unique || list.Contains(pkAttrNames, attr.name) {
attr
"primaryKey": list.Contains(pkAttrNames, attr.name)
} ]
primaryKeys: [ for attr in res.model.attributes if list.Contains(pkAttrNames, attr.name) {attr} ]
}
checkConstraints: {
_base
"fnIdent": "check\(expIdent)Constraints"
checks: [
for lookup in res.store.api.lookups if lookup.constraintCheck {
lookupFnIdent: lookup.expIdent
fields: [ for name in lookup.fields {res.model.attributes[name]}]
nullConstraint: [
for f in res.model.attributes if list.Contains(lookup.nullConstraint, f.name) {
"expIdent": f.expIdent
},
]
},
]
}
}
}
}
}
// Codegen template payload, reused for multiple outputs
_payload: {
package: string | *"store"
imports: {
// per-component type imports
for cmp in app.corteza.components for res in cmp.resources if res.store != _|_ {
"github.com/cortezaproject/corteza/server/\(cmp.ident)/types": "\(cmp.ident)Type"
}
for res in app.corteza.resources if res.store != _|_ {
"\(res.package.import)": "\(res.package.ident)Type"
}
for cmp in app.corteza.components for res in cmp.resources for i in res.imports {
"\(i.import)": ""
}
}
types: {
// for each resource in every store with store and actions defined
for cmp in app.corteza.components for res in cmp.resources if res.store != _|_ {
// use _Store resource as a function (https://cuetorials.com/patterns/functions/)
// and pass res(ource) and type-package string in as "arguments"
"\(res.store.ident)": { _StoreResource & { "res": res, "typePkg": "\(cmp.ident)Type" } }.result
},
for res in app.corteza.resources if res.store != _|_ {
"\(res.store.ident)": { _StoreResource & { "res": res, "typePkg": "\(res.package.ident)Type" } }.result
}
}
}
[...schema.#codegen] &
[
{
"bulk": [
{
"template": "gocode/store/interfaces.go.tpl"
"output": "store/interfaces.gen.go"
}, {
"template": "gocode/store/rdbms/rdbms.go.tpl"
"output": "store/adapters/rdbms/rdbms.gen.go"
}, {
"template": "gocode/store/rdbms/aux_types.go.tpl"
"output": "store/adapters/rdbms/aux_types.gen.go"
}, {
"template": "gocode/store/rdbms/queries.go.tpl"
"output": "store/adapters/rdbms/queries.gen.go"
}, {
"template": "gocode/store/rdbms/filters.go.tpl"
"output": "store/adapters/rdbms/filters.gen.go"
}, {
"template": "gocode/store/tests/all.go.tpl"
"output": "store/tests/all_test.go"
},
]
"payload": { _payload }
},
]