has-many-resolver.spec.js 89 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911
  1. import {format} from 'util';
  2. import {expect} from 'chai';
  3. import {Schema} from '../schema.js';
  4. import {DataType} from '../definition/index.js';
  5. import {RelationType} from '../definition/index.js';
  6. import {HasManyResolver} from './has-many-resolver.js';
  7. import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '../definition/index.js';
  8. describe('HasManyResolver', function () {
  9. describe('includeTo', function () {
  10. it('requires the "entities" parameter to be an array', async function () {
  11. const S = new Schema();
  12. const R = S.get(HasManyResolver);
  13. const error = v =>
  14. format(
  15. 'The parameter "entities" of HasManyResolver.includeTo requires ' +
  16. 'an Array of Object, but %s given.',
  17. v,
  18. );
  19. const throwable = v =>
  20. R.includeTo(
  21. v,
  22. 'sourceName',
  23. 'targetName',
  24. 'relationName',
  25. 'foreignKey',
  26. );
  27. await expect(throwable('')).to.be.rejectedWith(error('""'));
  28. await expect(throwable('str')).to.be.rejectedWith(error('"str"'));
  29. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  30. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  31. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  32. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  33. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  34. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  35. });
  36. it('requires elements of the "entities" parameter to be an Object', async function () {
  37. const S = new Schema();
  38. S.defineModel({name: 'source'});
  39. const R = S.get(HasManyResolver);
  40. const error = v =>
  41. format(
  42. 'The parameter "entities" of HasManyResolver.includeTo requires ' +
  43. 'an Array of Object, but %s given.',
  44. v,
  45. );
  46. const throwable = v =>
  47. R.includeTo([v], 'source', 'target', 'relationName', 'foreignKey');
  48. await expect(throwable('')).to.be.rejectedWith(error('""'));
  49. await expect(throwable('str')).to.be.rejectedWith(error('"str"'));
  50. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  51. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  52. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  53. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  54. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  55. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  56. });
  57. it('requires the "sourceName" parameter to be a non-empty string', async function () {
  58. const S = new Schema();
  59. const R = S.get(HasManyResolver);
  60. const error = v =>
  61. format(
  62. 'The parameter "sourceName" of HasManyResolver.includeTo requires ' +
  63. 'a non-empty String, but %s given.',
  64. v,
  65. );
  66. const throwable = v =>
  67. R.includeTo([], v, 'targetName', 'relationName', 'foreignKey');
  68. await expect(throwable('')).to.be.rejectedWith(error('""'));
  69. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  70. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  71. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  72. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  73. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  74. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  75. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  76. });
  77. it('requires the "targetName" parameter to be a non-empty string', async function () {
  78. const S = new Schema();
  79. const R = S.get(HasManyResolver);
  80. const error = v =>
  81. format(
  82. 'The parameter "targetName" of HasManyResolver.includeTo requires ' +
  83. 'a non-empty String, but %s given.',
  84. v,
  85. );
  86. const throwable = v =>
  87. R.includeTo([], 'sourceName', v, 'relationName', 'foreignKey');
  88. await expect(throwable('')).to.be.rejectedWith(error('""'));
  89. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  90. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  91. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  92. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  93. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  94. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  95. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  96. });
  97. it('requires the "relationName" parameter to be a non-empty string', async function () {
  98. const S = new Schema();
  99. const R = S.get(HasManyResolver);
  100. const error = v =>
  101. format(
  102. 'The parameter "relationName" of HasManyResolver.includeTo requires ' +
  103. 'a non-empty String, but %s given.',
  104. v,
  105. );
  106. const throwable = v =>
  107. R.includeTo([], 'sourceName', 'targetName', v, 'foreignKey');
  108. await expect(throwable('')).to.be.rejectedWith(error('""'));
  109. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  110. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  111. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  112. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  113. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  114. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  115. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  116. });
  117. it('requires the "foreignKey" parameter to be a non-empty string', async function () {
  118. const S = new Schema();
  119. const R = S.get(HasManyResolver);
  120. const error = v =>
  121. format(
  122. 'The parameter "foreignKey" of HasManyResolver.includeTo requires ' +
  123. 'a non-empty String, but %s given.',
  124. v,
  125. );
  126. const throwable = v =>
  127. R.includeTo([], 'sourceName', 'targetName', 'relationName', v);
  128. await expect(throwable('')).to.be.rejectedWith(error('""'));
  129. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  130. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  131. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  132. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  133. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  134. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  135. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  136. });
  137. it('requires the provided parameter "scope" to be an object', async function () {
  138. const S = new Schema();
  139. const R = S.get(HasManyResolver);
  140. const error = v =>
  141. format(
  142. 'The provided parameter "scope" of HasManyResolver.includeTo ' +
  143. 'should be an Object, but %s given.',
  144. v,
  145. );
  146. const throwable = v =>
  147. R.includeTo(
  148. [],
  149. 'sourceName',
  150. 'targetName',
  151. 'relationName',
  152. 'foreignKey',
  153. v,
  154. );
  155. await expect(throwable('str')).to.be.rejectedWith(error('"str"'));
  156. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  157. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  158. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  159. });
  160. it('throws an error if a target model is not found', async function () {
  161. const S = new Schema();
  162. S.defineModel({name: 'source'});
  163. const R = S.get(HasManyResolver);
  164. const promise = R.includeTo(
  165. [],
  166. 'source',
  167. 'target',
  168. 'relationName',
  169. 'foreignKey',
  170. );
  171. await expect(promise).to.be.rejectedWith(
  172. 'The model "target" is not defined',
  173. );
  174. });
  175. it('throws an error if a target model does not have datasource', async function () {
  176. const S = new Schema();
  177. S.defineModel({name: 'source'});
  178. S.defineModel({name: 'target'});
  179. const R = S.get(HasManyResolver);
  180. const promise = R.includeTo(
  181. [],
  182. 'source',
  183. 'target',
  184. 'relationName',
  185. 'foreignKey',
  186. );
  187. await expect(promise).to.be.rejectedWith(
  188. 'The model "target" does not have a specified datasource.',
  189. );
  190. });
  191. it('does not throw an error if a relation target is not exist', async function () {
  192. const S = new Schema();
  193. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  194. S.defineModel({name: 'source', datasource: 'datasource'});
  195. S.defineModel({name: 'target', datasource: 'datasource'});
  196. const sourceRel = S.getRepository('source');
  197. const source = await sourceRel.create({});
  198. const R = S.get(HasManyResolver);
  199. await R.includeTo([source], 'source', 'target', 'children', 'parentId');
  200. expect(source).to.be.eql({
  201. [DEF_PK]: source[DEF_PK],
  202. children: [],
  203. });
  204. });
  205. it('includes if a primary key is not defined in the source model', async function () {
  206. const S = new Schema();
  207. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  208. S.defineModel({name: 'source', datasource: 'datasource'});
  209. S.defineModel({name: 'target', datasource: 'datasource'});
  210. const sourceRep = S.getRepository('source');
  211. const targetRep = S.getRepository('target');
  212. const source = await sourceRep.create({});
  213. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  214. const target1 = await targetRep.create({parentId: source[DEF_PK]});
  215. const target2 = await targetRep.create({parentId: source[DEF_PK]});
  216. const target3 = await targetRep.create({parentId: -1});
  217. expect(target1).to.be.eql({
  218. [DEF_PK]: target1[DEF_PK],
  219. parentId: source[DEF_PK],
  220. });
  221. expect(target2).to.be.eql({
  222. [DEF_PK]: target2[DEF_PK],
  223. parentId: source[DEF_PK],
  224. });
  225. expect(target3).to.be.eql({
  226. [DEF_PK]: target3[DEF_PK],
  227. parentId: -1,
  228. });
  229. const R = S.get(HasManyResolver);
  230. await R.includeTo([source], 'source', 'target', 'children', 'parentId');
  231. expect(source).to.be.eql({
  232. [DEF_PK]: source[DEF_PK],
  233. children: [
  234. {
  235. id: target1[DEF_PK],
  236. parentId: source[DEF_PK],
  237. },
  238. {
  239. id: target2[DEF_PK],
  240. parentId: source[DEF_PK],
  241. },
  242. ],
  243. });
  244. });
  245. it('includes if the source model has a custom primary key', async function () {
  246. const S = new Schema();
  247. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  248. S.defineModel({
  249. name: 'source',
  250. datasource: 'datasource',
  251. properties: {
  252. myId: {
  253. type: DataType.NUMBER,
  254. primaryKey: true,
  255. },
  256. },
  257. });
  258. S.defineModel({name: 'target', datasource: 'datasource'});
  259. const sourceRep = S.getRepository('source');
  260. const targetRep = S.getRepository('target');
  261. const source = await sourceRep.create({});
  262. expect(source).to.be.eql({myId: source.myId});
  263. const target1 = await targetRep.create({parentId: source.myId});
  264. const target2 = await targetRep.create({parentId: source.myId});
  265. const target3 = await targetRep.create({parentId: -1});
  266. expect(target1).to.be.eql({
  267. [DEF_PK]: target1[DEF_PK],
  268. parentId: source.myId,
  269. });
  270. expect(target2).to.be.eql({
  271. [DEF_PK]: target2[DEF_PK],
  272. parentId: source.myId,
  273. });
  274. expect(target3).to.be.eql({
  275. [DEF_PK]: target3[DEF_PK],
  276. parentId: -1,
  277. });
  278. const R = S.get(HasManyResolver);
  279. await R.includeTo([source], 'source', 'target', 'children', 'parentId');
  280. expect(source).to.be.eql({
  281. myId: source.myId,
  282. children: [
  283. {
  284. [DEF_PK]: target1[DEF_PK],
  285. parentId: source.myId,
  286. },
  287. {
  288. [DEF_PK]: target2[DEF_PK],
  289. parentId: source.myId,
  290. },
  291. ],
  292. });
  293. });
  294. it('includes if the target model has a custom primary key', async function () {
  295. const S = new Schema();
  296. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  297. S.defineModel({name: 'source', datasource: 'datasource'});
  298. S.defineModel({
  299. name: 'target',
  300. datasource: 'datasource',
  301. properties: {
  302. myId: {
  303. type: DataType.NUMBER,
  304. primaryKey: true,
  305. },
  306. },
  307. });
  308. const sourceRep = S.getRepository('source');
  309. const targetRep = S.getRepository('target');
  310. const source = await sourceRep.create({});
  311. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  312. const target1 = await targetRep.create({parentId: source[DEF_PK]});
  313. const target2 = await targetRep.create({parentId: source[DEF_PK]});
  314. const target3 = await targetRep.create({parentId: -1});
  315. expect(target1).to.be.eql({
  316. myId: target1.myId,
  317. parentId: source[DEF_PK],
  318. });
  319. expect(target2).to.be.eql({
  320. myId: target2.myId,
  321. parentId: source[DEF_PK],
  322. });
  323. expect(target3).to.be.eql({
  324. myId: target3.myId,
  325. parentId: -1,
  326. });
  327. const R = S.get(HasManyResolver);
  328. await R.includeTo([source], 'source', 'target', 'children', 'parentId');
  329. expect(source).to.be.eql({
  330. [DEF_PK]: source[DEF_PK],
  331. children: [
  332. {
  333. myId: target1.myId,
  334. parentId: source[DEF_PK],
  335. },
  336. {
  337. myId: target2.myId,
  338. parentId: source[DEF_PK],
  339. },
  340. ],
  341. });
  342. });
  343. it('uses a where clause of the given scope to filter the relation target', async function () {
  344. const S = new Schema();
  345. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  346. S.defineModel({name: 'source', datasource: 'datasource'});
  347. S.defineModel({name: 'target', datasource: 'datasource'});
  348. const sourceRep = S.getRepository('source');
  349. const targetRep = S.getRepository('target');
  350. const source = await sourceRep.create({});
  351. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  352. const target1 = await targetRep.create({
  353. featured: false,
  354. parentId: source[DEF_PK],
  355. });
  356. expect(target1).to.be.eql({
  357. [DEF_PK]: target1[DEF_PK],
  358. featured: false,
  359. parentId: source[DEF_PK],
  360. });
  361. const target2 = await targetRep.create({
  362. featured: true,
  363. parentId: source[DEF_PK],
  364. });
  365. expect(target2).to.be.eql({
  366. [DEF_PK]: target2[DEF_PK],
  367. featured: true,
  368. parentId: source[DEF_PK],
  369. });
  370. const target3 = await targetRep.create({
  371. featured: true,
  372. parentId: source[DEF_PK],
  373. });
  374. expect(target3).to.be.eql({
  375. [DEF_PK]: target3[DEF_PK],
  376. featured: true,
  377. parentId: source[DEF_PK],
  378. });
  379. const R = S.get(HasManyResolver);
  380. await R.includeTo([source], 'source', 'target', 'children', 'parentId', {
  381. where: {featured: false},
  382. });
  383. expect(source).to.be.eql({
  384. [DEF_PK]: source[DEF_PK],
  385. children: [
  386. {
  387. [DEF_PK]: target1[DEF_PK],
  388. featured: false,
  389. parentId: source[DEF_PK],
  390. },
  391. ],
  392. });
  393. await R.includeTo([source], 'source', 'target', 'children', 'parentId', {
  394. where: {featured: true},
  395. });
  396. expect(source).to.be.eql({
  397. [DEF_PK]: source[DEF_PK],
  398. children: [
  399. {
  400. [DEF_PK]: target2[DEF_PK],
  401. featured: true,
  402. parentId: source[DEF_PK],
  403. },
  404. {
  405. [DEF_PK]: target3[DEF_PK],
  406. featured: true,
  407. parentId: source[DEF_PK],
  408. },
  409. ],
  410. });
  411. });
  412. it('uses a fields clause of the given scope to filter the relation target', async function () {
  413. const S = new Schema();
  414. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  415. S.defineModel({name: 'source', datasource: 'datasource'});
  416. S.defineModel({name: 'target', datasource: 'datasource'});
  417. const sourceRep = S.getRepository('source');
  418. const targetRep = S.getRepository('target');
  419. const source = await sourceRep.create({});
  420. expect(source).to.be.eql({
  421. [DEF_PK]: source[DEF_PK],
  422. });
  423. const target1 = await targetRep.create({
  424. foo: 'fooVal1',
  425. bar: 'barVal1',
  426. parentId: source[DEF_PK],
  427. });
  428. expect(target1).to.be.eql({
  429. [DEF_PK]: target1[DEF_PK],
  430. foo: 'fooVal1',
  431. bar: 'barVal1',
  432. parentId: source[DEF_PK],
  433. });
  434. const target2 = await targetRep.create({
  435. foo: 'fooVal2',
  436. bar: 'barVal2',
  437. parentId: source[DEF_PK],
  438. });
  439. expect(target2).to.be.eql({
  440. [DEF_PK]: target2[DEF_PK],
  441. foo: 'fooVal2',
  442. bar: 'barVal2',
  443. parentId: source[DEF_PK],
  444. });
  445. const target3 = await targetRep.create({
  446. foo: 'fooVal3',
  447. bar: 'barVal3',
  448. parentId: -1,
  449. });
  450. expect(target3).to.be.eql({
  451. [DEF_PK]: target3[DEF_PK],
  452. foo: 'fooVal3',
  453. bar: 'barVal3',
  454. parentId: -1,
  455. });
  456. const R = S.get(HasManyResolver);
  457. await R.includeTo([source], 'source', 'target', 'children', 'parentId', {
  458. fields: [DEF_PK, 'bar'],
  459. });
  460. expect(source).to.be.eql({
  461. [DEF_PK]: source[DEF_PK],
  462. children: [
  463. {
  464. [DEF_PK]: target1[DEF_PK],
  465. bar: target1.bar,
  466. },
  467. {
  468. [DEF_PK]: target2[DEF_PK],
  469. bar: target2.bar,
  470. },
  471. ],
  472. });
  473. });
  474. it('uses an include clause of the given scope to resolve target relations', async function () {
  475. const S = new Schema();
  476. S.defineDatasource({
  477. name: 'datasource',
  478. adapter: 'memory',
  479. });
  480. S.defineModel({
  481. name: 'modelA',
  482. datasource: 'datasource',
  483. properties: {
  484. id: {
  485. type: DataType.NUMBER,
  486. primaryKey: true,
  487. },
  488. source: {
  489. type: DataType.STRING,
  490. default: 'modelA',
  491. },
  492. },
  493. relations: {
  494. children: {
  495. type: RelationType.HAS_MANY,
  496. model: 'modelB',
  497. foreignKey: 'parentId',
  498. },
  499. },
  500. });
  501. S.defineModel({
  502. name: 'modelB',
  503. datasource: 'datasource',
  504. properties: {
  505. id: {
  506. type: DataType.NUMBER,
  507. primaryKey: true,
  508. },
  509. source: {
  510. type: DataType.STRING,
  511. default: 'modelB',
  512. },
  513. },
  514. relations: {
  515. children: {
  516. type: RelationType.HAS_MANY,
  517. model: 'modelC',
  518. foreignKey: 'parentId',
  519. },
  520. },
  521. });
  522. S.defineModel({
  523. name: 'modelC',
  524. datasource: 'datasource',
  525. properties: {
  526. id: {
  527. type: DataType.NUMBER,
  528. primaryKey: true,
  529. },
  530. source: {
  531. type: DataType.STRING,
  532. default: 'modelC',
  533. },
  534. },
  535. });
  536. const aRep = S.getRepository('modelA');
  537. const bRep = S.getRepository('modelB');
  538. const cRep = S.getRepository('modelC');
  539. const a = await aRep.create({});
  540. const b1 = await bRep.create({parentId: a.id});
  541. const b2 = await bRep.create({parentId: a.id});
  542. const b3 = await bRep.create({parentId: -1});
  543. const c1 = await cRep.create({parentId: b1.id});
  544. const c2 = await cRep.create({parentId: b1.id});
  545. const c3 = await cRep.create({parentId: b2.id});
  546. const c4 = await cRep.create({parentId: b2.id});
  547. expect(a).to.be.eql({
  548. id: a.id,
  549. source: 'modelA',
  550. });
  551. expect(b1).to.be.eql({
  552. id: b1.id,
  553. source: 'modelB',
  554. parentId: a.id,
  555. });
  556. expect(b2).to.be.eql({
  557. id: b2.id,
  558. source: 'modelB',
  559. parentId: a.id,
  560. });
  561. expect(b3).to.be.eql({
  562. id: b3.id,
  563. source: 'modelB',
  564. parentId: -1,
  565. });
  566. expect(c1).to.be.eql({
  567. id: c1.id,
  568. source: 'modelC',
  569. parentId: b1.id,
  570. });
  571. expect(c2).to.be.eql({
  572. id: c2.id,
  573. source: 'modelC',
  574. parentId: b1.id,
  575. });
  576. expect(c3).to.be.eql({
  577. id: c3.id,
  578. source: 'modelC',
  579. parentId: b2.id,
  580. });
  581. expect(c4).to.be.eql({
  582. id: c4.id,
  583. source: 'modelC',
  584. parentId: b2.id,
  585. });
  586. const R = S.get(HasManyResolver);
  587. await R.includeTo([a], 'modelA', 'modelB', 'children', 'parentId', {
  588. include: 'children',
  589. });
  590. expect(a).to.be.eql({
  591. id: a.id,
  592. source: 'modelA',
  593. children: [
  594. {
  595. id: b1.id,
  596. source: 'modelB',
  597. parentId: a.id,
  598. children: [
  599. {
  600. id: c1.id,
  601. source: 'modelC',
  602. parentId: b1.id,
  603. },
  604. {
  605. id: c2.id,
  606. source: 'modelC',
  607. parentId: b1.id,
  608. },
  609. ],
  610. },
  611. {
  612. id: b2.id,
  613. source: 'modelB',
  614. parentId: a.id,
  615. children: [
  616. {
  617. id: c3.id,
  618. source: 'modelC',
  619. parentId: b2.id,
  620. },
  621. {
  622. id: c4.id,
  623. source: 'modelC',
  624. parentId: b2.id,
  625. },
  626. ],
  627. },
  628. ],
  629. });
  630. });
  631. it('does not break the "and" operator of the given "where" clause', async function () {
  632. const S = new Schema();
  633. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  634. S.defineModel({name: 'source', datasource: 'datasource'});
  635. S.defineModel({name: 'target', datasource: 'datasource'});
  636. const sourceRep = S.getRepository('source');
  637. const targetRep = S.getRepository('target');
  638. const source = await sourceRep.create({});
  639. expect(source).to.be.eql({
  640. [DEF_PK]: source[DEF_PK],
  641. });
  642. const target1 = await targetRep.create({
  643. featured: false,
  644. parentId: source[DEF_PK],
  645. });
  646. expect(target1).to.be.eql({
  647. [DEF_PK]: target1[DEF_PK],
  648. featured: false,
  649. parentId: source[DEF_PK],
  650. });
  651. const target2 = await targetRep.create({
  652. featured: true,
  653. parentId: source[DEF_PK],
  654. });
  655. expect(target2).to.be.eql({
  656. [DEF_PK]: target2[DEF_PK],
  657. featured: true,
  658. parentId: source[DEF_PK],
  659. });
  660. const target3 = await targetRep.create({
  661. featured: true,
  662. parentId: source[DEF_PK],
  663. });
  664. expect(target3).to.be.eql({
  665. [DEF_PK]: target3[DEF_PK],
  666. featured: true,
  667. parentId: source[DEF_PK],
  668. });
  669. const R = S.get(HasManyResolver);
  670. await R.includeTo([source], 'source', 'target', 'children', 'parentId', {
  671. where: {and: [{featured: false}]},
  672. });
  673. expect(source).to.be.eql({
  674. [DEF_PK]: source[DEF_PK],
  675. children: [
  676. {
  677. [DEF_PK]: target1[DEF_PK],
  678. featured: false,
  679. parentId: source[DEF_PK],
  680. },
  681. ],
  682. });
  683. delete source.children;
  684. await R.includeTo([source], 'source', 'target', 'children', 'parentId', {
  685. where: {and: [{featured: true}]},
  686. });
  687. expect(source).to.be.eql({
  688. [DEF_PK]: source[DEF_PK],
  689. children: [
  690. {
  691. [DEF_PK]: target2[DEF_PK],
  692. featured: true,
  693. parentId: source[DEF_PK],
  694. },
  695. {
  696. [DEF_PK]: target3[DEF_PK],
  697. featured: true,
  698. parentId: source[DEF_PK],
  699. },
  700. ],
  701. });
  702. });
  703. });
  704. describe('includePolymorphicTo', function () {
  705. it('requires the "entities" parameter to be an array', async function () {
  706. const S = new Schema();
  707. const R = S.get(HasManyResolver);
  708. const error = v =>
  709. format(
  710. 'The parameter "entities" of HasManyResolver.includePolymorphicTo requires ' +
  711. 'an Array of Object, but %s given.',
  712. v,
  713. );
  714. const throwable = v =>
  715. R.includePolymorphicTo(
  716. v,
  717. 'sourceName',
  718. 'targetName',
  719. 'relationName',
  720. 'foreignKey',
  721. 'discriminator',
  722. );
  723. await expect(throwable('')).to.be.rejectedWith(error('""'));
  724. await expect(throwable('str')).to.be.rejectedWith(error('"str"'));
  725. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  726. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  727. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  728. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  729. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  730. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  731. });
  732. it('requires elements of the "entities" parameter to be an Object', async function () {
  733. const S = new Schema();
  734. S.defineModel({name: 'source'});
  735. const R = S.get(HasManyResolver);
  736. const error = v =>
  737. format(
  738. 'The parameter "entities" of HasManyResolver.includePolymorphicTo requires ' +
  739. 'an Array of Object, but %s given.',
  740. v,
  741. );
  742. const throwable = v =>
  743. R.includePolymorphicTo(
  744. [v],
  745. 'source',
  746. 'target',
  747. 'relationName',
  748. 'foreignKey',
  749. 'discriminator',
  750. );
  751. await expect(throwable('')).to.be.rejectedWith(error('""'));
  752. await expect(throwable('str')).to.be.rejectedWith(error('"str"'));
  753. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  754. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  755. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  756. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  757. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  758. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  759. });
  760. it('requires the "sourceName" parameter to be a non-empty string', async function () {
  761. const S = new Schema();
  762. const R = S.get(HasManyResolver);
  763. const error = v =>
  764. format(
  765. 'The parameter "sourceName" of HasManyResolver.includePolymorphicTo requires ' +
  766. 'a non-empty String, but %s given.',
  767. v,
  768. );
  769. const throwable = v =>
  770. R.includePolymorphicTo(
  771. [],
  772. v,
  773. 'targetName',
  774. 'relationName',
  775. 'foreignKey',
  776. 'discriminator',
  777. );
  778. await expect(throwable('')).to.be.rejectedWith(error('""'));
  779. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  780. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  781. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  782. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  783. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  784. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  785. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  786. });
  787. it('requires the "targetName" parameter to be a non-empty string', async function () {
  788. const S = new Schema();
  789. const R = S.get(HasManyResolver);
  790. const error = v =>
  791. format(
  792. 'The parameter "targetName" of HasManyResolver.includePolymorphicTo requires ' +
  793. 'a non-empty String, but %s given.',
  794. v,
  795. );
  796. const throwable = v =>
  797. R.includePolymorphicTo(
  798. [],
  799. 'sourceName',
  800. v,
  801. 'relationName',
  802. 'foreignKey',
  803. 'discriminator',
  804. );
  805. await expect(throwable('')).to.be.rejectedWith(error('""'));
  806. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  807. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  808. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  809. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  810. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  811. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  812. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  813. });
  814. it('requires the "relationName" parameter to be a non-empty string', async function () {
  815. const S = new Schema();
  816. const R = S.get(HasManyResolver);
  817. const error = v =>
  818. format(
  819. 'The parameter "relationName" of HasManyResolver.includePolymorphicTo requires ' +
  820. 'a non-empty String, but %s given.',
  821. v,
  822. );
  823. const throwable = v =>
  824. R.includePolymorphicTo(
  825. [],
  826. 'sourceName',
  827. 'targetName',
  828. v,
  829. 'foreignKey',
  830. 'discriminator',
  831. );
  832. await expect(throwable('')).to.be.rejectedWith(error('""'));
  833. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  834. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  835. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  836. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  837. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  838. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  839. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  840. });
  841. it('requires the "foreignKey" parameter to be a non-empty string', async function () {
  842. const S = new Schema();
  843. const R = S.get(HasManyResolver);
  844. const error = v =>
  845. format(
  846. 'The parameter "foreignKey" of HasManyResolver.includePolymorphicTo requires ' +
  847. 'a non-empty String, but %s given.',
  848. v,
  849. );
  850. const throwable = v =>
  851. R.includePolymorphicTo(
  852. [],
  853. 'sourceName',
  854. 'targetName',
  855. 'relationName',
  856. v,
  857. 'discriminator',
  858. );
  859. await expect(throwable('')).to.be.rejectedWith(error('""'));
  860. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  861. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  862. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  863. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  864. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  865. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  866. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  867. });
  868. it('requires the "discriminator" parameter to be a non-empty string', async function () {
  869. const S = new Schema();
  870. const R = S.get(HasManyResolver);
  871. const error = v =>
  872. format(
  873. 'The parameter "discriminator" of HasManyResolver.includePolymorphicTo requires ' +
  874. 'a non-empty String, but %s given.',
  875. v,
  876. );
  877. const throwable = v =>
  878. R.includePolymorphicTo(
  879. [],
  880. 'sourceName',
  881. 'targetName',
  882. 'relationName',
  883. 'foreignKey',
  884. v,
  885. );
  886. await expect(throwable('')).to.be.rejectedWith(error('""'));
  887. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  888. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  889. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  890. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  891. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  892. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  893. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  894. });
  895. it('requires the provided parameter "scope" to be an object', async function () {
  896. const S = new Schema();
  897. const R = S.get(HasManyResolver);
  898. const error = v =>
  899. format(
  900. 'The provided parameter "scope" of HasManyResolver.includePolymorphicTo ' +
  901. 'should be an Object, but %s given.',
  902. v,
  903. );
  904. const throwable = v =>
  905. R.includePolymorphicTo(
  906. [],
  907. 'sourceName',
  908. 'targetName',
  909. 'relationName',
  910. 'foreignKey',
  911. 'discriminator',
  912. v,
  913. );
  914. await expect(throwable('str')).to.be.rejectedWith(error('"str"'));
  915. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  916. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  917. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  918. });
  919. it('throws an error if the given target model is not found', async function () {
  920. const S = new Schema();
  921. S.defineModel({name: 'source'});
  922. const R = S.get(HasManyResolver);
  923. const entity = {[DEF_PK]: 1};
  924. const promise = R.includePolymorphicTo(
  925. [entity],
  926. 'source',
  927. 'target',
  928. 'children',
  929. 'parentId',
  930. 'parentType',
  931. );
  932. await expect(promise).to.be.rejectedWith(
  933. 'The model "target" is not defined',
  934. );
  935. });
  936. it('throws an error if the given target model does not have a datasource', async function () {
  937. const S = new Schema();
  938. S.defineModel({name: 'source'});
  939. S.defineModel({name: 'target'});
  940. const R = S.get(HasManyResolver);
  941. const entity = {[DEF_PK]: 1};
  942. const promise = R.includePolymorphicTo(
  943. [entity],
  944. 'source',
  945. 'target',
  946. 'children',
  947. 'parentId',
  948. 'parentType',
  949. );
  950. await expect(promise).to.be.rejectedWith(
  951. 'The model "target" does not have a specified datasource.',
  952. );
  953. });
  954. it('does not throw an error if a relation target is not found', async function () {
  955. const S = new Schema();
  956. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  957. S.defineModel({name: 'source', datasource: 'datasource'});
  958. S.defineModel({name: 'target', datasource: 'datasource'});
  959. const sourceRel = S.getRepository('source');
  960. const source = await sourceRel.create({});
  961. expect(source).to.be.eql({
  962. [DEF_PK]: source[DEF_PK],
  963. });
  964. const R = S.get(HasManyResolver);
  965. await R.includePolymorphicTo(
  966. [source],
  967. 'source',
  968. 'target',
  969. 'children',
  970. 'parentId',
  971. 'parentType',
  972. );
  973. expect(source).to.be.eql({
  974. [DEF_PK]: source[DEF_PK],
  975. children: [],
  976. });
  977. });
  978. it('does not include an entity with a not matched discriminator value', async function () {
  979. const S = new Schema();
  980. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  981. S.defineModel({name: 'source', datasource: 'datasource'});
  982. S.defineModel({name: 'target', datasource: 'datasource'});
  983. const sourceRel = S.getRepository('source');
  984. const targetRel = S.getRepository('target');
  985. const source = await sourceRel.create({});
  986. expect(source).to.be.eql({
  987. [DEF_PK]: source[DEF_PK],
  988. });
  989. const target = await targetRel.create({
  990. parentId: source[DEF_PK],
  991. parentType: 'unknown',
  992. });
  993. expect(target).to.be.eql({
  994. [DEF_PK]: target[DEF_PK],
  995. parentId: source[DEF_PK],
  996. parentType: 'unknown',
  997. });
  998. const R = S.get(HasManyResolver);
  999. await R.includePolymorphicTo(
  1000. [source],
  1001. 'source',
  1002. 'target',
  1003. 'children',
  1004. 'parentId',
  1005. 'parentType',
  1006. );
  1007. expect(source).to.be.eql({
  1008. [DEF_PK]: source[DEF_PK],
  1009. children: [],
  1010. });
  1011. });
  1012. it('includes if a primary key is not defined in the source model', async function () {
  1013. const S = new Schema();
  1014. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  1015. S.defineModel({name: 'source', datasource: 'datasource'});
  1016. S.defineModel({name: 'target', datasource: 'datasource'});
  1017. const sourceRep = S.getRepository('source');
  1018. const targetRep = S.getRepository('target');
  1019. const source = await sourceRep.create({});
  1020. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  1021. const target1 = await targetRep.create({
  1022. parentId: source[DEF_PK],
  1023. parentType: 'source',
  1024. });
  1025. expect(target1).to.be.eql({
  1026. [DEF_PK]: target1[DEF_PK],
  1027. parentId: source[DEF_PK],
  1028. parentType: 'source',
  1029. });
  1030. const target2 = await targetRep.create({
  1031. parentId: source[DEF_PK],
  1032. parentType: 'source',
  1033. });
  1034. expect(target2).to.be.eql({
  1035. [DEF_PK]: target2[DEF_PK],
  1036. parentId: source[DEF_PK],
  1037. parentType: 'source',
  1038. });
  1039. const target3 = await targetRep.create({
  1040. parentId: -1,
  1041. parentType: 'source',
  1042. });
  1043. expect(target3).to.be.eql({
  1044. [DEF_PK]: target3[DEF_PK],
  1045. parentId: -1,
  1046. parentType: 'source',
  1047. });
  1048. const R = S.get(HasManyResolver);
  1049. await R.includePolymorphicTo(
  1050. [source],
  1051. 'source',
  1052. 'target',
  1053. 'children',
  1054. 'parentId',
  1055. 'parentType',
  1056. );
  1057. expect(source).to.be.eql({
  1058. [DEF_PK]: source[DEF_PK],
  1059. children: [
  1060. {
  1061. id: target1[DEF_PK],
  1062. parentId: source[DEF_PK],
  1063. parentType: target1.parentType,
  1064. },
  1065. {
  1066. id: target2[DEF_PK],
  1067. parentId: source[DEF_PK],
  1068. parentType: target2.parentType,
  1069. },
  1070. ],
  1071. });
  1072. });
  1073. it('includes if the source model has a custom primary key', async function () {
  1074. const S = new Schema();
  1075. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  1076. S.defineModel({
  1077. name: 'source',
  1078. datasource: 'datasource',
  1079. properties: {
  1080. myId: {
  1081. type: DataType.NUMBER,
  1082. primaryKey: true,
  1083. },
  1084. },
  1085. });
  1086. S.defineModel({name: 'target', datasource: 'datasource'});
  1087. const sourceRep = S.getRepository('source');
  1088. const targetRep = S.getRepository('target');
  1089. const source = await sourceRep.create({});
  1090. expect(source).to.be.eql({myId: source.myId});
  1091. const target1 = await targetRep.create({
  1092. parentId: source.myId,
  1093. parentType: 'source',
  1094. });
  1095. expect(target1).to.be.eql({
  1096. [DEF_PK]: target1[DEF_PK],
  1097. parentId: source.myId,
  1098. parentType: 'source',
  1099. });
  1100. const target2 = await targetRep.create({
  1101. parentId: source.myId,
  1102. parentType: 'source',
  1103. });
  1104. expect(target2).to.be.eql({
  1105. [DEF_PK]: target2[DEF_PK],
  1106. parentId: source.myId,
  1107. parentType: 'source',
  1108. });
  1109. const target3 = await targetRep.create({
  1110. parentId: -1,
  1111. parentType: 'source',
  1112. });
  1113. expect(target3).to.be.eql({
  1114. [DEF_PK]: target3[DEF_PK],
  1115. parentId: -1,
  1116. parentType: 'source',
  1117. });
  1118. const R = S.get(HasManyResolver);
  1119. await R.includePolymorphicTo(
  1120. [source],
  1121. 'source',
  1122. 'target',
  1123. 'children',
  1124. 'parentId',
  1125. 'parentType',
  1126. );
  1127. expect(source).to.be.eql({
  1128. myId: source.myId,
  1129. children: [
  1130. {
  1131. [DEF_PK]: target1[DEF_PK],
  1132. parentId: source.myId,
  1133. parentType: target1.parentType,
  1134. },
  1135. {
  1136. [DEF_PK]: target2[DEF_PK],
  1137. parentId: source.myId,
  1138. parentType: target2.parentType,
  1139. },
  1140. ],
  1141. });
  1142. });
  1143. it('includes if the target model has a custom primary key', async function () {
  1144. const S = new Schema();
  1145. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  1146. S.defineModel({name: 'source', datasource: 'datasource'});
  1147. S.defineModel({
  1148. name: 'target',
  1149. datasource: 'datasource',
  1150. properties: {
  1151. myId: {
  1152. type: DataType.NUMBER,
  1153. primaryKey: true,
  1154. },
  1155. },
  1156. });
  1157. const sourceRep = S.getRepository('source');
  1158. const targetRep = S.getRepository('target');
  1159. const source = await sourceRep.create({});
  1160. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  1161. const target1 = await targetRep.create({
  1162. parentId: source[DEF_PK],
  1163. parentType: 'source',
  1164. });
  1165. expect(target1).to.be.eql({
  1166. myId: target1.myId,
  1167. parentId: source[DEF_PK],
  1168. parentType: 'source',
  1169. });
  1170. const target2 = await targetRep.create({
  1171. parentId: source[DEF_PK],
  1172. parentType: 'source',
  1173. });
  1174. expect(target2).to.be.eql({
  1175. myId: target2.myId,
  1176. parentId: source[DEF_PK],
  1177. parentType: 'source',
  1178. });
  1179. const target3 = await targetRep.create({
  1180. parentId: -1,
  1181. parentType: 'source',
  1182. });
  1183. expect(target3).to.be.eql({
  1184. myId: target3.myId,
  1185. parentId: -1,
  1186. parentType: 'source',
  1187. });
  1188. const R = S.get(HasManyResolver);
  1189. await R.includePolymorphicTo(
  1190. [source],
  1191. 'source',
  1192. 'target',
  1193. 'children',
  1194. 'parentId',
  1195. 'parentType',
  1196. );
  1197. expect(source).to.be.eql({
  1198. [DEF_PK]: source[DEF_PK],
  1199. children: [
  1200. {
  1201. myId: target1.myId,
  1202. parentId: source[DEF_PK],
  1203. parentType: target1.parentType,
  1204. },
  1205. {
  1206. myId: target2.myId,
  1207. parentId: source[DEF_PK],
  1208. parentType: target2.parentType,
  1209. },
  1210. ],
  1211. });
  1212. });
  1213. it('uses a where clause of the given scope to filter the relation target', async function () {
  1214. const S = new Schema();
  1215. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  1216. S.defineModel({name: 'source', datasource: 'datasource'});
  1217. S.defineModel({name: 'target', datasource: 'datasource'});
  1218. const sourceRep = S.getRepository('source');
  1219. const targetRep = S.getRepository('target');
  1220. const source = await sourceRep.create({});
  1221. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  1222. const target1 = await targetRep.create({
  1223. featured: false,
  1224. parentId: source[DEF_PK],
  1225. parentType: 'source',
  1226. });
  1227. expect(target1).to.be.eql({
  1228. [DEF_PK]: target1[DEF_PK],
  1229. featured: false,
  1230. parentId: source[DEF_PK],
  1231. parentType: 'source',
  1232. });
  1233. const target2 = await targetRep.create({
  1234. featured: true,
  1235. parentId: source[DEF_PK],
  1236. parentType: 'source',
  1237. });
  1238. expect(target2).to.be.eql({
  1239. [DEF_PK]: target2[DEF_PK],
  1240. featured: true,
  1241. parentId: source[DEF_PK],
  1242. parentType: 'source',
  1243. });
  1244. const target3 = await targetRep.create({
  1245. featured: true,
  1246. parentId: source[DEF_PK],
  1247. parentType: 'source',
  1248. });
  1249. expect(target3).to.be.eql({
  1250. [DEF_PK]: target3[DEF_PK],
  1251. featured: true,
  1252. parentId: source[DEF_PK],
  1253. parentType: 'source',
  1254. });
  1255. const R = S.get(HasManyResolver);
  1256. await R.includePolymorphicTo(
  1257. [source],
  1258. 'source',
  1259. 'target',
  1260. 'children',
  1261. 'parentId',
  1262. 'parentType',
  1263. {where: {featured: false}},
  1264. );
  1265. expect(source).to.be.eql({
  1266. [DEF_PK]: source[DEF_PK],
  1267. children: [
  1268. {
  1269. [DEF_PK]: target1[DEF_PK],
  1270. featured: false,
  1271. parentId: source[DEF_PK],
  1272. parentType: target1.parentType,
  1273. },
  1274. ],
  1275. });
  1276. await R.includePolymorphicTo(
  1277. [source],
  1278. 'source',
  1279. 'target',
  1280. 'children',
  1281. 'parentId',
  1282. 'parentType',
  1283. {where: {featured: true}},
  1284. );
  1285. expect(source).to.be.eql({
  1286. [DEF_PK]: source[DEF_PK],
  1287. children: [
  1288. {
  1289. [DEF_PK]: target2[DEF_PK],
  1290. featured: true,
  1291. parentId: source[DEF_PK],
  1292. parentType: target2.parentType,
  1293. },
  1294. {
  1295. [DEF_PK]: target3[DEF_PK],
  1296. featured: true,
  1297. parentId: source[DEF_PK],
  1298. parentType: target3.parentType,
  1299. },
  1300. ],
  1301. });
  1302. });
  1303. it('uses a fields clause of the given scope to filter the relation target', async function () {
  1304. const S = new Schema();
  1305. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  1306. S.defineModel({name: 'source', datasource: 'datasource'});
  1307. S.defineModel({name: 'target', datasource: 'datasource'});
  1308. const sourceRep = S.getRepository('source');
  1309. const targetRep = S.getRepository('target');
  1310. const source = await sourceRep.create({});
  1311. expect(source).to.be.eql({
  1312. [DEF_PK]: source[DEF_PK],
  1313. });
  1314. const target1 = await targetRep.create({
  1315. foo: 'fooVal1',
  1316. bar: 'barVal1',
  1317. parentId: source[DEF_PK],
  1318. parentType: 'source',
  1319. });
  1320. expect(target1).to.be.eql({
  1321. [DEF_PK]: target1[DEF_PK],
  1322. foo: 'fooVal1',
  1323. bar: 'barVal1',
  1324. parentId: source[DEF_PK],
  1325. parentType: 'source',
  1326. });
  1327. const target2 = await targetRep.create({
  1328. foo: 'fooVal2',
  1329. bar: 'barVal2',
  1330. parentId: source[DEF_PK],
  1331. parentType: 'source',
  1332. });
  1333. expect(target2).to.be.eql({
  1334. [DEF_PK]: target2[DEF_PK],
  1335. foo: 'fooVal2',
  1336. bar: 'barVal2',
  1337. parentId: source[DEF_PK],
  1338. parentType: 'source',
  1339. });
  1340. const target3 = await targetRep.create({
  1341. foo: 'fooVal3',
  1342. bar: 'barVal3',
  1343. parentId: -1,
  1344. parentType: 'source',
  1345. });
  1346. expect(target3).to.be.eql({
  1347. [DEF_PK]: target3[DEF_PK],
  1348. foo: 'fooVal3',
  1349. bar: 'barVal3',
  1350. parentId: -1,
  1351. parentType: 'source',
  1352. });
  1353. const R = S.get(HasManyResolver);
  1354. await R.includePolymorphicTo(
  1355. [source],
  1356. 'source',
  1357. 'target',
  1358. 'children',
  1359. 'parentId',
  1360. 'parentType',
  1361. {fields: [DEF_PK, 'bar']},
  1362. );
  1363. expect(source).to.be.eql({
  1364. [DEF_PK]: source[DEF_PK],
  1365. children: [
  1366. {
  1367. [DEF_PK]: target1[DEF_PK],
  1368. bar: target1.bar,
  1369. },
  1370. {
  1371. [DEF_PK]: target2[DEF_PK],
  1372. bar: target2.bar,
  1373. },
  1374. ],
  1375. });
  1376. });
  1377. it('uses an include clause of the given scope to resolve target relations', async function () {
  1378. const S = new Schema();
  1379. S.defineDatasource({
  1380. name: 'datasource',
  1381. adapter: 'memory',
  1382. });
  1383. S.defineModel({
  1384. name: 'modelA',
  1385. datasource: 'datasource',
  1386. properties: {
  1387. id: {
  1388. type: DataType.NUMBER,
  1389. primaryKey: true,
  1390. },
  1391. source: {
  1392. type: DataType.STRING,
  1393. default: 'modelA',
  1394. },
  1395. },
  1396. relations: {
  1397. children: {
  1398. type: RelationType.HAS_MANY,
  1399. model: 'modelB',
  1400. polymorphic: true,
  1401. foreignKey: 'parentId',
  1402. discriminator: 'parentType',
  1403. },
  1404. },
  1405. });
  1406. S.defineModel({
  1407. name: 'modelB',
  1408. datasource: 'datasource',
  1409. properties: {
  1410. id: {
  1411. type: DataType.NUMBER,
  1412. primaryKey: true,
  1413. },
  1414. source: {
  1415. type: DataType.STRING,
  1416. default: 'modelB',
  1417. },
  1418. },
  1419. relations: {
  1420. children: {
  1421. type: RelationType.HAS_MANY,
  1422. model: 'modelC',
  1423. polymorphic: true,
  1424. foreignKey: 'parentId',
  1425. discriminator: 'parentType',
  1426. },
  1427. },
  1428. });
  1429. S.defineModel({
  1430. name: 'modelC',
  1431. datasource: 'datasource',
  1432. properties: {
  1433. id: {
  1434. type: DataType.NUMBER,
  1435. primaryKey: true,
  1436. },
  1437. source: {
  1438. type: DataType.STRING,
  1439. default: 'modelC',
  1440. },
  1441. },
  1442. });
  1443. const aRep = S.getRepository('modelA');
  1444. const bRep = S.getRepository('modelB');
  1445. const cRep = S.getRepository('modelC');
  1446. const a = await aRep.create({});
  1447. const b1 = await bRep.create({parentId: a.id, parentType: 'modelA'});
  1448. const b2 = await bRep.create({parentId: a.id, parentType: 'modelA'});
  1449. const c1 = await cRep.create({parentId: b1.id, parentType: 'modelB'});
  1450. const c2 = await cRep.create({parentId: b1.id, parentType: 'modelB'});
  1451. const c3 = await cRep.create({parentId: b2.id, parentType: 'modelB'});
  1452. const c4 = await cRep.create({parentId: b2.id, parentType: 'modelB'});
  1453. expect(a).to.be.eql({
  1454. id: a.id,
  1455. source: 'modelA',
  1456. });
  1457. expect(b1).to.be.eql({
  1458. id: b1.id,
  1459. source: 'modelB',
  1460. parentId: a.id,
  1461. parentType: 'modelA',
  1462. });
  1463. expect(b2).to.be.eql({
  1464. id: b2.id,
  1465. source: 'modelB',
  1466. parentId: a.id,
  1467. parentType: 'modelA',
  1468. });
  1469. expect(c1).to.be.eql({
  1470. id: c1.id,
  1471. source: 'modelC',
  1472. parentId: b1.id,
  1473. parentType: 'modelB',
  1474. });
  1475. expect(c2).to.be.eql({
  1476. id: c2.id,
  1477. source: 'modelC',
  1478. parentId: b1.id,
  1479. parentType: 'modelB',
  1480. });
  1481. expect(c3).to.be.eql({
  1482. id: c3.id,
  1483. source: 'modelC',
  1484. parentId: b2.id,
  1485. parentType: 'modelB',
  1486. });
  1487. expect(c4).to.be.eql({
  1488. id: c4.id,
  1489. source: 'modelC',
  1490. parentId: b2.id,
  1491. parentType: 'modelB',
  1492. });
  1493. const R = S.get(HasManyResolver);
  1494. await R.includePolymorphicTo(
  1495. [a],
  1496. 'modelA',
  1497. 'modelB',
  1498. 'children',
  1499. 'parentId',
  1500. 'parentType',
  1501. {include: 'children'},
  1502. );
  1503. expect(a).to.be.eql({
  1504. id: a.id,
  1505. source: 'modelA',
  1506. children: [
  1507. {
  1508. id: b1.id,
  1509. source: 'modelB',
  1510. parentId: a.id,
  1511. parentType: 'modelA',
  1512. children: [
  1513. {
  1514. id: c1.id,
  1515. source: 'modelC',
  1516. parentId: b1.id,
  1517. parentType: 'modelB',
  1518. },
  1519. {
  1520. id: c2.id,
  1521. source: 'modelC',
  1522. parentId: b1.id,
  1523. parentType: 'modelB',
  1524. },
  1525. ],
  1526. },
  1527. {
  1528. id: b2.id,
  1529. source: 'modelB',
  1530. parentId: a.id,
  1531. parentType: 'modelA',
  1532. children: [
  1533. {
  1534. id: c3.id,
  1535. source: 'modelC',
  1536. parentId: b2.id,
  1537. parentType: 'modelB',
  1538. },
  1539. {
  1540. id: c4.id,
  1541. source: 'modelC',
  1542. parentId: b2.id,
  1543. parentType: 'modelB',
  1544. },
  1545. ],
  1546. },
  1547. ],
  1548. });
  1549. });
  1550. it('does not break the "and" operator of the given "where" clause', async function () {
  1551. const S = new Schema();
  1552. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  1553. S.defineModel({name: 'source', datasource: 'datasource'});
  1554. S.defineModel({name: 'target', datasource: 'datasource'});
  1555. const sourceRep = S.getRepository('source');
  1556. const targetRep = S.getRepository('target');
  1557. const source = await sourceRep.create({});
  1558. expect(source).to.be.eql({
  1559. [DEF_PK]: source[DEF_PK],
  1560. });
  1561. const target1 = await targetRep.create({
  1562. featured: false,
  1563. parentId: source[DEF_PK],
  1564. parentType: 'source',
  1565. });
  1566. expect(target1).to.be.eql({
  1567. [DEF_PK]: target1[DEF_PK],
  1568. featured: false,
  1569. parentId: source[DEF_PK],
  1570. parentType: 'source',
  1571. });
  1572. const target2 = await targetRep.create({
  1573. featured: true,
  1574. parentId: source[DEF_PK],
  1575. parentType: 'source',
  1576. });
  1577. expect(target2).to.be.eql({
  1578. [DEF_PK]: target2[DEF_PK],
  1579. featured: true,
  1580. parentId: source[DEF_PK],
  1581. parentType: 'source',
  1582. });
  1583. const target3 = await targetRep.create({
  1584. featured: true,
  1585. parentId: source[DEF_PK],
  1586. parentType: 'source',
  1587. });
  1588. expect(target3).to.be.eql({
  1589. [DEF_PK]: target3[DEF_PK],
  1590. featured: true,
  1591. parentId: source[DEF_PK],
  1592. parentType: 'source',
  1593. });
  1594. const R = S.get(HasManyResolver);
  1595. await R.includePolymorphicTo(
  1596. [source],
  1597. 'source',
  1598. 'target',
  1599. 'children',
  1600. 'parentId',
  1601. 'parentType',
  1602. {where: {and: [{featured: false}]}},
  1603. );
  1604. expect(source).to.be.eql({
  1605. [DEF_PK]: source[DEF_PK],
  1606. children: [
  1607. {
  1608. [DEF_PK]: target1[DEF_PK],
  1609. featured: false,
  1610. parentId: source[DEF_PK],
  1611. parentType: target1.parentType,
  1612. },
  1613. ],
  1614. });
  1615. delete source.children;
  1616. await R.includePolymorphicTo(
  1617. [source],
  1618. 'source',
  1619. 'target',
  1620. 'children',
  1621. 'parentId',
  1622. 'parentType',
  1623. {where: {and: [{featured: true}]}},
  1624. );
  1625. expect(source).to.be.eql({
  1626. [DEF_PK]: source[DEF_PK],
  1627. children: [
  1628. {
  1629. [DEF_PK]: target2[DEF_PK],
  1630. featured: true,
  1631. parentId: source[DEF_PK],
  1632. parentType: target2.parentType,
  1633. },
  1634. {
  1635. [DEF_PK]: target3[DEF_PK],
  1636. featured: true,
  1637. parentId: source[DEF_PK],
  1638. parentType: target3.parentType,
  1639. },
  1640. ],
  1641. });
  1642. });
  1643. });
  1644. describe('includePolymorphicByRelationName', function () {
  1645. it('requires the "entities" parameter to be an array', async function () {
  1646. const S = new Schema();
  1647. const R = S.get(HasManyResolver);
  1648. const error = v =>
  1649. format(
  1650. 'The parameter "entities" of HasManyResolver.includePolymorphicByRelationName requires ' +
  1651. 'an Array of Object, but %s given.',
  1652. v,
  1653. );
  1654. const throwable = v =>
  1655. R.includePolymorphicByRelationName(
  1656. v,
  1657. 'sourceName',
  1658. 'targetName',
  1659. 'relationName',
  1660. 'targetRelationName',
  1661. );
  1662. await expect(throwable('')).to.be.rejectedWith(error('""'));
  1663. await expect(throwable('str')).to.be.rejectedWith(error('"str"'));
  1664. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  1665. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  1666. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  1667. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  1668. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  1669. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  1670. });
  1671. it('requires elements of the "entities" parameter to be an Object', async function () {
  1672. const S = new Schema();
  1673. S.defineModel({name: 'source'});
  1674. S.defineModel({
  1675. name: 'target',
  1676. relations: {
  1677. parent: {
  1678. type: RelationType.BELONGS_TO,
  1679. polymorphic: true,
  1680. },
  1681. },
  1682. });
  1683. const R = S.get(HasManyResolver);
  1684. const error = v =>
  1685. format(
  1686. 'The parameter "entities" of HasManyResolver.includePolymorphicTo requires ' +
  1687. 'an Array of Object, but %s given.',
  1688. v,
  1689. );
  1690. const throwable = v =>
  1691. R.includePolymorphicByRelationName(
  1692. [v],
  1693. 'source',
  1694. 'target',
  1695. 'children',
  1696. 'parent',
  1697. );
  1698. await expect(throwable('')).to.be.rejectedWith(error('""'));
  1699. await expect(throwable('str')).to.be.rejectedWith(error('"str"'));
  1700. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  1701. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  1702. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  1703. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  1704. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  1705. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  1706. });
  1707. it('requires the "sourceName" parameter to be a non-empty string', async function () {
  1708. const S = new Schema();
  1709. const R = S.get(HasManyResolver);
  1710. const error = v =>
  1711. format(
  1712. 'The parameter "sourceName" of HasManyResolver.includePolymorphicByRelationName requires ' +
  1713. 'a non-empty String, but %s given.',
  1714. v,
  1715. );
  1716. const throwable = v =>
  1717. R.includePolymorphicByRelationName(
  1718. [],
  1719. v,
  1720. 'targetName',
  1721. 'relationName',
  1722. 'targetRelationName',
  1723. );
  1724. await expect(throwable('')).to.be.rejectedWith(error('""'));
  1725. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  1726. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  1727. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  1728. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  1729. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  1730. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  1731. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  1732. });
  1733. it('requires the "targetName" parameter to be a non-empty string', async function () {
  1734. const S = new Schema();
  1735. const R = S.get(HasManyResolver);
  1736. const error = v =>
  1737. format(
  1738. 'The parameter "targetName" of HasManyResolver.includePolymorphicByRelationName requires ' +
  1739. 'a non-empty String, but %s given.',
  1740. v,
  1741. );
  1742. const throwable = v =>
  1743. R.includePolymorphicByRelationName(
  1744. [],
  1745. 'sourceName',
  1746. v,
  1747. 'relationName',
  1748. 'targetRelationName',
  1749. );
  1750. await expect(throwable('')).to.be.rejectedWith(error('""'));
  1751. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  1752. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  1753. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  1754. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  1755. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  1756. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  1757. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  1758. });
  1759. it('requires the "relationName" parameter to be a non-empty string', async function () {
  1760. const S = new Schema();
  1761. const R = S.get(HasManyResolver);
  1762. const error = v =>
  1763. format(
  1764. 'The parameter "relationName" of HasManyResolver.includePolymorphicByRelationName requires ' +
  1765. 'a non-empty String, but %s given.',
  1766. v,
  1767. );
  1768. const throwable = v =>
  1769. R.includePolymorphicByRelationName(
  1770. [],
  1771. 'sourceName',
  1772. 'targetName',
  1773. v,
  1774. 'targetRelationName',
  1775. );
  1776. await expect(throwable('')).to.be.rejectedWith(error('""'));
  1777. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  1778. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  1779. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  1780. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  1781. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  1782. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  1783. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  1784. });
  1785. it('requires the "targetRelationName" parameter to be a non-empty string', async function () {
  1786. const S = new Schema();
  1787. const R = S.get(HasManyResolver);
  1788. const error = v =>
  1789. format(
  1790. 'The parameter "targetRelationName" of HasManyResolver.includePolymorphicByRelationName requires ' +
  1791. 'a non-empty String, but %s given.',
  1792. v,
  1793. );
  1794. const throwable = v =>
  1795. R.includePolymorphicByRelationName(
  1796. [],
  1797. 'sourceName',
  1798. 'targetName',
  1799. 'relationName',
  1800. v,
  1801. );
  1802. await expect(throwable('')).to.be.rejectedWith(error('""'));
  1803. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  1804. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  1805. await expect(throwable(false)).to.be.rejectedWith(error('false'));
  1806. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  1807. await expect(throwable({})).to.be.rejectedWith(error('Object'));
  1808. await expect(throwable(undefined)).to.be.rejectedWith(error('undefined'));
  1809. await expect(throwable(null)).to.be.rejectedWith(error('null'));
  1810. });
  1811. it('requires the provided parameter "scope" to be an object', async function () {
  1812. const S = new Schema();
  1813. const R = S.get(HasManyResolver);
  1814. const error = v =>
  1815. format(
  1816. 'The provided parameter "scope" of HasManyResolver.includePolymorphicByRelationName ' +
  1817. 'should be an Object, but %s given.',
  1818. v,
  1819. );
  1820. const throwable = v =>
  1821. R.includePolymorphicByRelationName(
  1822. [],
  1823. 'sourceName',
  1824. 'targetName',
  1825. 'relationName',
  1826. 'targetRelationName',
  1827. v,
  1828. );
  1829. await expect(throwable('str')).to.be.rejectedWith(error('"str"'));
  1830. await expect(throwable(10)).to.be.rejectedWith(error('10'));
  1831. await expect(throwable(true)).to.be.rejectedWith(error('true'));
  1832. await expect(throwable([])).to.be.rejectedWith(error('Array'));
  1833. });
  1834. it('throws an error if the given target model is not found', async function () {
  1835. const S = new Schema();
  1836. S.defineModel({name: 'source'});
  1837. const R = S.get(HasManyResolver);
  1838. const entity = {[DEF_PK]: 1};
  1839. const promise = R.includePolymorphicByRelationName(
  1840. [entity],
  1841. 'source',
  1842. 'target',
  1843. 'children',
  1844. 'parent',
  1845. );
  1846. await expect(promise).to.be.rejectedWith(
  1847. 'The model "target" is not defined',
  1848. );
  1849. });
  1850. it('throws an error if the given target model does not have the given relation name', async function () {
  1851. const S = new Schema();
  1852. S.defineModel({name: 'source'});
  1853. S.defineModel({name: 'target'});
  1854. const R = S.get(HasManyResolver);
  1855. const entity = {[DEF_PK]: 1};
  1856. const promise = R.includePolymorphicByRelationName(
  1857. [entity],
  1858. 'source',
  1859. 'target',
  1860. 'children',
  1861. 'parent',
  1862. );
  1863. await expect(promise).to.be.rejectedWith(
  1864. 'The model "target" does not have relation name "parent".',
  1865. );
  1866. });
  1867. it('throws an error if the target relation is not "belongsTo"', async function () {
  1868. const S = new Schema();
  1869. S.defineModel({name: 'source'});
  1870. S.defineModel({
  1871. name: 'target',
  1872. relations: {
  1873. parent: {
  1874. type: RelationType.REFERENCES_MANY,
  1875. model: 'source',
  1876. },
  1877. },
  1878. });
  1879. const R = S.get(HasManyResolver);
  1880. const entity = {[DEF_PK]: 1};
  1881. const promise = R.includePolymorphicByRelationName(
  1882. [entity],
  1883. 'source',
  1884. 'target',
  1885. 'children',
  1886. 'parent',
  1887. );
  1888. await expect(promise).to.be.rejectedWith(
  1889. 'The relation "children" of the model "source" is a polymorphic "hasMany" relation, ' +
  1890. 'so it requires the target relation "parent" to be a polymorphic "belongsTo", ' +
  1891. 'but "referencesMany" type given.',
  1892. );
  1893. });
  1894. it('throws an error if the target relation is not polymorphic', async function () {
  1895. const S = new Schema();
  1896. S.defineModel({name: 'source'});
  1897. S.defineModel({
  1898. name: 'target',
  1899. relations: {
  1900. parent: {
  1901. type: RelationType.BELONGS_TO,
  1902. model: 'source',
  1903. },
  1904. },
  1905. });
  1906. const R = S.get(HasManyResolver);
  1907. const entity = {[DEF_PK]: 1};
  1908. const promise = R.includePolymorphicByRelationName(
  1909. [entity],
  1910. 'source',
  1911. 'target',
  1912. 'children',
  1913. 'parent',
  1914. );
  1915. await expect(promise).to.be.rejectedWith(
  1916. 'The relation "children" of the model "source" is a polymorphic ' +
  1917. '"hasMany" relation, so it requires the target relation "parent" ' +
  1918. 'to be a polymorphic too.',
  1919. );
  1920. });
  1921. it('throws an error if the given target model does not have a datasource', async function () {
  1922. const S = new Schema();
  1923. S.defineModel({name: 'source'});
  1924. S.defineModel({
  1925. name: 'target',
  1926. relations: {
  1927. parent: {
  1928. type: RelationType.BELONGS_TO,
  1929. polymorphic: true,
  1930. },
  1931. },
  1932. });
  1933. const R = S.get(HasManyResolver);
  1934. const entity = {[DEF_PK]: 1};
  1935. const promise = R.includePolymorphicByRelationName(
  1936. [entity],
  1937. 'source',
  1938. 'target',
  1939. 'children',
  1940. 'parent',
  1941. );
  1942. await expect(promise).to.be.rejectedWith(
  1943. 'The model "target" does not have a specified datasource.',
  1944. );
  1945. });
  1946. it('does not throw an error if a relation target is not found', async function () {
  1947. const S = new Schema();
  1948. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  1949. S.defineModel({name: 'source', datasource: 'datasource'});
  1950. S.defineModel({
  1951. name: 'target',
  1952. datasource: 'datasource',
  1953. relations: {
  1954. parent: {
  1955. type: RelationType.BELONGS_TO,
  1956. polymorphic: true,
  1957. },
  1958. },
  1959. });
  1960. const sourceRel = S.getRepository('source');
  1961. const source = await sourceRel.create({});
  1962. expect(source).to.be.eql({
  1963. [DEF_PK]: source[DEF_PK],
  1964. });
  1965. const R = S.get(HasManyResolver);
  1966. await R.includePolymorphicByRelationName(
  1967. [source],
  1968. 'source',
  1969. 'target',
  1970. 'children',
  1971. 'parent',
  1972. );
  1973. expect(source).to.be.eql({
  1974. [DEF_PK]: source[DEF_PK],
  1975. children: [],
  1976. });
  1977. });
  1978. it('does not include an entity with a not matched discriminator value', async function () {
  1979. const S = new Schema();
  1980. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  1981. S.defineModel({name: 'source', datasource: 'datasource'});
  1982. S.defineModel({
  1983. name: 'target',
  1984. datasource: 'datasource',
  1985. relations: {
  1986. parent: {
  1987. type: RelationType.BELONGS_TO,
  1988. polymorphic: true,
  1989. },
  1990. },
  1991. });
  1992. const sourceRel = S.getRepository('source');
  1993. const targetRel = S.getRepository('target');
  1994. const source = await sourceRel.create({});
  1995. expect(source).to.be.eql({
  1996. [DEF_PK]: source[DEF_PK],
  1997. });
  1998. const target = await targetRel.create({
  1999. parentId: source[DEF_PK],
  2000. parentType: 'unknown',
  2001. });
  2002. expect(target).to.be.eql({
  2003. [DEF_PK]: target[DEF_PK],
  2004. parentId: source[DEF_PK],
  2005. parentType: 'unknown',
  2006. });
  2007. const R = S.get(HasManyResolver);
  2008. await R.includePolymorphicByRelationName(
  2009. [source],
  2010. 'source',
  2011. 'target',
  2012. 'children',
  2013. 'parent',
  2014. );
  2015. expect(source).to.be.eql({
  2016. [DEF_PK]: source[DEF_PK],
  2017. children: [],
  2018. });
  2019. });
  2020. it('includes if a primary key is not defined in the source model', async function () {
  2021. const S = new Schema();
  2022. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  2023. S.defineModel({name: 'source', datasource: 'datasource'});
  2024. S.defineModel({
  2025. name: 'target',
  2026. datasource: 'datasource',
  2027. relations: {
  2028. parent: {
  2029. type: RelationType.BELONGS_TO,
  2030. polymorphic: true,
  2031. },
  2032. },
  2033. });
  2034. const sourceRep = S.getRepository('source');
  2035. const targetRep = S.getRepository('target');
  2036. const source = await sourceRep.create({});
  2037. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  2038. const target1 = await targetRep.create({
  2039. parentId: source[DEF_PK],
  2040. parentType: 'source',
  2041. });
  2042. expect(target1).to.be.eql({
  2043. [DEF_PK]: target1[DEF_PK],
  2044. parentId: source[DEF_PK],
  2045. parentType: 'source',
  2046. });
  2047. const target2 = await targetRep.create({
  2048. parentId: source[DEF_PK],
  2049. parentType: 'source',
  2050. });
  2051. expect(target2).to.be.eql({
  2052. [DEF_PK]: target2[DEF_PK],
  2053. parentId: source[DEF_PK],
  2054. parentType: 'source',
  2055. });
  2056. const target3 = await targetRep.create({
  2057. parentId: -1,
  2058. parentType: 'source',
  2059. });
  2060. expect(target3).to.be.eql({
  2061. [DEF_PK]: target3[DEF_PK],
  2062. parentId: -1,
  2063. parentType: 'source',
  2064. });
  2065. const R = S.get(HasManyResolver);
  2066. await R.includePolymorphicByRelationName(
  2067. [source],
  2068. 'source',
  2069. 'target',
  2070. 'children',
  2071. 'parent',
  2072. );
  2073. expect(source).to.be.eql({
  2074. [DEF_PK]: source[DEF_PK],
  2075. children: [
  2076. {
  2077. id: target1[DEF_PK],
  2078. parentId: source[DEF_PK],
  2079. parentType: target1.parentType,
  2080. },
  2081. {
  2082. id: target2[DEF_PK],
  2083. parentId: source[DEF_PK],
  2084. parentType: target2.parentType,
  2085. },
  2086. ],
  2087. });
  2088. });
  2089. it('includes if the source model has a custom primary key', async function () {
  2090. const S = new Schema();
  2091. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  2092. S.defineModel({
  2093. name: 'source',
  2094. datasource: 'datasource',
  2095. properties: {
  2096. myId: {
  2097. type: DataType.NUMBER,
  2098. primaryKey: true,
  2099. },
  2100. },
  2101. });
  2102. S.defineModel({
  2103. name: 'target',
  2104. datasource: 'datasource',
  2105. relations: {
  2106. parent: {
  2107. type: RelationType.BELONGS_TO,
  2108. polymorphic: true,
  2109. },
  2110. },
  2111. });
  2112. const sourceRep = S.getRepository('source');
  2113. const targetRep = S.getRepository('target');
  2114. const source = await sourceRep.create({});
  2115. expect(source).to.be.eql({myId: source.myId});
  2116. const target1 = await targetRep.create({
  2117. parentId: source.myId,
  2118. parentType: 'source',
  2119. });
  2120. expect(target1).to.be.eql({
  2121. [DEF_PK]: target1[DEF_PK],
  2122. parentId: source.myId,
  2123. parentType: 'source',
  2124. });
  2125. const target2 = await targetRep.create({
  2126. parentId: source.myId,
  2127. parentType: 'source',
  2128. });
  2129. expect(target2).to.be.eql({
  2130. [DEF_PK]: target2[DEF_PK],
  2131. parentId: source.myId,
  2132. parentType: 'source',
  2133. });
  2134. const target3 = await targetRep.create({
  2135. parentId: -1,
  2136. parentType: 'source',
  2137. });
  2138. expect(target3).to.be.eql({
  2139. [DEF_PK]: target3[DEF_PK],
  2140. parentId: -1,
  2141. parentType: 'source',
  2142. });
  2143. const R = S.get(HasManyResolver);
  2144. await R.includePolymorphicByRelationName(
  2145. [source],
  2146. 'source',
  2147. 'target',
  2148. 'children',
  2149. 'parent',
  2150. );
  2151. expect(source).to.be.eql({
  2152. myId: source.myId,
  2153. children: [
  2154. {
  2155. [DEF_PK]: target1[DEF_PK],
  2156. parentId: source.myId,
  2157. parentType: target1.parentType,
  2158. },
  2159. {
  2160. [DEF_PK]: target2[DEF_PK],
  2161. parentId: source.myId,
  2162. parentType: target2.parentType,
  2163. },
  2164. ],
  2165. });
  2166. });
  2167. it('includes if the target model has a custom primary key', async function () {
  2168. const S = new Schema();
  2169. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  2170. S.defineModel({name: 'source', datasource: 'datasource'});
  2171. S.defineModel({
  2172. name: 'target',
  2173. datasource: 'datasource',
  2174. properties: {
  2175. myId: {
  2176. type: DataType.NUMBER,
  2177. primaryKey: true,
  2178. },
  2179. },
  2180. relations: {
  2181. parent: {
  2182. type: RelationType.BELONGS_TO,
  2183. polymorphic: true,
  2184. },
  2185. },
  2186. });
  2187. const sourceRep = S.getRepository('source');
  2188. const targetRep = S.getRepository('target');
  2189. const source = await sourceRep.create({});
  2190. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  2191. const target1 = await targetRep.create({
  2192. parentId: source[DEF_PK],
  2193. parentType: 'source',
  2194. });
  2195. expect(target1).to.be.eql({
  2196. myId: target1.myId,
  2197. parentId: source[DEF_PK],
  2198. parentType: 'source',
  2199. });
  2200. const target2 = await targetRep.create({
  2201. parentId: source[DEF_PK],
  2202. parentType: 'source',
  2203. });
  2204. expect(target2).to.be.eql({
  2205. myId: target2.myId,
  2206. parentId: source[DEF_PK],
  2207. parentType: 'source',
  2208. });
  2209. const target3 = await targetRep.create({
  2210. parentId: -1,
  2211. parentType: 'source',
  2212. });
  2213. expect(target3).to.be.eql({
  2214. myId: target3.myId,
  2215. parentId: -1,
  2216. parentType: 'source',
  2217. });
  2218. const R = S.get(HasManyResolver);
  2219. await R.includePolymorphicByRelationName(
  2220. [source],
  2221. 'source',
  2222. 'target',
  2223. 'children',
  2224. 'parent',
  2225. );
  2226. expect(source).to.be.eql({
  2227. [DEF_PK]: source[DEF_PK],
  2228. children: [
  2229. {
  2230. myId: target1.myId,
  2231. parentId: source[DEF_PK],
  2232. parentType: target1.parentType,
  2233. },
  2234. {
  2235. myId: target2.myId,
  2236. parentId: source[DEF_PK],
  2237. parentType: target2.parentType,
  2238. },
  2239. ],
  2240. });
  2241. });
  2242. it('includes if the target model has a custom "foreignKey"', async function () {
  2243. const S = new Schema();
  2244. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  2245. S.defineModel({name: 'source', datasource: 'datasource'});
  2246. S.defineModel({
  2247. name: 'target',
  2248. datasource: 'datasource',
  2249. properties: {
  2250. myId: {
  2251. type: DataType.NUMBER,
  2252. primaryKey: true,
  2253. },
  2254. },
  2255. relations: {
  2256. parent: {
  2257. type: RelationType.BELONGS_TO,
  2258. polymorphic: true,
  2259. foreignKey: 'relationId',
  2260. },
  2261. },
  2262. });
  2263. const sourceRep = S.getRepository('source');
  2264. const targetRep = S.getRepository('target');
  2265. const source = await sourceRep.create({});
  2266. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  2267. const target1 = await targetRep.create({
  2268. relationId: source[DEF_PK],
  2269. parentType: 'source',
  2270. });
  2271. expect(target1).to.be.eql({
  2272. myId: target1.myId,
  2273. relationId: source[DEF_PK],
  2274. parentType: 'source',
  2275. });
  2276. const target2 = await targetRep.create({
  2277. relationId: source[DEF_PK],
  2278. parentType: 'source',
  2279. });
  2280. expect(target2).to.be.eql({
  2281. myId: target2.myId,
  2282. relationId: source[DEF_PK],
  2283. parentType: 'source',
  2284. });
  2285. const target3 = await targetRep.create({
  2286. relationId: -1,
  2287. parentType: 'source',
  2288. });
  2289. expect(target3).to.be.eql({
  2290. myId: target3.myId,
  2291. relationId: -1,
  2292. parentType: 'source',
  2293. });
  2294. const R = S.get(HasManyResolver);
  2295. await R.includePolymorphicByRelationName(
  2296. [source],
  2297. 'source',
  2298. 'target',
  2299. 'children',
  2300. 'parent',
  2301. );
  2302. expect(source).to.be.eql({
  2303. [DEF_PK]: source[DEF_PK],
  2304. children: [
  2305. {
  2306. myId: target1.myId,
  2307. relationId: source[DEF_PK],
  2308. parentType: target1.parentType,
  2309. },
  2310. {
  2311. myId: target2.myId,
  2312. relationId: source[DEF_PK],
  2313. parentType: target2.parentType,
  2314. },
  2315. ],
  2316. });
  2317. });
  2318. it('includes if the target model has a custom "discriminator"', async function () {
  2319. const S = new Schema();
  2320. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  2321. S.defineModel({name: 'source', datasource: 'datasource'});
  2322. S.defineModel({
  2323. name: 'target',
  2324. datasource: 'datasource',
  2325. properties: {
  2326. myId: {
  2327. type: DataType.NUMBER,
  2328. primaryKey: true,
  2329. },
  2330. },
  2331. relations: {
  2332. parent: {
  2333. type: RelationType.BELONGS_TO,
  2334. polymorphic: true,
  2335. discriminator: 'relationType',
  2336. },
  2337. },
  2338. });
  2339. const sourceRep = S.getRepository('source');
  2340. const targetRep = S.getRepository('target');
  2341. const source = await sourceRep.create({});
  2342. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  2343. const target1 = await targetRep.create({
  2344. parentId: source[DEF_PK],
  2345. relationType: 'source',
  2346. });
  2347. expect(target1).to.be.eql({
  2348. myId: target1.myId,
  2349. parentId: source[DEF_PK],
  2350. relationType: 'source',
  2351. });
  2352. const target2 = await targetRep.create({
  2353. parentId: source[DEF_PK],
  2354. relationType: 'source',
  2355. });
  2356. expect(target2).to.be.eql({
  2357. myId: target2.myId,
  2358. parentId: source[DEF_PK],
  2359. relationType: 'source',
  2360. });
  2361. const target3 = await targetRep.create({
  2362. parentId: -1,
  2363. relationType: 'source',
  2364. });
  2365. expect(target3).to.be.eql({
  2366. myId: target3.myId,
  2367. parentId: -1,
  2368. relationType: 'source',
  2369. });
  2370. const R = S.get(HasManyResolver);
  2371. await R.includePolymorphicByRelationName(
  2372. [source],
  2373. 'source',
  2374. 'target',
  2375. 'children',
  2376. 'parent',
  2377. );
  2378. expect(source).to.be.eql({
  2379. [DEF_PK]: source[DEF_PK],
  2380. children: [
  2381. {
  2382. myId: target1.myId,
  2383. parentId: source[DEF_PK],
  2384. relationType: target1.relationType,
  2385. },
  2386. {
  2387. myId: target2.myId,
  2388. parentId: source[DEF_PK],
  2389. relationType: target2.relationType,
  2390. },
  2391. ],
  2392. });
  2393. });
  2394. it('uses a where clause of the given scope to filter the relation target', async function () {
  2395. const S = new Schema();
  2396. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  2397. S.defineModel({name: 'source', datasource: 'datasource'});
  2398. S.defineModel({
  2399. name: 'target',
  2400. datasource: 'datasource',
  2401. relations: {
  2402. parent: {
  2403. type: RelationType.BELONGS_TO,
  2404. polymorphic: true,
  2405. },
  2406. },
  2407. });
  2408. const sourceRep = S.getRepository('source');
  2409. const targetRep = S.getRepository('target');
  2410. const source = await sourceRep.create({});
  2411. expect(source).to.be.eql({[DEF_PK]: source[DEF_PK]});
  2412. const target1 = await targetRep.create({
  2413. featured: false,
  2414. parentId: source[DEF_PK],
  2415. parentType: 'source',
  2416. });
  2417. expect(target1).to.be.eql({
  2418. [DEF_PK]: target1[DEF_PK],
  2419. featured: false,
  2420. parentId: source[DEF_PK],
  2421. parentType: 'source',
  2422. });
  2423. const target2 = await targetRep.create({
  2424. featured: true,
  2425. parentId: source[DEF_PK],
  2426. parentType: 'source',
  2427. });
  2428. expect(target2).to.be.eql({
  2429. [DEF_PK]: target2[DEF_PK],
  2430. featured: true,
  2431. parentId: source[DEF_PK],
  2432. parentType: 'source',
  2433. });
  2434. const target3 = await targetRep.create({
  2435. featured: true,
  2436. parentId: source[DEF_PK],
  2437. parentType: 'source',
  2438. });
  2439. expect(target3).to.be.eql({
  2440. [DEF_PK]: target3[DEF_PK],
  2441. featured: true,
  2442. parentId: source[DEF_PK],
  2443. parentType: 'source',
  2444. });
  2445. const R = S.get(HasManyResolver);
  2446. await R.includePolymorphicByRelationName(
  2447. [source],
  2448. 'source',
  2449. 'target',
  2450. 'children',
  2451. 'parent',
  2452. {where: {featured: false}},
  2453. );
  2454. expect(source).to.be.eql({
  2455. [DEF_PK]: source[DEF_PK],
  2456. children: [
  2457. {
  2458. [DEF_PK]: target1[DEF_PK],
  2459. featured: false,
  2460. parentId: source[DEF_PK],
  2461. parentType: target1.parentType,
  2462. },
  2463. ],
  2464. });
  2465. await R.includePolymorphicByRelationName(
  2466. [source],
  2467. 'source',
  2468. 'target',
  2469. 'children',
  2470. 'parent',
  2471. {where: {featured: true}},
  2472. );
  2473. expect(source).to.be.eql({
  2474. [DEF_PK]: source[DEF_PK],
  2475. children: [
  2476. {
  2477. [DEF_PK]: target2[DEF_PK],
  2478. featured: true,
  2479. parentId: source[DEF_PK],
  2480. parentType: target2.parentType,
  2481. },
  2482. {
  2483. [DEF_PK]: target3[DEF_PK],
  2484. featured: true,
  2485. parentId: source[DEF_PK],
  2486. parentType: target3.parentType,
  2487. },
  2488. ],
  2489. });
  2490. });
  2491. it('uses a fields clause of the given scope to filter the relation target', async function () {
  2492. const S = new Schema();
  2493. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  2494. S.defineModel({name: 'source', datasource: 'datasource'});
  2495. S.defineModel({
  2496. name: 'target',
  2497. datasource: 'datasource',
  2498. relations: {
  2499. parent: {
  2500. type: RelationType.BELONGS_TO,
  2501. polymorphic: true,
  2502. },
  2503. },
  2504. });
  2505. const sourceRep = S.getRepository('source');
  2506. const targetRep = S.getRepository('target');
  2507. const source = await sourceRep.create({});
  2508. expect(source).to.be.eql({
  2509. [DEF_PK]: source[DEF_PK],
  2510. });
  2511. const target1 = await targetRep.create({
  2512. foo: 'fooVal1',
  2513. bar: 'barVal1',
  2514. parentId: source[DEF_PK],
  2515. parentType: 'source',
  2516. });
  2517. expect(target1).to.be.eql({
  2518. [DEF_PK]: target1[DEF_PK],
  2519. foo: 'fooVal1',
  2520. bar: 'barVal1',
  2521. parentId: source[DEF_PK],
  2522. parentType: 'source',
  2523. });
  2524. const target2 = await targetRep.create({
  2525. foo: 'fooVal2',
  2526. bar: 'barVal2',
  2527. parentId: source[DEF_PK],
  2528. parentType: 'source',
  2529. });
  2530. expect(target2).to.be.eql({
  2531. [DEF_PK]: target2[DEF_PK],
  2532. foo: 'fooVal2',
  2533. bar: 'barVal2',
  2534. parentId: source[DEF_PK],
  2535. parentType: 'source',
  2536. });
  2537. const target3 = await targetRep.create({
  2538. foo: 'fooVal3',
  2539. bar: 'barVal3',
  2540. parentId: -1,
  2541. parentType: 'source',
  2542. });
  2543. expect(target3).to.be.eql({
  2544. [DEF_PK]: target3[DEF_PK],
  2545. foo: 'fooVal3',
  2546. bar: 'barVal3',
  2547. parentId: -1,
  2548. parentType: 'source',
  2549. });
  2550. const R = S.get(HasManyResolver);
  2551. await R.includePolymorphicByRelationName(
  2552. [source],
  2553. 'source',
  2554. 'target',
  2555. 'children',
  2556. 'parent',
  2557. {fields: [DEF_PK, 'bar']},
  2558. );
  2559. expect(source).to.be.eql({
  2560. [DEF_PK]: source[DEF_PK],
  2561. children: [
  2562. {
  2563. [DEF_PK]: target1[DEF_PK],
  2564. bar: target1.bar,
  2565. },
  2566. {
  2567. [DEF_PK]: target2[DEF_PK],
  2568. bar: target2.bar,
  2569. },
  2570. ],
  2571. });
  2572. });
  2573. it('uses an include clause of the given scope to resolve target relations', async function () {
  2574. const S = new Schema();
  2575. S.defineDatasource({
  2576. name: 'datasource',
  2577. adapter: 'memory',
  2578. });
  2579. S.defineModel({
  2580. name: 'modelA',
  2581. datasource: 'datasource',
  2582. properties: {
  2583. id: {
  2584. type: DataType.NUMBER,
  2585. primaryKey: true,
  2586. },
  2587. source: {
  2588. type: DataType.STRING,
  2589. default: 'modelA',
  2590. },
  2591. },
  2592. relations: {
  2593. children: {
  2594. type: RelationType.HAS_MANY,
  2595. model: 'modelB',
  2596. polymorphic: 'parent',
  2597. },
  2598. },
  2599. });
  2600. S.defineModel({
  2601. name: 'modelB',
  2602. datasource: 'datasource',
  2603. properties: {
  2604. id: {
  2605. type: DataType.NUMBER,
  2606. primaryKey: true,
  2607. },
  2608. source: {
  2609. type: DataType.STRING,
  2610. default: 'modelB',
  2611. },
  2612. },
  2613. relations: {
  2614. parent: {
  2615. type: RelationType.BELONGS_TO,
  2616. polymorphic: true,
  2617. },
  2618. children: {
  2619. type: RelationType.HAS_MANY,
  2620. model: 'modelC',
  2621. polymorphic: 'parent',
  2622. },
  2623. },
  2624. });
  2625. S.defineModel({
  2626. name: 'modelC',
  2627. datasource: 'datasource',
  2628. properties: {
  2629. id: {
  2630. type: DataType.NUMBER,
  2631. primaryKey: true,
  2632. },
  2633. source: {
  2634. type: DataType.STRING,
  2635. default: 'modelC',
  2636. },
  2637. },
  2638. relations: {
  2639. parent: {
  2640. type: RelationType.BELONGS_TO,
  2641. polymorphic: true,
  2642. },
  2643. },
  2644. });
  2645. const aRep = S.getRepository('modelA');
  2646. const bRep = S.getRepository('modelB');
  2647. const cRep = S.getRepository('modelC');
  2648. const a = await aRep.create({});
  2649. const b1 = await bRep.create({parentId: a.id, parentType: 'modelA'});
  2650. const b2 = await bRep.create({parentId: a.id, parentType: 'modelA'});
  2651. const c1 = await cRep.create({parentId: b1.id, parentType: 'modelB'});
  2652. const c2 = await cRep.create({parentId: b1.id, parentType: 'modelB'});
  2653. const c3 = await cRep.create({parentId: b2.id, parentType: 'modelB'});
  2654. const c4 = await cRep.create({parentId: b2.id, parentType: 'modelB'});
  2655. expect(a).to.be.eql({
  2656. id: a.id,
  2657. source: 'modelA',
  2658. });
  2659. expect(b1).to.be.eql({
  2660. id: b1.id,
  2661. source: 'modelB',
  2662. parentId: a.id,
  2663. parentType: 'modelA',
  2664. });
  2665. expect(b2).to.be.eql({
  2666. id: b2.id,
  2667. source: 'modelB',
  2668. parentId: a.id,
  2669. parentType: 'modelA',
  2670. });
  2671. expect(c1).to.be.eql({
  2672. id: c1.id,
  2673. source: 'modelC',
  2674. parentId: b1.id,
  2675. parentType: 'modelB',
  2676. });
  2677. expect(c2).to.be.eql({
  2678. id: c2.id,
  2679. source: 'modelC',
  2680. parentId: b1.id,
  2681. parentType: 'modelB',
  2682. });
  2683. expect(c3).to.be.eql({
  2684. id: c3.id,
  2685. source: 'modelC',
  2686. parentId: b2.id,
  2687. parentType: 'modelB',
  2688. });
  2689. expect(c4).to.be.eql({
  2690. id: c4.id,
  2691. source: 'modelC',
  2692. parentId: b2.id,
  2693. parentType: 'modelB',
  2694. });
  2695. const R = S.get(HasManyResolver);
  2696. await R.includePolymorphicByRelationName(
  2697. [a],
  2698. 'modelA',
  2699. 'modelB',
  2700. 'children',
  2701. 'parent',
  2702. {include: 'children'},
  2703. );
  2704. expect(a).to.be.eql({
  2705. id: a.id,
  2706. source: 'modelA',
  2707. children: [
  2708. {
  2709. id: b1.id,
  2710. source: 'modelB',
  2711. parentId: a.id,
  2712. parentType: 'modelA',
  2713. children: [
  2714. {
  2715. id: c1.id,
  2716. source: 'modelC',
  2717. parentId: b1.id,
  2718. parentType: 'modelB',
  2719. },
  2720. {
  2721. id: c2.id,
  2722. source: 'modelC',
  2723. parentId: b1.id,
  2724. parentType: 'modelB',
  2725. },
  2726. ],
  2727. },
  2728. {
  2729. id: b2.id,
  2730. source: 'modelB',
  2731. parentId: a.id,
  2732. parentType: 'modelA',
  2733. children: [
  2734. {
  2735. id: c3.id,
  2736. source: 'modelC',
  2737. parentId: b2.id,
  2738. parentType: 'modelB',
  2739. },
  2740. {
  2741. id: c4.id,
  2742. source: 'modelC',
  2743. parentId: b2.id,
  2744. parentType: 'modelB',
  2745. },
  2746. ],
  2747. },
  2748. ],
  2749. });
  2750. });
  2751. it('does not break the "and" operator of the given "where" clause', async function () {
  2752. const S = new Schema();
  2753. S.defineDatasource({name: 'datasource', adapter: 'memory'});
  2754. S.defineModel({name: 'source', datasource: 'datasource'});
  2755. S.defineModel({
  2756. name: 'target',
  2757. datasource: 'datasource',
  2758. relations: {
  2759. parent: {
  2760. type: RelationType.BELONGS_TO,
  2761. polymorphic: true,
  2762. },
  2763. },
  2764. });
  2765. const sourceRep = S.getRepository('source');
  2766. const targetRep = S.getRepository('target');
  2767. const source = await sourceRep.create({});
  2768. expect(source).to.be.eql({
  2769. [DEF_PK]: source[DEF_PK],
  2770. });
  2771. const target1 = await targetRep.create({
  2772. featured: false,
  2773. parentId: source[DEF_PK],
  2774. parentType: 'source',
  2775. });
  2776. expect(target1).to.be.eql({
  2777. [DEF_PK]: target1[DEF_PK],
  2778. featured: false,
  2779. parentId: source[DEF_PK],
  2780. parentType: 'source',
  2781. });
  2782. const target2 = await targetRep.create({
  2783. featured: true,
  2784. parentId: source[DEF_PK],
  2785. parentType: 'source',
  2786. });
  2787. expect(target2).to.be.eql({
  2788. [DEF_PK]: target2[DEF_PK],
  2789. featured: true,
  2790. parentId: source[DEF_PK],
  2791. parentType: 'source',
  2792. });
  2793. const target3 = await targetRep.create({
  2794. featured: true,
  2795. parentId: source[DEF_PK],
  2796. parentType: 'source',
  2797. });
  2798. expect(target3).to.be.eql({
  2799. [DEF_PK]: target3[DEF_PK],
  2800. featured: true,
  2801. parentId: source[DEF_PK],
  2802. parentType: 'source',
  2803. });
  2804. const R = S.get(HasManyResolver);
  2805. await R.includePolymorphicByRelationName(
  2806. [source],
  2807. 'source',
  2808. 'target',
  2809. 'children',
  2810. 'parent',
  2811. {where: {and: [{featured: false}]}},
  2812. );
  2813. expect(source).to.be.eql({
  2814. [DEF_PK]: source[DEF_PK],
  2815. children: [
  2816. {
  2817. [DEF_PK]: target1[DEF_PK],
  2818. featured: false,
  2819. parentId: source[DEF_PK],
  2820. parentType: target1.parentType,
  2821. },
  2822. ],
  2823. });
  2824. delete source.children;
  2825. await R.includePolymorphicByRelationName(
  2826. [source],
  2827. 'source',
  2828. 'target',
  2829. 'children',
  2830. 'parent',
  2831. {where: {and: [{featured: true}]}},
  2832. );
  2833. expect(source).to.be.eql({
  2834. [DEF_PK]: source[DEF_PK],
  2835. children: [
  2836. {
  2837. [DEF_PK]: target2[DEF_PK],
  2838. featured: true,
  2839. parentId: source[DEF_PK],
  2840. parentType: target2.parentType,
  2841. },
  2842. {
  2843. [DEF_PK]: target3[DEF_PK],
  2844. featured: true,
  2845. parentId: source[DEF_PK],
  2846. parentType: target3.parentType,
  2847. },
  2848. ],
  2849. });
  2850. });
  2851. });
  2852. });