properties-definition-validator.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import {Service} from '@e22m4u/js-service';
  2. import {DataType as Type} from './data-type.js';
  3. import {capitalize} from '../../../utils/index.js';
  4. import {InvalidArgumentError} from '../../../errors/index.js';
  5. import {PrimaryKeysDefinitionValidator} from './primary-keys-definition-validator.js';
  6. /**
  7. * Properties definition validator.
  8. */
  9. export class PropertiesDefinitionValidator extends Service {
  10. /**
  11. * Validate.
  12. *
  13. * @param {string} modelName
  14. * @param {object} propDefs
  15. */
  16. validate(modelName, propDefs) {
  17. if (!modelName || typeof modelName !== 'string')
  18. throw new InvalidArgumentError(
  19. 'The first argument of PropertiesDefinitionValidator.validate ' +
  20. 'should be a non-empty String, but %v given.',
  21. modelName,
  22. );
  23. if (!propDefs || typeof propDefs !== 'object' || Array.isArray(propDefs)) {
  24. throw new InvalidArgumentError(
  25. 'The provided option "properties" of the model %v ' +
  26. 'should be an Object, but %v given.',
  27. modelName,
  28. propDefs,
  29. );
  30. }
  31. const propNames = Object.keys(propDefs);
  32. propNames.forEach(propName => {
  33. const propDef = propDefs[propName];
  34. this._validateProperty(modelName, propName, propDef);
  35. });
  36. this.getService(PrimaryKeysDefinitionValidator).validate(
  37. modelName,
  38. propDefs,
  39. );
  40. }
  41. /**
  42. * Validate property.
  43. *
  44. * @param {string} modelName
  45. * @param {string} propName
  46. * @param {object} propDef
  47. */
  48. _validateProperty(modelName, propName, propDef) {
  49. if (!modelName || typeof modelName !== 'string')
  50. throw new InvalidArgumentError(
  51. 'The first argument of PropertiesDefinitionValidator._validateProperty ' +
  52. 'should be a non-empty String, but %v given.',
  53. modelName,
  54. );
  55. if (!propName || typeof propName !== 'string')
  56. throw new InvalidArgumentError(
  57. 'The property name of the model %v should be ' +
  58. 'a non-empty String, but %v given.',
  59. modelName,
  60. propName,
  61. );
  62. if (!propDef)
  63. throw new InvalidArgumentError(
  64. 'The property %v of the model %v should have ' +
  65. 'a property definition, but %v given.',
  66. propName,
  67. modelName,
  68. propDef,
  69. );
  70. if (typeof propDef === 'string') {
  71. if (!Object.values(Type).includes(propDef))
  72. throw new InvalidArgumentError(
  73. 'In case of a short property definition, the property %v ' +
  74. 'of the model %v should have one of data types: %l, but %v given.',
  75. propName,
  76. modelName,
  77. Object.values(Type),
  78. propDef,
  79. );
  80. return;
  81. }
  82. if (!propDef || typeof propDef !== 'object' || Array.isArray(propDef)) {
  83. throw new InvalidArgumentError(
  84. 'In case of a full property definition, the property %v ' +
  85. 'of the model %v should be an Object, but %v given.',
  86. propName,
  87. modelName,
  88. propDef,
  89. );
  90. }
  91. if (!propDef.type || !Object.values(Type).includes(propDef.type))
  92. throw new InvalidArgumentError(
  93. 'The property %v of the model %v requires the option "type" ' +
  94. 'to have one of data types: %l, but %v given.',
  95. propName,
  96. modelName,
  97. Object.values(Type),
  98. propDef.type,
  99. );
  100. if (propDef.itemType && !Object.values(Type).includes(propDef.itemType)) {
  101. throw new InvalidArgumentError(
  102. 'The provided option "itemType" of the property %v in the model %v ' +
  103. 'should have one of data types: %l, but %v given.',
  104. propName,
  105. modelName,
  106. Object.values(Type),
  107. propDef.itemType,
  108. );
  109. }
  110. if (propDef.model && typeof propDef.model !== 'string')
  111. throw new InvalidArgumentError(
  112. 'The provided option "model" of the property %v in the model %v ' +
  113. 'should be a String, but %v given.',
  114. propName,
  115. modelName,
  116. propDef.model,
  117. );
  118. if (propDef.primaryKey && typeof propDef.primaryKey !== 'boolean')
  119. throw new InvalidArgumentError(
  120. 'The provided option "primaryKey" of the property %v in the model %v ' +
  121. 'should be a Boolean, but %v given.',
  122. propName,
  123. modelName,
  124. propDef.primaryKey,
  125. );
  126. if (propDef.columnName && typeof propDef.columnName !== 'string')
  127. throw new InvalidArgumentError(
  128. 'The provided option "columnName" of the property %v in the model %v ' +
  129. 'should be a String, but %v given.',
  130. propName,
  131. modelName,
  132. propDef.columnName,
  133. );
  134. if (propDef.columnType && typeof propDef.columnType !== 'string')
  135. throw new InvalidArgumentError(
  136. 'The provided option "columnType" of the property %v in the model %v ' +
  137. 'should be a String, but %v given.',
  138. propName,
  139. modelName,
  140. propDef.columnType,
  141. );
  142. if (propDef.required && typeof propDef.required !== 'boolean')
  143. throw new InvalidArgumentError(
  144. 'The provided option "required" of the property %v in the model %v ' +
  145. 'should be a Boolean, but %v given.',
  146. propName,
  147. modelName,
  148. propDef.required,
  149. );
  150. if (propDef.required && propDef.default !== undefined)
  151. throw new InvalidArgumentError(
  152. 'The property %v of the model %v is a required property, ' +
  153. 'so it should not have the option "default" to be provided.',
  154. propName,
  155. modelName,
  156. );
  157. if (propDef.primaryKey && propDef.required)
  158. throw new InvalidArgumentError(
  159. 'The property %v of the model %v is a primary key, ' +
  160. 'so it should not have the option "required" to be provided.',
  161. propName,
  162. modelName,
  163. );
  164. if (propDef.primaryKey && propDef.default !== undefined)
  165. throw new InvalidArgumentError(
  166. 'The property %v of the model %v is a primary key, ' +
  167. 'so it should not have the option "default" to be provided.',
  168. propName,
  169. modelName,
  170. );
  171. if (propDef.itemType && propDef.type !== Type.ARRAY)
  172. throw new InvalidArgumentError(
  173. 'The property %v of the model %v has the non-array type, ' +
  174. 'so it should not have the option "itemType" to be provided.',
  175. propName,
  176. modelName,
  177. propDef.type,
  178. );
  179. if (
  180. propDef.model &&
  181. propDef.type !== Type.OBJECT &&
  182. propDef.itemType !== Type.OBJECT
  183. ) {
  184. if (propDef.type !== Type.ARRAY) {
  185. throw new InvalidArgumentError(
  186. 'The option "model" is not supported for %s property type, ' +
  187. 'so the property %v of the model %v should not have ' +
  188. 'the option "model" to be provided.',
  189. capitalize(propDef.type),
  190. propName,
  191. modelName,
  192. );
  193. } else {
  194. throw new InvalidArgumentError(
  195. 'The option "model" is not supported for Array property type of %s, ' +
  196. 'so the property %v of the model %v should not have ' +
  197. 'the option "model" to be provided.',
  198. capitalize(propDef.itemType),
  199. propName,
  200. modelName,
  201. );
  202. }
  203. }
  204. }
  205. }