diff --git a/rootfs_overlay/lkmc/nodejs/assert_cheat.js b/rootfs_overlay/lkmc/nodejs/assert_cheat.js new file mode 100755 index 0000000..e999822 --- /dev/null +++ b/rootfs_overlay/lkmc/nodejs/assert_cheat.js @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +const assert = require('assert'); + +assert(1 + 1 === 2) diff --git a/rootfs_overlay/lkmc/nodejs/list_object_methods.js b/rootfs_overlay/lkmc/nodejs/list_object_methods.js new file mode 100755 index 0000000..1a34111 --- /dev/null +++ b/rootfs_overlay/lkmc/nodejs/list_object_methods.js @@ -0,0 +1,47 @@ +#!/usr/bin/env node + +// https://stackoverflow.com/questions/2257993/how-to-display-all-methods-of-an-object/67975040#67975040 +// https://stackoverflow.com/questions/30881632/es6-iterate-over-class-methods/47714550#47714550 + +const isGetter = (x, name) => (Object.getOwnPropertyDescriptor(x, name) || {}).get +const isFunction = (x, name) => typeof x[name] === "function"; +const deepFunctions = x => + x && x !== Object.prototype && + Object.getOwnPropertyNames(x) + .filter(name => isGetter(x, name) || isFunction(x, name)) + .concat(deepFunctions(Object.getPrototypeOf(x)) || []); +const distinctDeepFunctions = x => Array.from(new Set(deepFunctions(x))); +const getMethods = (obj) => distinctDeepFunctions(obj).filter( + name => name !== "constructor" && !~name.indexOf("__")); + +// Example usage. + +class BaseClass { + constructor() { + this.baseProp = 1 + } + override() { return 1; } + baseMethod() { return 2; } +} + +class DerivedClass extends BaseClass { + constructor() { + super() + this.derivedProp = 2 + } + override() { return 3; } + get myGetter() { return 4; } + static myStatic() { return 5; } +} + +const obj = new DerivedClass(); +const methods = getMethods(obj) +methods.sort() +const assert = require('assert') +const util = require('util') +assert(methods[0] === 'baseMethod') +assert(methods[1] === 'myGetter') +assert(methods[2] === 'override') +assert(methods.length === 3) + +console.log(getMethods(Math)) diff --git a/rootfs_overlay/lkmc/nodejs/object_to_string.js b/rootfs_overlay/lkmc/nodejs/object_to_string.js index 62cbefc..888c530 100755 --- a/rootfs_overlay/lkmc/nodejs/object_to_string.js +++ b/rootfs_overlay/lkmc/nodejs/object_to_string.js @@ -29,15 +29,19 @@ let my_object = new MyClassUtilInspectCustom(1, 2, new MyClassUtilInspectCustomS // Affected. console.log('util.inspect'); console.log(util.inspect(my_object)); +console.log(); // Affected. console.log('console.log'); console.log(my_object); +console.log(); // Not affected. console.log('toString'); console.log(my_object.toString()); +console.log(); // Not affected. console.log('toString implicit +'); console.log('implicit ' + my_object); +console.log(); // Not affected. console.log('template string'); console.log(`${my_object}`); @@ -68,15 +72,20 @@ my_object = new MyClassToString(1, 2, new MyClassToStringSubobject(3, 4)); // Affected. console.log('util.inspect'); console.log(util.inspect(my_object)); +console.log(); // Affected. console.log('console.log'); console.log(my_object); +console.log(); // Affected. console.log('toString'); console.log(my_object.toString()); +console.log(); // Affected. console.log('toString implicit +'); console.log('implicit ' + my_object); +console.log(); // Affected. console.log('template string'); console.log(`${my_object}`); +console.log(); diff --git a/rootfs_overlay/lkmc/nodejs/package.json b/rootfs_overlay/lkmc/nodejs/package.json index d1f6fcb..f7a2e1a 100644 --- a/rootfs_overlay/lkmc/nodejs/package.json +++ b/rootfs_overlay/lkmc/nodejs/package.json @@ -9,8 +9,8 @@ "pg": "8.5.1", "pg-hstore": "2.3.3", "sequelize": "6.5.1", - "sqlite3": "^5.0.2", - "ts-node": "^10.0.0" + "sqlite3": "5.0.2", + "ts-node": "10.0.0" }, "devDependencies": {}, "scripts": { diff --git a/rootfs_overlay/lkmc/nodejs/sequelize/association.js b/rootfs_overlay/lkmc/nodejs/sequelize/association.js index 21de415..85c04aa 100755 --- a/rootfs_overlay/lkmc/nodejs/sequelize/association.js +++ b/rootfs_overlay/lkmc/nodejs/sequelize/association.js @@ -65,6 +65,7 @@ await Comment.create({body: 'u1c0', UserId: u1.id}); console.log(Object.getOwnPropertyNames(u0)); const u0Comments = await u0.getComments({ include: [{ model: User }], + order: [['id', 'ASC']], }); assert(u0Comments[0].body === 'u0c0'); assert(u0Comments[1].body === 'u0c1'); @@ -143,6 +144,5 @@ await Comment.create({body: 'u1c0', UserId: u1.id}); //assert(u0Comments[1].author.name === 'u0'); } } - await sequelize.close(); })(); diff --git a/rootfs_overlay/lkmc/nodejs/sequelize/association_many_to_many.js b/rootfs_overlay/lkmc/nodejs/sequelize/association_many_to_many.js new file mode 100755 index 0000000..0e8de5d --- /dev/null +++ b/rootfs_overlay/lkmc/nodejs/sequelize/association_many_to_many.js @@ -0,0 +1,132 @@ +#!/usr/bin/env node + +// https://stackoverflow.com/questions/22958683/how-to-implement-many-to-many-association-in-sequelize/67973948#67973948 + +const assert = require('assert'); +const path = require('path'); + +const { Sequelize, DataTypes } = require('sequelize'); + +const sequelize = new Sequelize({ + dialect: 'sqlite', + storage: 'tmp.' + path.basename(__filename) + '.sqlite', +}); + +(async () => { + +// Create the tables. +const User = sequelize.define('User', { + name: { type: DataTypes.STRING }, +}, {}); +const Post = sequelize.define('Post', { + body: { type: DataTypes.STRING }, +}, {}); +// UserLikesPost is the name of the relation table. +// Sequelize creates it automatically for us. +// On SQLite that table looks like this: +// CREATE TABLE `UserLikesPost` ( +// `createdAt` DATETIME NOT NULL, +// `updatedAt` DATETIME NOT NULL, +// `UserId` INTEGER NOT NULL REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, +// `PostId` INTEGER NOT NULL REFERENCES `Posts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, +// PRIMARY KEY (`UserId`, `PostId`) +// ); +User.belongsToMany(Post, {through: 'UserLikesPost'}); +Post.belongsToMany(User, {through: 'UserLikesPost'}); +await sequelize.sync({force: true}); + +// Create some users and likes. + +const user0 = await User.create({name: 'user0'}) +const user1 = await User.create({name: 'user1'}) +const user2 = await User.create({name: 'user2'}) + +const post0 = await Post.create({body: 'post0'}); +const post1 = await Post.create({body: 'post1'}); +const post2 = await Post.create({body: 'post2'}); + +// Autogenerated add* methods + +// Make user0 like post0 +await user0.addPost(post0) +// Make user0 and user2 like post1 +await post1.addUsers([user0, user2]) + +// Autogenerated get* methods + +// Get likes by a user. + +const user0Likes = await user0.getPosts({order: [['body', 'ASC']]}) +assert(user0Likes[0].body === 'post0'); +assert(user0Likes[1].body === 'post1'); +assert(user0Likes.length === 2); + +const user1Likes = await user1.getPosts({order: [['body', 'ASC']]}) +assert(user1Likes.length === 0); + +const user2Likes = await user2.getPosts({order: [['body', 'ASC']]}) +assert(user2Likes[0].body === 'post1'); +assert(user2Likes.length === 1); + +// Get users that liked a given likes. + +const post0Likers = await post0.getUsers({order: [['name', 'ASC']]}) +assert(post0Likers[0].name === 'user0'); +assert(post0Likers.length === 1); + +const post1Likers = await post1.getUsers({order: [['name', 'ASC']]}) +assert(post1Likers[0].name === 'user0'); +assert(post1Likers[1].name === 'user2'); +assert(post1Likers.length === 2); + +const post2Likers = await post2.getUsers({order: [['name', 'ASC']]}) +assert(post1Likers[0].name === 'user0'); +assert(post1Likers[1].name === 'user2'); +assert(post1Likers.length === 2); + +// Autogenerated has* methods + +// Check if user likes post. +assert( await user0.hasPost(post0)) +assert( await user0.hasPost(post1)) +assert(!await user0.hasPost(post2)) + +// Check if post is liked by user. +assert( await post0.hasUser(user0)) +assert(!await post0.hasUser(user1)) +assert(!await post0.hasUser(user2)) + +// AND of multiple has checks at once. +assert( await user0.hasPosts([post0, post1])) +assert(!await user0.hasPosts([post0, post1, post2])) + +// Autogenerated count* methods +assert(await user0.countPosts() === 2) +assert(await post0.countUsers() === 1) + +// Autogenerated remove* method + +// user0 doesn't like post0 anymore. +await user0.removePost(post0) +// user0 and user 2 don't like post1 anymore. +await post1.removeUsers([user0, user2]) +// Check that no-one likes anything anymore. +assert(await user0.countPosts() === 0) +assert(await post0.countUsers() === 0) + +// Autogenerated create* method +// Create a new post and automatically make user0 like it. +const post3 = await user0.createPost({'body': 'post3'}) +assert(await user0.hasPost(post3)) +assert(await post3.hasUser(user0)) + +// Autogenerated set* method +// Make user0 like exactly these posts. Unlike anything else. +await user0.setPosts([post1, post2]) +assert(!await user0.hasPost(post0)) +assert( await user0.hasPost(post1)) +assert( await user0.hasPost(post2)) +assert(!await user0.hasPost(post3)) + +await sequelize.close(); +})(); diff --git a/rootfs_overlay/lkmc/nodejs/sequelize/association_many_to_many_custom_table.js b/rootfs_overlay/lkmc/nodejs/sequelize/association_many_to_many_custom_table.js new file mode 100755 index 0000000..8c1fd08 --- /dev/null +++ b/rootfs_overlay/lkmc/nodejs/sequelize/association_many_to_many_custom_table.js @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +// https://stackoverflow.com/questions/22958683/how-to-implement-many-to-many-association-in-sequelize/67973948#67973948 + +const assert = require('assert'); +const path = require('path'); + +const { Sequelize, DataTypes } = require('sequelize'); + +const sequelize = new Sequelize({ + dialect: 'sqlite', + storage: 'tmp.' + path.basename(__filename) + '.sqlite', +}); + +(async () => { + +// Create the tables. +const User = sequelize.define('User', { + name: { type: DataTypes.STRING }, +}, {}); +const Post = sequelize.define('Post', { + body: { type: DataTypes.STRING }, +}, {}); +const UserLikesPost = sequelize.define('UserLikesPost', { + UserId: { + type: DataTypes.INTEGER, + references: { + model: User, + key: 'id' + } + }, + PostId: { + type: DataTypes.INTEGER, + references: { + model: Post, + key: 'id' + } + }, + score: { + type: DataTypes.INTEGER, + }, +}); +// UserLikesPost is the name of the relation table. +// Sequelize creates it automatically for us. +// On SQLite that table looks like this: +// CREATE TABLE `UserLikesPost` ( +// `createdAt` DATETIME NOT NULL, +// `updatedAt` DATETIME NOT NULL, +// `UserId` INTEGER NOT NULL REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, +// `PostId` INTEGER NOT NULL REFERENCES `Posts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, +// `Score` INTEGER, +// PRIMARY KEY (`UserId`, `PostId`) +// ); +User.belongsToMany(Post, {through: UserLikesPost}); +Post.belongsToMany(User, {through: UserLikesPost}); +await sequelize.sync({force: true}); + +// Create some users and likes. + +const user0 = await User.create({name: 'user0'}) +const user1 = await User.create({name: 'user1'}) +const user2 = await User.create({name: 'user2'}) + +const post0 = await Post.create({body: 'post0'}); +const post1 = await Post.create({body: 'post1'}); +const post2 = await Post.create({body: 'post2'}); + +// Autogenerated add* methods + +// Make user0 like post0 +await user0.addPost(post0, {through: { score: 1 }}) + +const user0Likes = await user0.getPosts({order: [['body', 'ASC']]}) +assert(user0Likes[0].body === 'post0'); +assert(user0Likes[0].UserLikesPost.score === 1); +assert(user0Likes.length === 1); + +// TODO: this doesn't work. Possible at all in a single addUsers call? +// Make user0 and user2 like post1 +// This method automatically generated. +//await post1.addUsers( +// [user0, user2], +// {through: [ +// {score: 2}, +// {score: 3}, +// ]} +//) + +await sequelize.close(); +})(); diff --git a/rootfs_overlay/lkmc/nodejs/sequelize/association_many_to_many_same_model.js b/rootfs_overlay/lkmc/nodejs/sequelize/association_many_to_many_same_model.js new file mode 100755 index 0000000..1b3c36d --- /dev/null +++ b/rootfs_overlay/lkmc/nodejs/sequelize/association_many_to_many_same_model.js @@ -0,0 +1,40 @@ +#!/usr/bin/env node + +// https://stackoverflow.com/questions/22958683/how-to-implement-many-to-many-association-in-sequelize/67973948#67973948 + +const assert = require('assert'); +const path = require('path'); + +const { Sequelize, DataTypes } = require('sequelize'); + +const sequelize = new Sequelize({ + dialect: 'sqlite', + storage: 'tmp.' + path.basename(__filename) + '.sqlite', +}); + +(async () => { + +// Create the tables. +const User = sequelize.define('User', { + name: { type: DataTypes.STRING }, +}, {}); +User.belongsToMany(User, {through: 'UserFollowsUser', as: 'Follow'}); +await sequelize.sync({force: true}); + +// Create some users. + +const user0 = await User.create({name: 'user0'}) +const user1 = await User.create({name: 'user1'}) +const user2 = await User.create({name: 'user2'}) +const user3 = await User.create({name: 'user3'}) + +// Make user0 follow user1 and user2 +await user0.addFollow(user1) +await user0.addFollow(user2) +const user0Follows = await user0.getFollow({order: [['name', 'ASC']]}) +assert(user0Follows[0].name === 'user1'); +assert(user0Follows[1].name === 'user2'); +assert(user0Follows.length === 2); + +await sequelize.close(); +})();