|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +// https://stackoverflow.com/questions/22958683/how-to-implement-many-to-many-association-in-sequelize/67973948#67973948 |
| 4 | + |
| 5 | +const assert = require('assert'); |
| 6 | +const path = require('path'); |
| 7 | + |
| 8 | +const { Sequelize, DataTypes } = require('sequelize'); |
| 9 | + |
| 10 | +const sequelize = new Sequelize({ |
| 11 | + dialect: 'sqlite', |
| 12 | + storage: 'tmp.' + path.basename(__filename) + '.sqlite', |
| 13 | +}); |
| 14 | + |
| 15 | +(async () => { |
| 16 | + |
| 17 | +// Create the tables. |
| 18 | +const User = sequelize.define('User', { |
| 19 | + name: { type: DataTypes.STRING }, |
| 20 | +}, {}); |
| 21 | +const Post = sequelize.define('Post', { |
| 22 | + body: { type: DataTypes.STRING }, |
| 23 | +}, {}); |
| 24 | +// UserLikesPost is the name of the relation table. |
| 25 | +// Sequelize creates it automatically for us. |
| 26 | +// On SQLite that table looks like this: |
| 27 | +// CREATE TABLE `UserLikesPost` ( |
| 28 | +// `createdAt` DATETIME NOT NULL, |
| 29 | +// `updatedAt` DATETIME NOT NULL, |
| 30 | +// `UserId` INTEGER NOT NULL REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, |
| 31 | +// `PostId` INTEGER NOT NULL REFERENCES `Posts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, |
| 32 | +// PRIMARY KEY (`UserId`, `PostId`) |
| 33 | +// ); |
| 34 | +User.belongsToMany(Post, {through: 'UserLikesPost'}); |
| 35 | +Post.belongsToMany(User, {through: 'UserLikesPost'}); |
| 36 | +await sequelize.sync({force: true}); |
| 37 | + |
| 38 | +// Create some users and likes. |
| 39 | + |
| 40 | +const user0 = await User.create({name: 'user0'}) |
| 41 | +const user1 = await User.create({name: 'user1'}) |
| 42 | +const user2 = await User.create({name: 'user2'}) |
| 43 | + |
| 44 | +const post0 = await Post.create({body: 'post0'}); |
| 45 | +const post1 = await Post.create({body: 'post1'}); |
| 46 | +const post2 = await Post.create({body: 'post2'}); |
| 47 | + |
| 48 | +// Autogenerated add* methods |
| 49 | + |
| 50 | +// Make user0 like post0 |
| 51 | +await user0.addPost(post0) |
| 52 | +// Make user0 and user2 like post1 |
| 53 | +await post1.addUsers([user0, user2]) |
| 54 | + |
| 55 | +// Autogenerated get* methods |
| 56 | + |
| 57 | +// Get likes by a user. |
| 58 | + |
| 59 | +const user0Likes = await user0.getPosts({order: [['body', 'ASC']]}) |
| 60 | +assert(user0Likes[0].body === 'post0'); |
| 61 | +assert(user0Likes[1].body === 'post1'); |
| 62 | +assert(user0Likes.length === 2); |
| 63 | + |
| 64 | +const user1Likes = await user1.getPosts({order: [['body', 'ASC']]}) |
| 65 | +assert(user1Likes.length === 0); |
| 66 | + |
| 67 | +const user2Likes = await user2.getPosts({order: [['body', 'ASC']]}) |
| 68 | +assert(user2Likes[0].body === 'post1'); |
| 69 | +assert(user2Likes.length === 1); |
| 70 | + |
| 71 | +// Get users that liked a given likes. |
| 72 | + |
| 73 | +const post0Likers = await post0.getUsers({order: [['name', 'ASC']]}) |
| 74 | +assert(post0Likers[0].name === 'user0'); |
| 75 | +assert(post0Likers.length === 1); |
| 76 | + |
| 77 | +const post1Likers = await post1.getUsers({order: [['name', 'ASC']]}) |
| 78 | +assert(post1Likers[0].name === 'user0'); |
| 79 | +assert(post1Likers[1].name === 'user2'); |
| 80 | +assert(post1Likers.length === 2); |
| 81 | + |
| 82 | +const post2Likers = await post2.getUsers({order: [['name', 'ASC']]}) |
| 83 | +assert(post1Likers[0].name === 'user0'); |
| 84 | +assert(post1Likers[1].name === 'user2'); |
| 85 | +assert(post1Likers.length === 2); |
| 86 | + |
| 87 | +// Autogenerated has* methods |
| 88 | + |
| 89 | +// Check if user likes post. |
| 90 | +assert( await user0.hasPost(post0)) |
| 91 | +assert( await user0.hasPost(post1)) |
| 92 | +assert(!await user0.hasPost(post2)) |
| 93 | + |
| 94 | +// Check if post is liked by user. |
| 95 | +assert( await post0.hasUser(user0)) |
| 96 | +assert(!await post0.hasUser(user1)) |
| 97 | +assert(!await post0.hasUser(user2)) |
| 98 | + |
| 99 | +// AND of multiple has checks at once. |
| 100 | +assert( await user0.hasPosts([post0, post1])) |
| 101 | +assert(!await user0.hasPosts([post0, post1, post2])) |
| 102 | + |
| 103 | +// Autogenerated count* methods |
| 104 | +assert(await user0.countPosts() === 2) |
| 105 | +assert(await post0.countUsers() === 1) |
| 106 | + |
| 107 | +// Autogenerated remove* method |
| 108 | + |
| 109 | +// user0 doesn't like post0 anymore. |
| 110 | +await user0.removePost(post0) |
| 111 | +// user0 and user 2 don't like post1 anymore. |
| 112 | +await post1.removeUsers([user0, user2]) |
| 113 | +// Check that no-one likes anything anymore. |
| 114 | +assert(await user0.countPosts() === 0) |
| 115 | +assert(await post0.countUsers() === 0) |
| 116 | + |
| 117 | +// Autogenerated create* method |
| 118 | +// Create a new post and automatically make user0 like it. |
| 119 | +const post3 = await user0.createPost({'body': 'post3'}) |
| 120 | +assert(await user0.hasPost(post3)) |
| 121 | +assert(await post3.hasUser(user0)) |
| 122 | + |
| 123 | +// Autogenerated set* method |
| 124 | +// Make user0 like exactly these posts. Unlike anything else. |
| 125 | +await user0.setPosts([post1, post2]) |
| 126 | +assert(!await user0.hasPost(post0)) |
| 127 | +assert( await user0.hasPost(post1)) |
| 128 | +assert( await user0.hasPost(post2)) |
| 129 | +assert(!await user0.hasPost(post3)) |
| 130 | + |
| 131 | +await sequelize.close(); |
| 132 | +})(); |
0 commit comments