joinTables.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. var assert = require('assert');
  2. var _ = require('@sailshq/lodash');
  3. var SchemaBuilder = require('../lib/waterline-schema/schema');
  4. var ForeignKeyMapper = require('../lib/waterline-schema/foreignKeys');
  5. var JoinTableMapper = require('../lib/waterline-schema/joinTables');
  6. describe('Join Table Mapper :: ', function() {
  7. describe('Auto mapping of foreign keys', function() {
  8. var schema;
  9. before(function() {
  10. var fixtures = [
  11. {
  12. identity: 'foo',
  13. primaryKey: 'id',
  14. connection: 'bar',
  15. attributes: {
  16. id: {
  17. type: 'number'
  18. },
  19. bars: {
  20. collection: 'bar',
  21. via: 'foos',
  22. dominant: true
  23. }
  24. }
  25. },
  26. {
  27. identity: 'bar',
  28. primaryKey: 'id',
  29. connection: 'bar',
  30. attributes: {
  31. id: {
  32. type: 'number'
  33. },
  34. foos: {
  35. collection: 'foo',
  36. via: 'bars'
  37. }
  38. }
  39. }
  40. ];
  41. var collections = _.map(fixtures, function(obj) {
  42. var collection = function() {};
  43. collection.prototype = obj;
  44. return collection;
  45. });
  46. // Build the schema
  47. schema = SchemaBuilder(collections);
  48. ForeignKeyMapper(schema);
  49. JoinTableMapper(schema);
  50. });
  51. it('should add a junction table for a many to many relationship', function() {
  52. assert(schema.bar_foos__foo_bars);
  53. assert.equal(schema.bar_foos__foo_bars.identity, 'bar_foos__foo_bars');
  54. assert.equal(schema.bar_foos__foo_bars.junctionTable, true);
  55. assert(schema.bar_foos__foo_bars.schema.foo_bars);
  56. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.type, 'number');
  57. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.columnName, 'foo_bars');
  58. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.foreignKey, true);
  59. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.references, 'foo');
  60. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.on, 'id');
  61. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.groupKey, 'foo');
  62. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.model, 'foo');
  63. assert(schema.bar_foos__foo_bars.schema.bar_foos);
  64. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.type, 'number');
  65. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.columnName, 'bar_foos');
  66. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.foreignKey, true);
  67. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.references, 'bar');
  68. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.on, 'id');
  69. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.groupKey, 'bar');
  70. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.model, 'bar');
  71. });
  72. it('should update the parent collection to point to the join table', function() {
  73. assert(schema.foo.schema.bars.references === 'bar_foos__foo_bars');
  74. assert(schema.foo.schema.bars.on === 'foo_bars');
  75. assert(schema.bar.schema.foos.references === 'bar_foos__foo_bars');
  76. assert(schema.bar.schema.foos.on === 'bar_foos');
  77. });
  78. });
  79. describe('mapping of custom foreign keys', function() {
  80. var schema;
  81. before(function() {
  82. var fixtures = [
  83. {
  84. identity: 'foo',
  85. connection: 'bar',
  86. primaryKey: 'uuid',
  87. attributes: {
  88. uuid: {
  89. type: 'string',
  90. },
  91. bars: {
  92. collection: 'bar',
  93. via: 'foos'
  94. }
  95. }
  96. },
  97. {
  98. identity: 'bar',
  99. connection: 'bar',
  100. primaryKey: 'area',
  101. attributes: {
  102. area: {
  103. type: 'number'
  104. },
  105. foos: {
  106. collection: 'foo',
  107. via: 'bars',
  108. dominant: true
  109. }
  110. }
  111. }
  112. ];
  113. var collections = _.map(fixtures, function(obj) {
  114. var collection = function() {};
  115. collection.prototype = obj;
  116. return collection;
  117. });
  118. // Build the schema
  119. schema = SchemaBuilder(collections);
  120. ForeignKeyMapper(schema);
  121. JoinTableMapper(schema);
  122. });
  123. it('should add a junction table for a many to many relationship', function() {
  124. assert(schema.bar_foos__foo_bars);
  125. assert.equal(schema.bar_foos__foo_bars.identity, 'bar_foos__foo_bars');
  126. assert.equal(schema.bar_foos__foo_bars.junctionTable, true);
  127. assert(schema.bar_foos__foo_bars.schema.foo_bars);
  128. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.type, 'string');
  129. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.columnName, 'foo_bars');
  130. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.foreignKey, true);
  131. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.references, 'foo');
  132. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.on, 'uuid');
  133. assert.equal(schema.bar_foos__foo_bars.schema.foo_bars.groupKey, 'foo');
  134. assert(schema.bar_foos__foo_bars.schema.bar_foos);
  135. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.type, 'number');
  136. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.columnName, 'bar_foos');
  137. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.foreignKey, true);
  138. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.references, 'bar');
  139. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.on, 'area');
  140. assert.equal(schema.bar_foos__foo_bars.schema.bar_foos.groupKey, 'bar');
  141. });
  142. });
  143. describe('mapping of custom foreign keys with the wrong `via` value', function() {
  144. var schema;
  145. before(function() {
  146. var fixtures = [
  147. {
  148. identity: 'foo',
  149. connection: 'bar',
  150. primaryKey: 'uuid',
  151. attributes: {
  152. uuid: {
  153. type: 'string'
  154. },
  155. bars: {
  156. collection: 'bar',
  157. via: 'foos'
  158. }
  159. }
  160. },
  161. {
  162. identity: 'bar',
  163. connection: 'bar',
  164. primaryKey: 'area',
  165. attributes: {
  166. area: {
  167. type: 'number'
  168. },
  169. foos: {
  170. collection: 'foo',
  171. via: 'fake',
  172. dominant: true
  173. }
  174. }
  175. }
  176. ];
  177. var collections = _.map(fixtures, function(obj) {
  178. var collection = function() {};
  179. collection.prototype = obj;
  180. return collection;
  181. });
  182. // Build the schema
  183. schema = SchemaBuilder(collections);
  184. ForeignKeyMapper(schema);
  185. });
  186. it('should throw an exception message', function() {
  187. assert.throws(function() {
  188. JoinTableMapper(schema);
  189. });
  190. });
  191. });
  192. describe('self-referencing associations', function() {
  193. var schema;
  194. before(function() {
  195. var fixtures = [
  196. {
  197. identity: 'foo',
  198. connection: 'bar',
  199. primaryKey: 'id',
  200. attributes: {
  201. id: {
  202. type: 'number'
  203. },
  204. isFollowing: {
  205. collection: 'foo',
  206. via: 'followedBy'
  207. },
  208. followedBy: {
  209. collection: 'foo',
  210. via: 'isFollowing'
  211. }
  212. }
  213. }
  214. ];
  215. var collections = _.map(fixtures, function(obj) {
  216. var collection = function() {};
  217. collection.prototype = obj;
  218. return collection;
  219. });
  220. // Build the schema
  221. schema = SchemaBuilder(collections);
  222. ForeignKeyMapper(schema);
  223. JoinTableMapper(schema);
  224. });
  225. it('should add a junction table for the self referencing attributes', function() {
  226. // Validate only a single join table gets setup
  227. assert(schema.foo_followedby__foo_isfollowing);
  228. assert(!schema.foo_isfollowing__foo_followeby);
  229. assert(schema.foo_followedby__foo_isfollowing.schema.foo_isFollowing);
  230. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_isFollowing.type, 'number');
  231. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_isFollowing.columnName, 'foo_isFollowing');
  232. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_isFollowing.foreignKey, true);
  233. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_isFollowing.references, 'foo');
  234. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_isFollowing.on, 'id');
  235. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_isFollowing.groupKey, 'foo');
  236. assert(schema.foo_followedby__foo_isfollowing.schema.foo_followedBy);
  237. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_followedBy.type, 'number');
  238. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_followedBy.columnName, 'foo_followedBy');
  239. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_followedBy.foreignKey, true);
  240. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_followedBy.references, 'foo');
  241. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_followedBy.on, 'id');
  242. assert.equal(schema.foo_followedby__foo_isfollowing.schema.foo_followedBy.groupKey, 'foo');
  243. assert.equal(schema.foo.schema.isFollowing.references, 'foo_followedBy__foo_isFollowing');
  244. assert.equal(schema.foo.schema.isFollowing.on, 'foo_isFollowing');
  245. assert.equal(schema.foo.schema.followedBy.references, 'foo_followedBy__foo_isFollowing');
  246. assert.equal(schema.foo.schema.followedBy.on, 'foo_followedBy');
  247. });
  248. });
  249. describe('junction table between the same model', function() {
  250. var schema;
  251. before(function() {
  252. var fixtures = [
  253. {
  254. identity: 'foo',
  255. connection: 'foo',
  256. primaryKey: 'id',
  257. attributes: {
  258. id: {
  259. type: 'number'
  260. },
  261. follows: {
  262. collection: 'foo',
  263. through: 'bar',
  264. via: 'to'
  265. },
  266. followers: {
  267. collection: 'foo',
  268. through: 'bar',
  269. via: 'from'
  270. }
  271. }
  272. },
  273. {
  274. identity: 'bar',
  275. connection: 'foo',
  276. primaryKey: 'id',
  277. attributes: {
  278. id: {
  279. type: 'number'
  280. },
  281. to: {
  282. model: 'foo'
  283. },
  284. from: {
  285. model: 'foo'
  286. }
  287. }
  288. }
  289. ];
  290. var collections = _.map(fixtures, function(obj) {
  291. var collection = function() {};
  292. collection.prototype = obj;
  293. return collection;
  294. });
  295. // Build the schema
  296. schema = SchemaBuilder(collections);
  297. ForeignKeyMapper(schema);
  298. JoinTableMapper(schema);
  299. });
  300. it('should expand the attributes on `bar`', function() {
  301. assert.equal(schema.foo.schema.follows.onKey, 'to');
  302. assert.equal(schema.foo.schema.follows.on, 'to');
  303. assert.equal(schema.foo.schema.followers.onKey, 'from');
  304. assert.equal(schema.foo.schema.followers.on, 'from');
  305. });
  306. });
  307. });