model.lua 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. local dir = require "pl.dir"
  2. local path = require "pl.path"
  3. local term = require "volksdata.term"
  4. local nsm = require "volksdata.namespace"
  5. local pkar = require "pocket_archive"
  6. local logger = pkar.logger
  7. -- "nil" table.
  8. local NT = {}
  9. local no_ll_pnames = {
  10. archive_path = true,
  11. checksum = true,
  12. size = true,
  13. submitted = true,
  14. sub_id = true,
  15. }
  16. local M = {
  17. -- Parsed typedef configurations.
  18. types = {},
  19. -- Field names. Order is kept in encoding laundry lists. The hardcoded
  20. -- values come first, all others are harvested from the typedef
  21. -- configuration and ordered alphabetically.
  22. pnames = {"content_type", "id", "source_path"},
  23. -- Term-to-URI map. URIs are volksdata.Term objects.
  24. id_to_uri = {},
  25. -- URI-to-term map. Keys are URI strings, not volksdata.Term objects,
  26. -- because key comparison wouldn't work with them.
  27. uri_to_id = {},
  28. }
  29. M.from_uri = function(type_uri)
  30. assert(type_uri)
  31. return M.types[M.uri_to_id[nsm.denormalize_uri(type_uri.data)]]
  32. end
  33. -- Parameters that do not get inherited.
  34. local NO_INHERIT = {abstract = true}
  35. local MODEL_PATH = path.join(pkar.config_path, "model")
  36. local gen_config = dofile(path.join(MODEL_PATH, "generation.lua"))
  37. local function add_term(id, uri_str)
  38. --if not uri then error(("Term %s has not a URI!"):format(term), 2) end
  39. if not uri_str then return end
  40. local uri = term.new_iriref_ns(uri_str)
  41. if not M.id_to_uri[id] then M.id_to_uri[id] = uri end
  42. if not M.uri_to_id[uri_str] then M.uri_to_id[uri_str] = id end
  43. end
  44. local function parse_model(mod_id)
  45. local hierarchy = {}
  46. local function traverse(mod_id)
  47. logger:debug("traversing: " .. mod_id)
  48. local model = dofile(path.join(
  49. MODEL_PATH, "typedef", mod_id .. ".lua"))
  50. -- Merge separate generator config
  51. model.gen = gen_config[mod_id]
  52. --model.id = mod_id
  53. --print("Model: ")
  54. --for k, v in pairs(model) do print (k, v) end
  55. -- Prepend to hierarchy.
  56. model.id = mod_id
  57. -- Store term-to-URI and URI-to-term mappings.
  58. add_term(model.id, model.uri)
  59. for prop, pdata in pairs(model.properties or {}) do
  60. add_term(prop, pdata.uri) end
  61. table.insert(hierarchy, 1, model)
  62. if model.broader then traverse(model.broader) end
  63. end
  64. traverse(mod_id)
  65. local lineage = {} -- Ordered lineage of types, from ancestor to leaf.
  66. local types = {} -- Set of all types.
  67. for _, mod in ipairs(hierarchy) do
  68. table.insert(lineage, mod.id)
  69. types[mod.id] = true
  70. end
  71. local function merge(src, dest)
  72. for k, v in pairs(src) do
  73. if NO_INHERIT[k] then goto continue end
  74. if type(v) == "table" then
  75. dest[k] = dest[k] or {}
  76. assert(type(dest[k]) == "table")
  77. merge(v, dest[k])
  78. else
  79. dest[k] = v
  80. end
  81. ::continue::
  82. end
  83. end
  84. local config = {lineage = lineage, types = types}
  85. for _, src_config in ipairs(hierarchy) do
  86. merge(src_config, config)
  87. end
  88. return config
  89. end
  90. local function setup_model()
  91. -- Temp store (set) for property names.
  92. local all_pnames = {}
  93. -- Collect all type names from config file names.
  94. for _, fpath in ipairs(dir.getfiles(
  95. path.join(MODEL_PATH, "typedef"), "*.lua")) do
  96. local mname = path.basename(fpath):gsub(".lua$", "")
  97. local typedef = parse_model(mname)
  98. -- Store parsed typedef configurations.
  99. M.types[mname] = typedef
  100. -- Store unique prop names.
  101. for pn in pairs(typedef.properties or NT) do
  102. if not no_ll_pnames[pn] then all_pnames[pn] = true end
  103. end
  104. end
  105. -- Remove hardcoded prop names, reorder, and append to module's pnames.
  106. local pnames_ordered = {}
  107. for _, hcpn in ipairs(M.pnames) do
  108. all_pnames[hcpn] = nil
  109. end
  110. for pn in pairs(all_pnames) do
  111. table.insert(pnames_ordered, pn)
  112. end
  113. table.sort(pnames_ordered)
  114. for _, pn in ipairs(pnames_ordered) do table.insert(M.pnames, pn) end
  115. logger:debug("Property names ordered: " .. table.concat(M.pnames, ", "))
  116. end
  117. setup_model()
  118. return M