describe.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // ██████╗ ███████╗███████╗ ██████╗██████╗ ██╗██████╗ ███████╗
  2. // ██╔══██╗██╔════╝██╔════╝██╔════╝██╔══██╗██║██╔══██╗██╔════╝
  3. // ██║ ██║█████╗ ███████╗██║ ██████╔╝██║██████╔╝█████╗
  4. // ██║ ██║██╔══╝ ╚════██║██║ ██╔══██╗██║██╔══██╗██╔══╝
  5. // ██████╔╝███████╗███████║╚██████╗██║ ██║██║██████╔╝███████╗
  6. // ╚═════╝ ╚══════╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═════╝ ╚══════╝
  7. //
  8. module.exports = require('machine').build({
  9. friendlyName: 'Describe',
  10. description: 'Describe a table in the related data store.',
  11. inputs: {
  12. datastore: {
  13. description: 'The datastore to use for connections.',
  14. extendedDescription: 'Datastores represent the config and manager required to obtain an active database connection.',
  15. required: true,
  16. example: '==='
  17. },
  18. tableName: {
  19. description: 'The name of the table to describe.',
  20. required: true,
  21. example: 'users'
  22. },
  23. meta: {
  24. friendlyName: 'Meta (custom)',
  25. description: 'Additional stuff to pass to the driver.',
  26. extendedDescription: 'This is reserved for custom driver-specific extensions.',
  27. example: '==='
  28. }
  29. },
  30. exits: {
  31. success: {
  32. description: 'The results of the describe query.',
  33. outputVariableName: 'records',
  34. outputType: 'ref'
  35. },
  36. badConnection: {
  37. friendlyName: 'Bad connection',
  38. description: 'A connection either could not be obtained or there was an error using the connection.'
  39. }
  40. },
  41. fn: function describe(inputs, exits) {
  42. // Dependencies
  43. var _ = require('@sailshq/lodash');
  44. var Helpers = require('./private');
  45. // Set a flag if a leased connection from outside the adapter was used or not.
  46. var leased = _.has(inputs.meta, 'leasedConnection');
  47. // ██████╗ ██╗ ██╗███████╗██████╗ ██╗███████╗███████╗
  48. // ██╔═══██╗██║ ██║██╔════╝██╔══██╗██║██╔════╝██╔════╝
  49. // ██║ ██║██║ ██║█████╗ ██████╔╝██║█████╗ ███████╗
  50. // ██║▄▄ ██║██║ ██║██╔══╝ ██╔══██╗██║██╔══╝ ╚════██║
  51. // ╚██████╔╝╚██████╔╝███████╗██║ ██║██║███████╗███████║
  52. // ╚══▀▀═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝
  53. //
  54. // These native queries are responsible for describing a single table and the
  55. // various attributes that make them.
  56. var describeQuery = 'DESCRIBE ' + inputs.tableName;
  57. var autoIncrementQuery = 'SHOW INDEX FROM ' + inputs.tableName;
  58. // ╔═╗╔═╗╔═╗╦ ╦╔╗╔ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
  59. // ╚═╗╠═╝╠═╣║║║║║║ │ │ │││││││├┤ │ │ ││ ││││
  60. // ╚═╝╩ ╩ ╩╚╩╝╝╚╝ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
  61. // Spawn a new connection to run the queries on.
  62. Helpers.connection.spawnOrLeaseConnection(inputs.datastore, inputs.meta, function spawnConnectionCb(err, connection) {
  63. if (err) {
  64. return exits.badConnection(err);
  65. }
  66. // ╦═╗╦ ╦╔╗╔ ┌┬┐┌─┐┌─┐┌─┐┬─┐┬┌┐ ┌─┐ ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
  67. // ╠╦╝║ ║║║║ ││├┤ └─┐│ ├┬┘│├┴┐├┤ │─┼┐│ │├┤ ├┬┘└┬┘
  68. // ╩╚═╚═╝╝╚╝ ─┴┘└─┘└─┘└─┘┴└─┴└─┘└─┘ └─┘└└─┘└─┘┴└─ ┴
  69. Helpers.query.runNativeQuery(connection, describeQuery, [], undefined, function runDescribeQueryCb(err, describeResults) {
  70. if (err) {
  71. // Release the connection on error
  72. Helpers.connection.releaseConnection(connection, leased, function cb() {
  73. // If the table doesn't exist, return an empty object
  74. if (err.code === 'ER_NO_SUCH_TABLE') {
  75. return exits.success({ schema: {} });
  76. }
  77. return exits.error(err);
  78. });
  79. return;
  80. }
  81. // ╦═╗╦ ╦╔╗╔ ┌─┐┬ ┬┌┬┐┌─┐ ┬┌┐┌┌─┐┬─┐┌─┐┌┬┐┌─┐┌┐┌┌┬┐
  82. // ╠╦╝║ ║║║║ ├─┤│ │ │ │ │───│││││ ├┬┘├┤ │││├┤ │││ │
  83. // ╩╚═╚═╝╝╚╝ ┴ ┴└─┘ ┴ └─┘ ┴┘└┘└─┘┴└─└─┘┴ ┴└─┘┘└┘ ┴
  84. // ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
  85. // │─┼┐│ │├┤ ├┬┘└┬┘
  86. // └─┘└└─┘└─┘┴└─ ┴
  87. Helpers.query.runNativeQuery(connection, autoIncrementQuery, [], undefined, function runAutoIncrementQueryCb(err, incrementResults) {
  88. if (err) {
  89. // Release the connection on error
  90. Helpers.connection.releaseConnection(connection, leased, function cb() {
  91. return exits.error(err);
  92. });
  93. return;
  94. }
  95. // ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
  96. // ╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ │─┼┐│ │├┤ ├┬┘└┬┘
  97. // ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ └─┘└└─┘└─┘┴└─ ┴
  98. // ┬─┐┌─┐┌─┐┬ ┬┬ ┌┬┐┌─┐
  99. // ├┬┘├┤ └─┐│ ││ │ └─┐
  100. // ┴└─└─┘└─┘└─┘┴─┘┴ └─┘
  101. // Normalize Schema
  102. var schema = {};
  103. _.each(describeResults, function normalize(column) {
  104. // Set Type
  105. schema[column.Field] = {
  106. // Remove (n) column-size indicators
  107. type: column.Type.replace(/\([0-9]+\)$/, '')
  108. };
  109. // Check for primary key
  110. if (column.Key === 'PRI') {
  111. schema[column.Field].primaryKey = true;
  112. }
  113. // Check for uniqueness
  114. if (column.Key === 'UNI') {
  115. schema[column.Field].unique = true;
  116. }
  117. // If also an integer set auto increment attribute
  118. if (column.Type === 'int(11)') {
  119. schema[column.Field].autoIncrement = true;
  120. }
  121. // Loop Through Indexes and Add Properties
  122. _.each(incrementResults, function processIndexes(result) {
  123. _.each(schema, function loopThroughSchema(attr) {
  124. if (attr.Field !== result.Column_name) {
  125. return;
  126. }
  127. attr.indexed = true;
  128. });
  129. });
  130. });
  131. Helpers.connection.releaseConnection(connection, leased, function cb() {
  132. // Return the model schema
  133. return exits.success({ schema: schema });
  134. }); // </ releaseConnection >
  135. }); // </ runAutoIncrementQuery >
  136. }); // </ runDescribeQuery >
  137. }); // </ spawnConnection >
  138. }
  139. });