};
function removeCachedPath (pluginPath: string) {
- const pathCache = (module.constructor as any)._pathCache
+ const pathCache = (module.constructor as any)._pathCache as { [ id: string ]: string[] }
Object.keys(pathCache).forEach(function (cacheKey) {
if (cacheKey.includes(pluginPath)) {
--- /dev/null
+import memoizee from 'memoizee'
+
+export function Memoize (config?: memoizee.Options<any>) {
+ return function (_target, _key, descriptor: PropertyDescriptor) {
+ const oldFunction = descriptor.value
+ const newFunction = memoizee(oldFunction, config)
+
+ descriptor.value = function () {
+ return newFunction.apply(this, arguments)
+ }
+ }
+}
import { VideoBlacklistModel } from '../video/video-blacklist'
import { ScopeNames as VideoChannelScopeNames, SummaryOptions as ChannelSummaryOptions, VideoChannelModel } from '../video/video-channel'
import { ScopeNames as CommentScopeNames, VideoCommentModel } from '../video/video-comment'
-import { buildAbuseListQuery, BuildAbusesQueryOptions } from './abuse-query-builder'
+import { buildAbuseListQuery, BuildAbusesQueryOptions } from './sql/abuse-query-builder'
import { VideoAbuseModel } from './video-abuse'
import { VideoCommentAbuseModel } from './video-comment-abuse'
import { exists } from '@server/helpers/custom-validators/misc'
import { forceNumber } from '@shared/core-utils'
import { AbuseFilter, AbuseState, AbuseVideoIs } from '@shared/models'
-import { buildBlockedAccountSQL, buildDirectionAndField } from '../utils'
+import { buildBlockedAccountSQL, buildDirectionAndField } from '../../utils'
export type BuildAbusesQueryOptions = {
start: number
import { ServerModel } from '../server/server'
import { ServerBlocklistModel } from '../server/server-blocklist'
import { UserModel } from '../user/user'
-import { getSort, throwIfNotValid } from '../utils'
+import { buildSQLAttributes, getSort, throwIfNotValid } from '../utils'
import { VideoModel } from '../video/video'
import { VideoChannelModel } from '../video/video-channel'
import { VideoCommentModel } from '../video/video-comment'
return undefined
}
+ // ---------------------------------------------------------------------------
+
+ static getSQLAttributes (tableName: string, aliasPrefix = '') {
+ return buildSQLAttributes({
+ model: this,
+ tableName,
+ aliasPrefix
+ })
+ }
+
+ // ---------------------------------------------------------------------------
+
static load (id: number, transaction?: Transaction): Promise<MAccountDefault> {
return AccountModel.findByPk(id, { transaction })
}
import { AccountModel } from '../account/account'
import { ServerModel } from '../server/server'
import { doesExist } from '../shared/query'
-import { createSafeIn, getSort, searchAttribute, throwIfNotValid } from '../utils'
+import { buildSQLAttributes, createSafeIn, getSort, searchAttribute, throwIfNotValid } from '../utils'
import { VideoChannelModel } from '../video/video-channel'
import { ActorModel, unusedActorAttributesForAPI } from './actor'
import { InstanceListFollowersQueryBuilder, ListFollowersOptions } from './sql/instance-list-followers-query-builder'
})
}
+ // ---------------------------------------------------------------------------
+
+ static getSQLAttributes (tableName: string, aliasPrefix = '') {
+ return buildSQLAttributes({
+ model: this,
+ tableName,
+ aliasPrefix
+ })
+ }
+
+ // ---------------------------------------------------------------------------
+
/*
* @deprecated Use `findOrCreateCustom` instead
*/
import { logger } from '../../helpers/logger'
import { CONFIG } from '../../initializers/config'
import { LAZY_STATIC_PATHS, MIMETYPES, WEBSERVER } from '../../initializers/constants'
-import { throwIfNotValid } from '../utils'
+import { buildSQLAttributes, throwIfNotValid } from '../utils'
import { ActorModel } from './actor'
@Table({
.catch(err => logger.error('Cannot remove actor image file %s.', instance.filename, { err }))
}
+ // ---------------------------------------------------------------------------
+
+ static getSQLAttributes (tableName: string, aliasPrefix = '') {
+ return buildSQLAttributes({
+ model: this,
+ tableName,
+ aliasPrefix
+ })
+ }
+
+ // ---------------------------------------------------------------------------
+
static loadByName (filename: string) {
const query = {
where: {
import { AccountModel } from '../account/account'
import { getServerActor } from '../application/application'
import { ServerModel } from '../server/server'
-import { isOutdated, throwIfNotValid } from '../utils'
+import { buildSQLAttributes, isOutdated, throwIfNotValid } from '../utils'
import { VideoModel } from '../video/video'
import { VideoChannelModel } from '../video/video-channel'
import { ActorFollowModel } from './actor-follow'
FULL = 'FULL'
}
-export const unusedActorAttributesForAPI = [
+export const unusedActorAttributesForAPI: (keyof AttributesOnly<ActorModel>)[] = [
'publicKey',
'privateKey',
'inboxUrl',
})
VideoChannel: VideoChannelModel
+ // ---------------------------------------------------------------------------
+
+ static getSQLAttributes (tableName: string, aliasPrefix = '') {
+ return buildSQLAttributes({
+ model: this,
+ tableName,
+ aliasPrefix
+ })
+ }
+
+ static getSQLAPIAttributes (tableName: string, aliasPrefix = '') {
+ return buildSQLAttributes({
+ model: this,
+ tableName,
+ aliasPrefix,
+ excludeAttributes: unusedActorAttributesForAPI
+ })
+ }
+
+ // ---------------------------------------------------------------------------
+
static async load (id: number): Promise<MActor> {
const actorServer = await getServerActor()
if (id === actorServer.id) return actorServer
+import { logger } from '@server/helpers/logger'
+import { Memoize } from '@server/helpers/memoize'
+import { ServerModel } from '@server/models/server/server'
+import { ActorModel } from '../../actor'
+import { ActorFollowModel } from '../../actor-follow'
+import { ActorImageModel } from '../../actor-image'
+
export class ActorFollowTableAttributes {
+ @Memoize()
getFollowAttributes () {
- return [
- '"ActorFollowModel"."id"',
- '"ActorFollowModel"."state"',
- '"ActorFollowModel"."score"',
- '"ActorFollowModel"."url"',
- '"ActorFollowModel"."actorId"',
- '"ActorFollowModel"."targetActorId"',
- '"ActorFollowModel"."createdAt"',
- '"ActorFollowModel"."updatedAt"'
- ].join(', ')
+ logger.error('coucou')
+
+ return ActorFollowModel.getSQLAttributes('ActorFollowModel').join(', ')
}
+ @Memoize()
getActorAttributes (actorTableName: string) {
- return [
- `"${actorTableName}"."id" AS "${actorTableName}.id"`,
- `"${actorTableName}"."type" AS "${actorTableName}.type"`,
- `"${actorTableName}"."preferredUsername" AS "${actorTableName}.preferredUsername"`,
- `"${actorTableName}"."url" AS "${actorTableName}.url"`,
- `"${actorTableName}"."publicKey" AS "${actorTableName}.publicKey"`,
- `"${actorTableName}"."privateKey" AS "${actorTableName}.privateKey"`,
- `"${actorTableName}"."followersCount" AS "${actorTableName}.followersCount"`,
- `"${actorTableName}"."followingCount" AS "${actorTableName}.followingCount"`,
- `"${actorTableName}"."inboxUrl" AS "${actorTableName}.inboxUrl"`,
- `"${actorTableName}"."outboxUrl" AS "${actorTableName}.outboxUrl"`,
- `"${actorTableName}"."sharedInboxUrl" AS "${actorTableName}.sharedInboxUrl"`,
- `"${actorTableName}"."followersUrl" AS "${actorTableName}.followersUrl"`,
- `"${actorTableName}"."followingUrl" AS "${actorTableName}.followingUrl"`,
- `"${actorTableName}"."remoteCreatedAt" AS "${actorTableName}.remoteCreatedAt"`,
- `"${actorTableName}"."serverId" AS "${actorTableName}.serverId"`,
- `"${actorTableName}"."createdAt" AS "${actorTableName}.createdAt"`,
- `"${actorTableName}"."updatedAt" AS "${actorTableName}.updatedAt"`
- ].join(', ')
+ return ActorModel.getSQLAttributes(actorTableName, `${actorTableName}.`).join(', ')
}
+ @Memoize()
getServerAttributes (actorTableName: string) {
- return [
- `"${actorTableName}->Server"."id" AS "${actorTableName}.Server.id"`,
- `"${actorTableName}->Server"."host" AS "${actorTableName}.Server.host"`,
- `"${actorTableName}->Server"."redundancyAllowed" AS "${actorTableName}.Server.redundancyAllowed"`,
- `"${actorTableName}->Server"."createdAt" AS "${actorTableName}.Server.createdAt"`,
- `"${actorTableName}->Server"."updatedAt" AS "${actorTableName}.Server.updatedAt"`
- ].join(', ')
+ return ServerModel.getSQLAttributes(`${actorTableName}->Server`, `${actorTableName}.Server.`).join(', ')
}
+ @Memoize()
getAvatarAttributes (actorTableName: string) {
- return [
- `"${actorTableName}->Avatars"."id" AS "${actorTableName}.Avatars.id"`,
- `"${actorTableName}->Avatars"."filename" AS "${actorTableName}.Avatars.filename"`,
- `"${actorTableName}->Avatars"."height" AS "${actorTableName}.Avatars.height"`,
- `"${actorTableName}->Avatars"."width" AS "${actorTableName}.Avatars.width"`,
- `"${actorTableName}->Avatars"."fileUrl" AS "${actorTableName}.Avatars.fileUrl"`,
- `"${actorTableName}->Avatars"."onDisk" AS "${actorTableName}.Avatars.onDisk"`,
- `"${actorTableName}->Avatars"."type" AS "${actorTableName}.Avatars.type"`,
- `"${actorTableName}->Avatars"."actorId" AS "${actorTableName}.Avatars.actorId"`,
- `"${actorTableName}->Avatars"."createdAt" AS "${actorTableName}.Avatars.createdAt"`,
- `"${actorTableName}->Avatars"."updatedAt" AS "${actorTableName}.Avatars.updatedAt"`
- ].join(', ')
+ return ActorImageModel.getSQLAttributes(`${actorTableName}->Avatars`, `${actorTableName}.Avatars.`).join(', ')
}
}
import { AttributesOnly } from '@shared/typescript-utils'
import { isHostValid } from '../../helpers/custom-validators/servers'
import { ActorModel } from '../actor/actor'
-import { throwIfNotValid } from '../utils'
+import { buildSQLAttributes, throwIfNotValid } from '../utils'
import { ServerBlocklistModel } from './server-blocklist'
@Table({
})
BlockedBy: ServerBlocklistModel[]
+ // ---------------------------------------------------------------------------
+
+ static getSQLAttributes (tableName: string, aliasPrefix = '') {
+ return buildSQLAttributes({
+ model: this,
+ tableName,
+ aliasPrefix
+ })
+ }
+
+ // ---------------------------------------------------------------------------
+
static load (id: number, transaction?: Transaction): Promise<MServer> {
const query = {
where: {
-import { literal, Op, OrderItem, Sequelize } from 'sequelize'
+import { literal, Model, ModelStatic, Op, OrderItem, Sequelize } from 'sequelize'
import validator from 'validator'
import { forceNumber } from '@shared/core-utils'
+import { AttributesOnly } from '@shared/typescript-utils'
type SortType = { sortModel: string, sortValue: string }
'WHERE "serverBlocklist"."accountId" IN (' + blockerIdsString + ')'
}
-function buildBlockedAccountSQLOptimized (columnNameJoin: string, blockerIds: number[]) {
- const blockerIdsString = blockerIds.join(', ')
-
- return [
- literal(
- `NOT EXISTS (` +
- ` SELECT 1 FROM "accountBlocklist" ` +
- ` WHERE "targetAccountId" = ${columnNameJoin} ` +
- ` AND "accountId" IN (${blockerIdsString})` +
- `)`
- ),
-
- literal(
- `NOT EXISTS (` +
- ` SELECT 1 FROM "account" ` +
- ` INNER JOIN "actor" ON account."actorId" = actor.id ` +
- ` INNER JOIN "serverBlocklist" ON "actor"."serverId" = "serverBlocklist"."targetServerId" ` +
- ` WHERE "account"."id" = ${columnNameJoin} ` +
- ` AND "serverBlocklist"."accountId" IN (${blockerIdsString})` +
- `)`
- )
- ]
-}
-
function buildServerIdsFollowedBy (actorId: any) {
const actorIdNumber = forceNumber(actorId)
}
}
+function buildSQLAttributes <M extends Model> (options: {
+ model: ModelStatic<M>
+ tableName: string
+
+ excludeAttributes?: (keyof AttributesOnly<M>)[]
+ aliasPrefix?: string
+}) {
+ const { model, tableName, aliasPrefix, excludeAttributes } = options
+
+ const attributes = Object.keys(model.getAttributes())
+
+ return attributes
+ .filter(a => {
+ if (!excludeAttributes) return true
+ if (excludeAttributes.includes(a)) return false
+
+ return true
+ })
+ .map(a => {
+ return `"${tableName}"."${a}" AS "${aliasPrefix || ''}${a}"`
+ })
+}
+
// ---------------------------------------------------------------------------
export {
+ buildSQLAttributes,
buildBlockedAccountSQL,
- buildBlockedAccountSQLOptimized,
buildLocalActorIdsIn,
getPlaylistSort,
SortType,
+import { Memoize } from '@server/helpers/memoize'
+import { AccountModel } from '@server/models/account/account'
+import { ActorModel } from '@server/models/actor/actor'
+import { ActorImageModel } from '@server/models/actor/actor-image'
+import { ServerModel } from '@server/models/server/server'
+import { VideoCommentModel } from '../../video-comment'
+
export class VideoCommentTableAttributes {
+ @Memoize()
getVideoCommentAttributes () {
- return [
- '"VideoCommentModel"."id"',
- '"VideoCommentModel"."url"',
- '"VideoCommentModel"."deletedAt"',
- '"VideoCommentModel"."updatedAt"',
- '"VideoCommentModel"."createdAt"',
- '"VideoCommentModel"."text"',
- '"VideoCommentModel"."originCommentId"',
- '"VideoCommentModel"."inReplyToCommentId"',
- '"VideoCommentModel"."videoId"',
- '"VideoCommentModel"."accountId"'
- ].join(', ')
+ return VideoCommentModel.getSQLAttributes('VideoCommentModel').join(', ')
}
+ @Memoize()
getAccountAttributes () {
- return [
- `"Account"."id" AS "Account.id"`,
- `"Account"."name" AS "Account.name"`,
- `"Account"."description" AS "Account.description"`,
- `"Account"."createdAt" AS "Account.createdAt"`,
- `"Account"."updatedAt" AS "Account.updatedAt"`,
- `"Account"."actorId" AS "Account.actorId"`,
- `"Account"."userId" AS "Account.userId"`,
- `"Account"."applicationId" AS "Account.applicationId"`
- ].join(', ')
+ return AccountModel.getSQLAttributes('Account', 'Account.').join(', ')
}
+ @Memoize()
getVideoAttributes () {
return [
`"Video"."id" AS "Video.id"`,
].join(', ')
}
+ @Memoize()
getActorAttributes () {
- return [
- `"Account->Actor"."id" AS "Account.Actor.id"`,
- `"Account->Actor"."type" AS "Account.Actor.type"`,
- `"Account->Actor"."preferredUsername" AS "Account.Actor.preferredUsername"`,
- `"Account->Actor"."url" AS "Account.Actor.url"`,
- `"Account->Actor"."followersCount" AS "Account.Actor.followersCount"`,
- `"Account->Actor"."followingCount" AS "Account.Actor.followingCount"`,
- `"Account->Actor"."remoteCreatedAt" AS "Account.Actor.remoteCreatedAt"`,
- `"Account->Actor"."serverId" AS "Account.Actor.serverId"`,
- `"Account->Actor"."createdAt" AS "Account.Actor.createdAt"`,
- `"Account->Actor"."updatedAt" AS "Account.Actor.updatedAt"`
- ].join(', ')
+ return ActorModel.getSQLAPIAttributes('Account->Actor', `Account.Actor.`).join(', ')
}
+ @Memoize()
getServerAttributes () {
- return [
- `"Account->Actor->Server"."id" AS "Account.Actor.Server.id"`,
- `"Account->Actor->Server"."host" AS "Account.Actor.Server.host"`,
- `"Account->Actor->Server"."redundancyAllowed" AS "Account.Actor.Server.redundancyAllowed"`,
- `"Account->Actor->Server"."createdAt" AS "Account.Actor.Server.createdAt"`,
- `"Account->Actor->Server"."updatedAt" AS "Account.Actor.Server.updatedAt"`
- ].join(', ')
+ return ServerModel.getSQLAttributes('Account->Actor->Server', `Account.Actor.Server.`).join(', ')
}
+ @Memoize()
getAvatarAttributes () {
- return [
- `"Account->Actor->Avatars"."id" AS "Account.Actor.Avatars.id"`,
- `"Account->Actor->Avatars"."filename" AS "Account.Actor.Avatars.filename"`,
- `"Account->Actor->Avatars"."height" AS "Account.Actor.Avatars.height"`,
- `"Account->Actor->Avatars"."width" AS "Account.Actor.Avatars.width"`,
- `"Account->Actor->Avatars"."fileUrl" AS "Account.Actor.Avatars.fileUrl"`,
- `"Account->Actor->Avatars"."onDisk" AS "Account.Actor.Avatars.onDisk"`,
- `"Account->Actor->Avatars"."type" AS "Account.Actor.Avatars.type"`,
- `"Account->Actor->Avatars"."actorId" AS "Account.Actor.Avatars.actorId"`,
- `"Account->Actor->Avatars"."createdAt" AS "Account.Actor.Avatars.createdAt"`,
- `"Account->Actor->Avatars"."updatedAt" AS "Account.Actor.Avatars.updatedAt"`
- ].join(', ')
+ return ActorImageModel.getSQLAttributes('Account->Actor->Avatars', 'Account.Actor.Avatars.id').join(', ')
}
}
import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse'
import { AccountModel } from '../account/account'
import { ActorModel } from '../actor/actor'
-import { buildLocalAccountIdsIn, throwIfNotValid } from '../utils'
+import { buildLocalAccountIdsIn, buildSQLAttributes, throwIfNotValid } from '../utils'
import { ListVideoCommentsOptions, VideoCommentListQueryBuilder } from './sql/comment/video-comment-list-query-builder'
import { VideoModel } from './video'
import { VideoChannelModel } from './video-channel'
})
CommentAbuses: VideoCommentAbuseModel[]
+ // ---------------------------------------------------------------------------
+
+ static getSQLAttributes (tableName: string, aliasPrefix = '') {
+ return buildSQLAttributes({
+ model: this,
+ tableName,
+ aliasPrefix
+ })
+ }
+
+ // ---------------------------------------------------------------------------
+
static loadById (id: number, t?: Transaction): Promise<MComment> {
const query: FindOptions = {
where: {