diff options
Diffstat (limited to 'util/src')
-rw-r--r-- | util/src/entities/Channel.ts | 11 | ||||
-rw-r--r-- | util/src/entities/Guild.ts | 7 | ||||
-rw-r--r-- | util/src/entities/Member.ts | 9 | ||||
-rw-r--r-- | util/src/entities/User.ts | 5 | ||||
-rw-r--r-- | util/src/util/imports/OrmUtils.ts | 113 | ||||
-rw-r--r-- | util/src/util/imports/index.ts | 1 |
6 files changed, 132 insertions, 14 deletions
diff --git a/util/src/entities/Channel.ts b/util/src/entities/Channel.ts index a7ca647b..48469103 100644 --- a/util/src/entities/Channel.ts +++ b/util/src/entities/Channel.ts @@ -1,4 +1,5 @@ -import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId} from "typeorm"; +import { OrmUtils } from "@fosscord/util"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { PublicUserProjection, User } from "./User"; @@ -222,7 +223,7 @@ export class Channel extends BaseClass { }; await Promise.all([ - Object.assign(new Channel(),channel).save(), + OrmUtils.mergeDeep(new Channel(),channel).save(), !opts?.skipEventEmit ? emitEvent({ event: "CHANNEL_CREATE", @@ -263,7 +264,7 @@ export class Channel extends BaseClass { if (containsAll(re, channelRecipients)) { if (channel == null) { channel = ur.channel; - ur = Object.assign(ur, { closed: false }); + ur = OrmUtils.mergeDeep(ur, { closed: false }); await ur.save(); } } @@ -273,7 +274,7 @@ export class Channel extends BaseClass { if (channel == null) { name = trimSpecial(name); - channel = await (Object.assign(new Channel(), { + channel = await (OrmUtils.mergeDeep(new Channel(), { name, type, owner_id: type === ChannelType.DM ? undefined : null, // 1:1 DMs are ownerless in fosscord-server @@ -281,7 +282,7 @@ export class Channel extends BaseClass { last_message_id: null, recipients: channelRecipients.map( (x) => - Object.assign(new Recipient(), { user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) }) + OrmUtils.mergeDeep(new Recipient(), { user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) }) ), }) as Channel).save(); } diff --git a/util/src/entities/Guild.ts b/util/src/entities/Guild.ts index 058033e8..da8a2c2f 100644 --- a/util/src/entities/Guild.ts +++ b/util/src/entities/Guild.ts @@ -1,4 +1,5 @@ -import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToMany, OneToOne, RelationId } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToMany, OneToOne, RelationId} from "typeorm"; +import { OrmUtils } from "@fosscord/util"; import { Config, handleFile, Snowflake } from ".."; import { Ban } from "./Ban"; import { BaseClass } from "./BaseClass"; @@ -285,7 +286,7 @@ export class Guild extends BaseClass { }) { const guild_id = Snowflake.generate(); - const guild: Guild = Object.assign(new Guild(),{ + const guild: Guild = OrmUtils.mergeDeep(new Guild(),{ name: body.name || "Fosscord", icon: await handleFile(`/icons/${guild_id}`, body.icon as string), region: Config.get().regions.default, @@ -321,7 +322,7 @@ export class Guild extends BaseClass { // we have to create the role _after_ the guild because else we would get a "SQLITE_CONSTRAINT: FOREIGN KEY constraint failed" error // TODO: make the @everyone a pseudorole that is dynamically generated at runtime so we can save storage - let role: Role = Object.assign(new Role(), { + let role: Role = OrmUtils.mergeDeep(new Role(), { id: guild_id, guild_id: guild_id, color: 0, diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts index e4aa8331..f0c361d0 100644 --- a/util/src/entities/Member.ts +++ b/util/src/entities/Member.ts @@ -25,6 +25,7 @@ import { Role } from "./Role"; import { BaseClassWithoutId } from "./BaseClass"; import { Ban, PublicGuildRelations } from "."; import { DiscordApiErrors } from "../util/Constants"; +import { OrmUtils } from "@fosscord/util"; export const MemberPrivateProjection: (keyof Member)[] = [ "id", @@ -161,7 +162,7 @@ export class Member extends BaseClassWithoutId { }), Role.findOneOrFail({ where: { id: role_id, guild_id }, select: ["id"] }), ]); - member.roles.push(Object.assign(new Role(), { id: role_id })); + member.roles.push(OrmUtils.mergeDeep(new Role(), { id: role_id })); await Promise.all([ member.save(), @@ -256,7 +257,7 @@ export class Member extends BaseClassWithoutId { nick: undefined, roles: [guild_id], // @everyone role joined_at: new Date(), - premium_since: (new Date()).getTime(), + premium_since: new Date(), deaf: false, mute: false, pending: false, @@ -264,9 +265,9 @@ export class Member extends BaseClassWithoutId { //TODO: check for bugs if(guild.member_count) guild.member_count++; await Promise.all([ - Object.assign(new Member(), { + OrmUtils.mergeDeep(new Member(), { ...member, - roles: [Object.assign(new Role(), { id: guild_id })], + roles: [OrmUtils.mergeDeep(new Role(), { id: guild_id })], // read_state: {}, settings: { channel_overrides: [], diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts index 81017c2d..d023780b 100644 --- a/util/src/entities/User.ts +++ b/util/src/entities/User.ts @@ -1,4 +1,5 @@ -import { Column, Entity, FindOneOptions, FindOptionsSelectByString, JoinColumn, ManyToMany, OneToMany, RelationId } from "typeorm"; +import { Column, Entity, FindOneOptions, FindOptionsSelectByString, JoinColumn, ManyToMany, OneToMany, RelationId} from "typeorm"; +import { OrmUtils } from "@fosscord/util"; import { BaseClass } from "./BaseClass"; import { BitField } from "../util/BitField"; import { Relationship } from "./Relationship"; @@ -255,7 +256,7 @@ export class User extends BaseClass { // if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false const language = req.language === "en" ? "en-US" : req.language || "en-US"; - const user = Object.assign(new User(), { + const user = OrmUtils.mergeDeep(new User(), { created_at: new Date(), username: username, discriminator, diff --git a/util/src/util/imports/OrmUtils.ts b/util/src/util/imports/OrmUtils.ts new file mode 100644 index 00000000..91d88172 --- /dev/null +++ b/util/src/util/imports/OrmUtils.ts @@ -0,0 +1,113 @@ +//source: https://github.com/typeorm/typeorm/blob/master/src/util/OrmUtils.ts +export class OrmUtils { + // Checks if it's an object made by Object.create(null), {} or new Object() + private static isPlainObject(item: any) { + if (item === null || item === undefined) { + return false + } + + return !item.constructor || item.constructor === Object + } + + private static mergeArrayKey( + target: any, + key: number, + value: any, + memo: Map<any, any>, + ) { + // Have we seen this before? Prevent infinite recursion. + if (memo.has(value)) { + target[key] = memo.get(value) + return + } + + if (value instanceof Promise) { + // Skip promises entirely. + // This is a hold-over from the old code & is because we don't want to pull in + // the lazy fields. Ideally we'd remove these promises via another function first + // but for now we have to do it here. + return + } + + if (!this.isPlainObject(value) && !Array.isArray(value)) { + target[key] = value + return + } + + if (!target[key]) { + target[key] = Array.isArray(value) ? [] : {} + } + + memo.set(value, target[key]) + this.merge(target[key], value, memo) + memo.delete(value) + } + + private static mergeObjectKey( + target: any, + key: string, + value: any, + memo: Map<any, any>, + ) { + // Have we seen this before? Prevent infinite recursion. + if (memo.has(value)) { + Object.assign(target, { [key]: memo.get(value) }) + return + } + + if (value instanceof Promise) { + // Skip promises entirely. + // This is a hold-over from the old code & is because we don't want to pull in + // the lazy fields. Ideally we'd remove these promises via another function first + // but for now we have to do it here. + return + } + + if (!this.isPlainObject(value) && !Array.isArray(value)) { + Object.assign(target, { [key]: value }) + return + } + + if (!target[key]) { + Object.assign(target, { [key]: value }) + } + + memo.set(value, target[key]) + this.merge(target[key], value, memo) + memo.delete(value) + } + + private static merge( + target: any, + source: any, + memo: Map<any, any> = new Map(), + ): any { + if (Array.isArray(target) && Array.isArray(source)) { + for (let key = 0; key < source.length; key++) { + this.mergeArrayKey(target, key, source[key], memo) + } + } + else { + for (const key of Object.keys(source)) { + this.mergeObjectKey(target, key, source[key], memo) + } + } + + + } + + /** + * Deep Object.assign. + */ + static mergeDeep(target: any, ...sources: any[]): any { + if (!sources.length) { + return target + } + + for (const source of sources) { + OrmUtils.merge(target, source) + } + + return target + } +} \ No newline at end of file diff --git a/util/src/util/imports/index.ts b/util/src/util/imports/index.ts index 4a4448ba..18c47a3b 100644 --- a/util/src/util/imports/index.ts +++ b/util/src/util/imports/index.ts @@ -1,2 +1,3 @@ export * from './Checks'; export * from './HTTPError'; +export * from './OrmUtils'; \ No newline at end of file |