modelTableMetadata.js 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. const { defineNonEnumerableProperty } = require('./modelUtils');
  2. const { isPromise } = require('../utils/promiseUtils');
  3. const TABLE_METADATA = '$$tableMetadata';
  4. function fetchTableMetadata(
  5. modelClass,
  6. { parentBuilder = null, knex = null, force = false, table = null } = {}
  7. ) {
  8. // The table isn't necessarily same as `modelClass.getTableName()` for example if
  9. // a view is queried instead.
  10. if (!table) {
  11. if (parentBuilder) {
  12. table = parentBuilder.tableNameFor(modelClass);
  13. } else {
  14. table = modelClass.getTableName();
  15. }
  16. }
  17. // Call tableMetadata first instead of accessing the cache directly beause
  18. // tableMetadata may have been overriden.
  19. let metadata = modelClass.tableMetadata({ table });
  20. if (!force && metadata) {
  21. return Promise.resolve(metadata);
  22. }
  23. // Memoize metadata but only for modelClass. The hasOwnProperty check
  24. // will fail for subclasses and the value gets recreated.
  25. if (!modelClass.hasOwnProperty(TABLE_METADATA)) {
  26. defineNonEnumerableProperty(modelClass, TABLE_METADATA, new Map());
  27. }
  28. // The cache needs to be checked in addition to calling tableMetadata
  29. // because the cache may contain a temporary promise in which case
  30. // tableMetadata returns null.
  31. metadata = modelClass[TABLE_METADATA].get(table);
  32. if (!force && metadata) {
  33. return Promise.resolve(metadata);
  34. } else {
  35. const promise = modelClass
  36. .query(knex)
  37. .childQueryOf(parentBuilder)
  38. .columnInfo({ table })
  39. .then(columnInfo => {
  40. const metadata = {
  41. columns: Object.keys(columnInfo)
  42. };
  43. modelClass[TABLE_METADATA].set(table, metadata);
  44. return metadata;
  45. });
  46. modelClass[TABLE_METADATA].set(table, promise);
  47. return promise;
  48. }
  49. }
  50. function tableMetadata(modelClass, { table } = {}) {
  51. if (modelClass.hasOwnProperty(TABLE_METADATA)) {
  52. const metadata = modelClass[TABLE_METADATA].get(table || modelClass.getTableName());
  53. if (isPromise(metadata)) {
  54. return null;
  55. } else {
  56. return metadata;
  57. }
  58. } else {
  59. return null;
  60. }
  61. }
  62. module.exports = {
  63. fetchTableMetadata,
  64. tableMetadata
  65. };