diff --git a/.gitignore b/.gitignore index 2a463c714..6f37b887a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,7 @@ src/auth-server/emails/templates/preview /db/persisted /scripts/orion-v1-migration/data /db/export +/db/migrations_dir* + +# LOGS +chron_mail_scheduler.log diff --git a/CHANGELOG.md b/CHANGELOG.md index 70a15b4a3..ba7a921eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +# 3.4.0 + +## Schema changes +- Added `@schema(name: "admin")` directive to hide entities (from public GRAPHQL API) in Graphql schema definitions. + +## Misc +- Patch `@subsquid/typeorm-config` & `@subsquid/typeorm-migration` packages to change `squid-typeorm-migration apply` command to apply a single migrations file too using `--filename` option instead of applying the whole `db/migrations` directory. +- Patch `@subsquid/openreader` and `@subsquid/typeorm-codegen` dependencies to include the db schema `name` too in the generated typeorm/postgres migrations, and an optional `schema` directive to specify the schema of any GRAPHQL entity. + +## DB Migrations +- Update `generate-migrations` makefile command. Now the existing `*-Data.js` will not be overwritten, instead a new `*-Data.js` migration file (containing only changes compared to the previous DB state) will be added whenever there are GRAPHQL schema changes. The `*-Views.js` migration file will also be updated whenever the GRAPHQL schema changes. +- Create `generateViewsMigration.js` script to create new `*-Views.js` migration file. +- Separate the view definitions(in `db/viewDefinitions.js`) from views migration file(`*-Views.js`). +- Add `*-Admin.js` migration file to create an `admin` schema & user, previously the `admin` schema and user was being created in the `*-Views.js` migration. +- Regenerate the postgres db migrations. + +## Documentation +- Updated documentation for [upgrading-orion.md](docs/operator-guide/tutorials/upgrading-orion.md) +- Updated documentation for [entity-visibility.md#managing-entity-visibility](docs/developer-guide/tutorials/entity-visibility.md) + +### Bug Fixes: +- read/write `export.json` file, containing the offchain state, using `big-json` package, instead using Javascript native `JSON.stringify` function which does not work on large JSON objects + # 3.3.0 ## Schema diff --git a/Makefile b/Makefile index 9cfc2b928..44c01e29b 100644 --- a/Makefile +++ b/Makefile @@ -24,16 +24,25 @@ dbgen: @npx squid-typeorm-migration generate generate-migrations: - @rm db/migrations/*-Data.js || true @docker run -d --name temp_migrations_db \ -e POSTGRES_DB=squid \ -e POSTGRES_HOST_AUTH_METHOD=trust \ -v temp_migrations_db_volume:/var/lib/postgresql/data \ -v ./db/postgres.conf:/etc/postgresql/postgresql.conf \ -p 5555:5555 postgres:14 postgres -p 5555 || true - @export DB_PORT=5555 && sleep 5 && npx squid-typeorm-migration generate + @sleep 5 + @export DB_PORT=5555 && npx squid-typeorm-migration apply --filename *-Admin.js + @ls db/migrations > db/migrations_dir_before.txt + @export DB_PORT=5555 && npx squid-typeorm-migration apply --filename *-Data.js + @export DB_PORT=5555 && npx squid-typeorm-migration generate || true + @ls db/migrations > db/migrations_dir_after.txt + @if ! diff db/migrations_dir_before.txt db/migrations_dir_after.txt > /dev/null ; then \ + rm db/migrations/*-Views.js; \ + node db/generateViewsMigration.js; \ + fi; @docker rm temp_migrations_db -vf || true @docker volume rm temp_migrations_db_volume || true + @rm db/migrations_dir_before.txt db/migrations_dir_after.txt || true codegen: @npm run generate:schema || true diff --git a/assets/patches/@subsquid+openreader+3.1.7.patch b/assets/patches/@subsquid+openreader+3.1.7.patch index d74ca3a1c..2495adaa9 100644 --- a/assets/patches/@subsquid+openreader+3.1.7.patch +++ b/assets/patches/@subsquid+openreader+3.1.7.patch @@ -20,6 +20,54 @@ index ccb64b5..faa6199 100644 } //# sourceMappingURL=context.d.ts.map \ No newline at end of file +diff --git a/node_modules/@subsquid/openreader/lib/model.schema.js b/node_modules/@subsquid/openreader/lib/model.schema.js +index 25be2da..74f14da 100644 +--- a/node_modules/@subsquid/openreader/lib/model.schema.js ++++ b/node_modules/@subsquid/openreader/lib/model.schema.js +@@ -11,6 +11,7 @@ const model_tools_1 = require("./model.tools"); + const scalars_1 = require("./scalars"); + const baseSchema = (0, graphql_1.buildASTSchema)((0, graphql_1.parse)(` + directive @entity on OBJECT ++ directive @schema(name: String!) on OBJECT + directive @query on INTERFACE + directive @derivedFrom(field: String!) on FIELD_DEFINITION + directive @unique on FIELD_DEFINITION +@@ -57,11 +58,12 @@ function addEntityOrJsonObjectOrInterface(model, type) { + let properties = {}; + let interfaces = []; + let indexes = type instanceof graphql_1.GraphQLObjectType ? checkEntityIndexes(type) : []; ++ let schema = type instanceof graphql_1.GraphQLObjectType ? checkEntitySchema(type) : undefined; + let cardinality = checkEntityCardinality(type); + let description = type.description || undefined; + switch (kind) { + case 'entity': +- model[type.name] = { kind, properties, description, interfaces, indexes, ...cardinality }; ++ model[type.name] = {kind, properties, description, interfaces, indexes, schema, ...cardinality} + break; + case 'object': + model[type.name] = { kind, properties, description, interfaces }; +@@ -393,6 +395,21 @@ function checkEntityIndexes(type) { + }); + return indexes; + } ++function checkEntitySchema(type) { ++ let schema; ++ type.astNode?.directives?.forEach(d => { ++ if (d.name.value != 'schema') ++ return; ++ if (!isEntityType(type)) ++ throw new SchemaError(`@schema was applied to ${type.name}, but only entities can have base schema`); ++ let fieldsArg = d.arguments?.find(arg => arg.name.value == 'name'); ++ if (fieldsArg == null) ++ throw new SchemaError(`@schema was applied to ${type.name}, but no name were specified`); ++ (0, assert_1.default)(fieldsArg.value.kind == 'StringValue'); ++ schema = fieldsArg.value.value; ++ }); ++ return schema; ++} + function checkDerivedFrom(type, f) { + let directives = f.astNode?.directives?.filter(d => d.name.value == 'derivedFrom') || []; + if (directives.length == 0) diff --git a/node_modules/@subsquid/openreader/lib/server.d.ts b/node_modules/@subsquid/openreader/lib/server.d.ts index da31a85..3691776 100644 --- a/node_modules/@subsquid/openreader/lib/server.d.ts diff --git a/assets/patches/@subsquid+typeorm-codegen+0.3.1.patch b/assets/patches/@subsquid+typeorm-codegen+0.3.1.patch index 59a749d79..ec239aa70 100644 --- a/assets/patches/@subsquid+typeorm-codegen+0.3.1.patch +++ b/assets/patches/@subsquid+typeorm-codegen+0.3.1.patch @@ -1,8 +1,8 @@ diff --git a/node_modules/@subsquid/typeorm-codegen/lib/codegen.js b/node_modules/@subsquid/typeorm-codegen/lib/codegen.js -index e40f9bc..648e5e8 100644 +index e40f9bc..1055524 100644 --- a/node_modules/@subsquid/typeorm-codegen/lib/codegen.js +++ b/node_modules/@subsquid/typeorm-codegen/lib/codegen.js -@@ -62,9 +62,17 @@ function generateOrmModels(model, dir) { +@@ -62,11 +62,19 @@ function generateOrmModels(model, dir) { out.line(); printComment(entity, out); entity.indexes?.forEach(index => { @@ -19,8 +19,11 @@ index e40f9bc..648e5e8 100644 - out.line(`@Index_([${index.fields.map(f => `"${f.name}"`).join(', ')}], {unique: ${!!index.unique}})`); + out.line(`@Index_([${index.fields.map(f => `"${f.name}"`).join(', ')}])`); }); - out.line('@Entity_()'); +- out.line('@Entity_()'); ++ out.line(`@Entity_(${entity.schema ? `{schema: "${entity.schema}"}` : ''})`); out.block(`export class ${name}`, () => { + out.block(`constructor(props?: Partial<${name}>)`, () => { + out.line('Object.assign(this, props)'); @@ -109,8 +117,8 @@ function generateOrmModels(model, dir) { case 'fk': if (getFieldIndex(entity, key)?.unique) { diff --git a/assets/patches/@subsquid+typeorm-config+2.0.2.patch b/assets/patches/@subsquid+typeorm-config+2.0.2.patch new file mode 100644 index 000000000..a95c6d1b5 --- /dev/null +++ b/assets/patches/@subsquid+typeorm-config+2.0.2.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@subsquid/typeorm-config/lib/config.js b/node_modules/@subsquid/typeorm-config/lib/config.js +index 046611f..28fd4e2 100644 +--- a/node_modules/@subsquid/typeorm-config/lib/config.js ++++ b/node_modules/@subsquid/typeorm-config/lib/config.js +@@ -28,22 +28,22 @@ const path = __importStar(require("path")); + const process = __importStar(require("process")); + const connectionOptions_1 = require("./connectionOptions"); + const namingStrategy_1 = require("./namingStrategy"); +-exports.MIGRATIONS_DIR = 'db/migrations'; ++exports.MIGRATIONS_DIR = "db/migrations"; + function createOrmConfig(options) { + let dir = path.resolve(options?.projectDir || process.cwd()); +- let model = resolveModel(path.join(dir, 'lib/model')); ++ let model = resolveModel(path.join(dir, "lib/model")); + let migrationsDir = path.join(dir, exports.MIGRATIONS_DIR); + return { +- type: 'postgres', ++ type: "postgres", + namingStrategy: new namingStrategy_1.SnakeNamingStrategy(), + entities: [model], +- migrations: [migrationsDir + '/*.js'], +- ...(0, connectionOptions_1.createConnectionOptions)() ++ migrations: [migrationsDir + `/${options?.file || "*.js"}`], ++ ...(0, connectionOptions_1.createConnectionOptions)(), + }; + } + exports.createOrmConfig = createOrmConfig; + function resolveModel(model) { +- model = path.resolve(model || 'lib/model'); ++ model = path.resolve(model || "lib/model"); + try { + return require.resolve(model); + } diff --git a/assets/patches/@subsquid+typeorm-migration+0.1.4.patch b/assets/patches/@subsquid+typeorm-migration+0.1.4.patch new file mode 100644 index 000000000..4bf88b6b3 --- /dev/null +++ b/assets/patches/@subsquid+typeorm-migration+0.1.4.patch @@ -0,0 +1,30 @@ +diff --git a/node_modules/@subsquid/typeorm-migration/lib/apply.js b/node_modules/@subsquid/typeorm-migration/lib/apply.js +index a8dd9c8..999ed2a 100644 +--- a/node_modules/@subsquid/typeorm-migration/lib/apply.js ++++ b/node_modules/@subsquid/typeorm-migration/lib/apply.js +@@ -29,10 +29,14 @@ const commander_1 = require("commander"); + const dotenv = __importStar(require("dotenv")); + const typeorm_1 = require("typeorm"); + (0, util_internal_1.runProgram)(async () => { +- commander_1.program.description('Apply pending migrations').parse(); ++ commander_1.program ++ .description("Apply pending migrations") ++ .option("-f, --filename ", "Specify a filename") ++ .parse(); ++ const options = commander_1.program.opts(); + dotenv.config(); + let connection = new typeorm_1.DataSource({ +- ...(0, typeorm_config_1.createOrmConfig)(), ++ ...(0, typeorm_config_1.createOrmConfig)({ file: options.filename }), + subscribers: [], + synchronize: false, + migrationsRun: false, +@@ -41,7 +45,7 @@ const typeorm_1 = require("typeorm"); + }); + await connection.initialize(); + try { +- await connection.runMigrations({ transaction: 'all' }); ++ await connection.runMigrations({ transaction: "all" }); + } + finally { + await connection.destroy().catch(() => null); diff --git a/db/generateViewsMigration.js b/db/generateViewsMigration.js new file mode 100644 index 000000000..827f8c255 --- /dev/null +++ b/db/generateViewsMigration.js @@ -0,0 +1,49 @@ +const fs = require('fs') +const path = require('path') + +const migrationsDir = path.join(__dirname, 'migrations') + +// Function to generate the new views migration file +const generateViewsMigration = (versionNumber) => { + const className = `Views${versionNumber}` + const fileName = `${versionNumber}-Views.js` + const fileContent = ` +const { getViewDefinitions } = require('../viewDefinitions') + +module.exports = class ${className} { + name = '${className}' + + async up(db) { + const viewDefinitions = getViewDefinitions(db); + for (const [tableName, viewConditions] of Object.entries(viewDefinitions)) { + if (Array.isArray(viewConditions)) { + await db.query(\` + CREATE OR REPLACE VIEW "\${tableName}" AS + SELECT * + FROM "admin"."\${tableName}" AS "this" + WHERE \${viewConditions.map(cond => \`(\${cond})\`).join(' AND ')} + \`); + } else { + await db.query(\` + CREATE OR REPLACE VIEW "\${tableName}" AS (\${viewConditions}) + \`); + } + } + } + + async down(db) { + const viewDefinitions = this.getViewDefinitions(db) + for (const viewName of Object.keys(viewDefinitions)) { + await db.query(\`DROP VIEW "\${viewName}"\`) + } + } +} +` + + const filePath = path.join(migrationsDir, fileName) + fs.writeFileSync(filePath, fileContent) + console.log(`Generated new views migration: ${filePath}`) +} + +// Get the latest data migration number and generate the views migration +generateViewsMigration(Date.now()) diff --git a/db/migrations/1000000000000-Admin.js b/db/migrations/1000000000000-Admin.js new file mode 100644 index 000000000..1074280e0 --- /dev/null +++ b/db/migrations/1000000000000-Admin.js @@ -0,0 +1,17 @@ +module.exports = class Admin1000000000000 { + name = 'Admin1000000000000' + + async up(db) { + // Create a new "admin" schema through which the "hidden" entities can be accessed + await db.query(`CREATE SCHEMA "admin"`) + // Create admin user with "admin" schema in default "search_path" + await db.query(`CREATE USER "${process.env.DB_ADMIN_USER}" WITH PASSWORD '${process.env.DB_ADMIN_PASS}'`) + await db.query(`GRANT pg_read_all_data TO "${process.env.DB_ADMIN_USER}"`) + await db.query(`GRANT pg_write_all_data TO "${process.env.DB_ADMIN_USER}"`) + await db.query(`ALTER USER "${process.env.DB_ADMIN_USER}" SET search_path TO admin,public`) + } + + async down(db) { + await db.query(`DROP SCHEMA "admin"`) + } +} diff --git a/db/migrations/1707311702202-Data.js b/db/migrations/1707311702202-Data.js deleted file mode 100644 index a2c7d8243..000000000 --- a/db/migrations/1707311702202-Data.js +++ /dev/null @@ -1,453 +0,0 @@ -module.exports = class Data1707311702202 { - name = 'Data1707311702202' - - async up(db) { - await db.query(`CREATE TABLE "channel_follow" ("id" character varying NOT NULL, "user_id" character varying, "channel_id" text NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_9410df2b9a316af3f0d216f9487" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_822778b4b1ea8e3b60b127cb8b" ON "channel_follow" ("user_id") `) - await db.query(`CREATE INDEX "IDX_9bc0651dda94437ec18764a260" ON "channel_follow" ("channel_id") `) - await db.query(`CREATE TABLE "video_view_event" ("id" character varying NOT NULL, "video_id" text NOT NULL, "user_id" character varying, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_2efd85597a6a7a704fc4d0f7701" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_2e29fba63e12a2b1818e0782d7" ON "video_view_event" ("video_id") `) - await db.query(`CREATE INDEX "IDX_31e1e798ec387ad905cf98d33b" ON "video_view_event" ("user_id") `) - await db.query(`CREATE TABLE "report" ("id" character varying NOT NULL, "user_id" character varying, "channel_id" text, "video_id" text, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "rationale" text NOT NULL, CONSTRAINT "PK_99e4d0bea58cba73c57f935a546" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_c6686efa4cd49fa9a429f01bac" ON "report" ("user_id") `) - await db.query(`CREATE INDEX "IDX_893057921f4b5cc37a0ef36684" ON "report" ("channel_id") `) - await db.query(`CREATE INDEX "IDX_f732b6f82095a935db68c9491f" ON "report" ("video_id") `) - await db.query(`CREATE TABLE "nft_featuring_request" ("id" character varying NOT NULL, "user_id" character varying, "nft_id" text NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "rationale" text NOT NULL, CONSTRAINT "PK_d0b1ccb74336b30b9575387d328" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_519be2a41216c278c35f254dcb" ON "nft_featuring_request" ("user_id") `) - await db.query(`CREATE INDEX "IDX_76d87e26cce72ac2e7ffa28dfb" ON "nft_featuring_request" ("nft_id") `) - await db.query(`CREATE TABLE "user" ("id" character varying NOT NULL, "is_root" boolean NOT NULL, "permissions" character varying(34) array, CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "storage_bucket" ("id" character varying NOT NULL, "operator_status" jsonb NOT NULL, "accepting_new_bags" boolean NOT NULL, "data_objects_size_limit" numeric NOT NULL, "data_object_count_limit" numeric NOT NULL, "data_objects_count" numeric NOT NULL, "data_objects_size" numeric NOT NULL, CONSTRAINT "PK_97cd0c3fe7f51e34216822e5f91" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "storage_bucket_bag" ("id" character varying NOT NULL, "storage_bucket_id" character varying, "bag_id" character varying, CONSTRAINT "StorageBucketBag_storageBucket_bag" UNIQUE ("storage_bucket_id", "bag_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_9d54c04557134225652d566cc82" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_aaf00b2c7d0cba49f97da14fbb" ON "storage_bucket_bag" ("bag_id") `) - await db.query(`CREATE INDEX "IDX_4c475f6c9300284b095859eec3" ON "storage_bucket_bag" ("storage_bucket_id", "bag_id") `) - await db.query(`CREATE TABLE "distribution_bucket_family" ("id" character varying NOT NULL, CONSTRAINT "PK_8cb7454d1ec34b0d3bb7ecdee4e" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "distribution_bucket_operator" ("id" character varying NOT NULL, "distribution_bucket_id" character varying, "worker_id" integer NOT NULL, "status" character varying(7) NOT NULL, CONSTRAINT "PK_03b87e6e972f414bab94c142285" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_678dc5427cdde0cd4fef2c07a4" ON "distribution_bucket_operator" ("distribution_bucket_id") `) - await db.query(`CREATE TABLE "distribution_bucket" ("id" character varying NOT NULL, "family_id" character varying, "bucket_index" integer NOT NULL, "accepting_new_bags" boolean NOT NULL, "distributing" boolean NOT NULL, CONSTRAINT "PK_c90d25fff461f2f5fa9082e2fb7" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_8cb7454d1ec34b0d3bb7ecdee4" ON "distribution_bucket" ("family_id") `) - await db.query(`CREATE TABLE "distribution_bucket_bag" ("id" character varying NOT NULL, "distribution_bucket_id" character varying, "bag_id" character varying, CONSTRAINT "DistributionBucketBag_distributionBucket_bag" UNIQUE ("distribution_bucket_id", "bag_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_02cb97c17ccabf42e8f5154d002" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_a9810100aee7584680f197c8ff" ON "distribution_bucket_bag" ("bag_id") `) - await db.query(`CREATE INDEX "IDX_32e552d352848d64ab82d38e9a" ON "distribution_bucket_bag" ("distribution_bucket_id", "bag_id") `) - await db.query(`CREATE TABLE "storage_bag" ("id" character varying NOT NULL, "owner" jsonb NOT NULL, CONSTRAINT "PK_242aecdc788d9b22bcbb9ade19a" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "storage_data_object" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "is_accepted" boolean NOT NULL, "size" numeric NOT NULL, "storage_bag_id" character varying, "ipfs_hash" text NOT NULL, "type" jsonb, "state_bloat_bond" numeric NOT NULL, "unset_at" TIMESTAMP WITH TIME ZONE, "resolved_urls" text array NOT NULL, CONSTRAINT "PK_61f224a4aef08f580a5ab4aadf0" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_ff8014300b8039dbaed764f51b" ON "storage_data_object" ("storage_bag_id") `) - await db.query(`CREATE TABLE "banned_member" ("id" character varying NOT NULL, "member_id" character varying, "channel_id" character varying, CONSTRAINT "BannedMember_member_channel" UNIQUE ("member_id", "channel_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_ebdf9a9c6d88f1116a5f2d0815d" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_ed36c6c26bf5410796c2fc21f7" ON "banned_member" ("channel_id") `) - await db.query(`CREATE INDEX "IDX_f29ff095bdb945975deca021ad" ON "banned_member" ("member_id", "channel_id") `) - await db.query(`CREATE TABLE "app" ("id" character varying NOT NULL, "name" text NOT NULL, "owner_member_id" character varying, "website_url" text, "use_uri" text, "small_icon" text, "medium_icon" text, "big_icon" text, "one_liner" text, "description" text, "terms_of_service" text, "platforms" text array, "category" text, "auth_key" text, CONSTRAINT "App_name" UNIQUE ("name") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_9478629fc093d229df09e560aea" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_f36adbb7b096ceeb6f3e80ad14" ON "app" ("name") `) - await db.query(`CREATE INDEX "IDX_c9cc395bbc485f70a15be64553" ON "app" ("owner_member_id") `) - await db.query(`CREATE TABLE "channel" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "owner_member_id" character varying, "title" text, "description" text, "cover_photo_id" character varying, "avatar_photo_id" character varying, "is_public" boolean, "is_censored" boolean NOT NULL, "is_excluded" boolean NOT NULL, "language" text, "created_in_block" integer NOT NULL, "reward_account" text NOT NULL, "channel_state_bloat_bond" numeric NOT NULL, "follows_num" integer NOT NULL, "video_views_num" integer NOT NULL, "entry_app_id" character varying, "total_videos_created" integer NOT NULL, "cumulative_reward_claimed" numeric NOT NULL, "cumulative_reward" numeric NOT NULL, "channel_weight" numeric, "ypp_status" jsonb NOT NULL, CONSTRAINT "PK_590f33ee6ee7d76437acf362e39" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_a4752a0a0899dedc4d18077dd0" ON "channel" ("created_at") `) - await db.query(`CREATE INDEX "IDX_25c85bc448b5e236a4c1a5f789" ON "channel" ("owner_member_id") `) - await db.query(`CREATE INDEX "IDX_a77e12f3d8c6ced020e179a5e9" ON "channel" ("cover_photo_id") `) - await db.query(`CREATE INDEX "IDX_6997e94413b3f2f25a84e4a96f" ON "channel" ("avatar_photo_id") `) - await db.query(`CREATE INDEX "IDX_e58a2e1d78b8eccf40531a7fdb" ON "channel" ("language") `) - await db.query(`CREATE INDEX "IDX_118ecfa0199aeb5a014906933e" ON "channel" ("entry_app_id") `) - await db.query(`CREATE TABLE "video_featured_in_category" ("id" character varying NOT NULL, "video_id" character varying, "category_id" character varying, "video_cut_url" text, CONSTRAINT "VideoFeaturedInCategory_category_video" UNIQUE ("category_id", "video_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_f84d38b5cdb7567ac04d6e9d209" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_7b16ddad43901921a8d3c8eab7" ON "video_featured_in_category" ("video_id") `) - await db.query(`CREATE INDEX "IDX_6d0917e1ac0cc06c8075bcf256" ON "video_featured_in_category" ("category_id", "video_id") `) - await db.query(`CREATE TABLE "video_category" ("id" character varying NOT NULL, "name" text, "description" text, "parent_category_id" character varying, "is_supported" boolean NOT NULL, "created_in_block" integer NOT NULL, CONSTRAINT "PK_2a5c61f32e9636ee10821e9a58d" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_cbe7e5d162a819e4ee2e2f6105" ON "video_category" ("name") `) - await db.query(`CREATE INDEX "IDX_da26b34f037c0d59d3c0d0646e" ON "video_category" ("parent_category_id") `) - await db.query(`CREATE TABLE "license" ("id" character varying NOT NULL, "code" integer, "attribution" text, "custom_text" text, CONSTRAINT "PK_f168ac1ca5ba87286d03b2ef905" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "video_subtitle" ("id" character varying NOT NULL, "video_id" character varying, "type" text NOT NULL, "language" text, "mime_type" text NOT NULL, "asset_id" character varying, CONSTRAINT "PK_2ac3e585fc608e673e7fbf94d8e" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_2203674f18d8052ed6bac39625" ON "video_subtitle" ("video_id") `) - await db.query(`CREATE INDEX "IDX_ffa63c28188eecc32af921bfc3" ON "video_subtitle" ("language") `) - await db.query(`CREATE INDEX "IDX_b6eabfb8de4128b28d73681020" ON "video_subtitle" ("asset_id") `) - await db.query(`CREATE TABLE "comment_reaction" ("id" character varying NOT NULL, "reaction_id" integer NOT NULL, "member_id" character varying, "comment_id" character varying, "video_id" character varying, CONSTRAINT "PK_87f27d282c06eb61b1e0cde2d24" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_15080d9fb7cf8b563103dd9d90" ON "comment_reaction" ("member_id") `) - await db.query(`CREATE INDEX "IDX_962582f04d3f639e33f43c54bb" ON "comment_reaction" ("comment_id") `) - await db.query(`CREATE INDEX "IDX_d7995b1d57614a6fbd0c103874" ON "comment_reaction" ("video_id") `) - await db.query(`CREATE TABLE "comment" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "author_id" character varying, "text" text NOT NULL, "video_id" character varying, "status" character varying(9) NOT NULL, "reactions_count_by_reaction_id" jsonb, "parent_comment_id" character varying, "replies_count" integer NOT NULL, "reactions_count" integer NOT NULL, "reactions_and_replies_count" integer NOT NULL, "is_edited" boolean NOT NULL, "is_excluded" boolean NOT NULL, CONSTRAINT "PK_0b0e4bbc8415ec426f87f3a88e2" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_3ce66469b26697baa097f8da92" ON "comment" ("author_id") `) - await db.query(`CREATE INDEX "IDX_1ff03403fd31dfeaba0623a89c" ON "comment" ("video_id") `) - await db.query(`CREATE INDEX "IDX_c3c2abe750c76c7c8e305f71f2" ON "comment" ("status") `) - await db.query(`CREATE INDEX "IDX_ac69bddf8202b7c0752d9dc8f3" ON "comment" ("parent_comment_id") `) - await db.query(`CREATE TABLE "video_reaction" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "reaction" character varying(6) NOT NULL, "member_id" character varying, "video_id" character varying, CONSTRAINT "PK_504876585c394f4ab33665dd44b" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_73dda64f53bbc7ec7035d5e7f0" ON "video_reaction" ("member_id") `) - await db.query(`CREATE INDEX "IDX_436a3836eb47acb5e1e3c88dde" ON "video_reaction" ("video_id") `) - await db.query(`CREATE TABLE "video" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "channel_id" character varying, "category_id" character varying, "title" text, "description" text, "duration" integer, "thumbnail_photo_id" character varying, "language" text, "orion_language" text, "has_marketing" boolean, "published_before_joystream" TIMESTAMP WITH TIME ZONE, "is_public" boolean, "is_censored" boolean NOT NULL, "is_excluded" boolean NOT NULL, "is_explicit" boolean, "license_id" character varying, "media_id" character varying, "video_state_bloat_bond" numeric NOT NULL, "created_in_block" integer NOT NULL, "is_comment_section_enabled" boolean NOT NULL, "pinned_comment_id" character varying, "comments_count" integer NOT NULL, "is_reaction_feature_enabled" boolean NOT NULL, "reactions_count_by_reaction_id" jsonb, "reactions_count" integer NOT NULL, "views_num" integer NOT NULL, "entry_app_id" character varying, "yt_video_id" text, "video_relevance" numeric NOT NULL, CONSTRAINT "PK_1a2f3856250765d72e7e1636c8e" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_fe2b4b6aace15f1b6610830846" ON "video" ("created_at") `) - await db.query(`CREATE INDEX "IDX_81b11ef99a9db9ef1aed040d75" ON "video" ("channel_id") `) - await db.query(`CREATE INDEX "IDX_2a5c61f32e9636ee10821e9a58" ON "video" ("category_id") `) - await db.query(`CREATE INDEX "IDX_8530d052cc79b420f7ce2b4e09" ON "video" ("thumbnail_photo_id") `) - await db.query(`CREATE INDEX "IDX_57b335fa0a960877caf6d2fc29" ON "video" ("orion_language") `) - await db.query(`CREATE INDEX "IDX_3ec633ae5d0477f512b4ed957d" ON "video" ("license_id") `) - await db.query(`CREATE INDEX "IDX_2db879ed42e3308fe65e679672" ON "video" ("media_id") `) - await db.query(`CREATE INDEX "IDX_54f88a7decf7d22fd9bd9fa439" ON "video" ("pinned_comment_id") `) - await db.query(`CREATE INDEX "IDX_6c49ad08c44d36d11f77c426e4" ON "video" ("entry_app_id") `) - await db.query(`CREATE INDEX "IDX_f33816960d690ac836f5d5c28a" ON "video" ("video_relevance") `) - await db.query(`CREATE TABLE "bid" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "auction_id" character varying, "nft_id" character varying, "bidder_id" character varying, "amount" numeric NOT NULL, "is_canceled" boolean NOT NULL, "created_in_block" integer NOT NULL, "index_in_block" integer NOT NULL, "previous_top_bid_id" character varying, CONSTRAINT "PK_ed405dda320051aca2dcb1a50bb" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_9e594e5a61c0f3cb25679f6ba8" ON "bid" ("auction_id") `) - await db.query(`CREATE INDEX "IDX_3caf2d6b31d2fe45a2b85b8191" ON "bid" ("nft_id") `) - await db.query(`CREATE INDEX "IDX_e7618559409a903a897164156b" ON "bid" ("bidder_id") `) - await db.query(`CREATE INDEX "IDX_32cb73025ec49c87f4c594a265" ON "bid" ("previous_top_bid_id") `) - await db.query(`CREATE TABLE "owned_nft" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "video_id" character varying NOT NULL, "owner" jsonb NOT NULL, "transactional_status" jsonb, "creator_royalty" numeric, "last_sale_price" numeric, "last_sale_date" TIMESTAMP WITH TIME ZONE, "is_featured" boolean NOT NULL, CONSTRAINT "OwnedNft_video" UNIQUE ("video_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_466896e39b9ec953f4f2545622" UNIQUE ("video_id"), CONSTRAINT "PK_5e0c289b350e863668fff44bb56" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_8c7201ed7d4765dcbcc3609356" ON "owned_nft" ("created_at") `) - await db.query(`CREATE INDEX "IDX_466896e39b9ec953f4f2545622" ON "owned_nft" ("video_id") `) - await db.query(`CREATE TABLE "auction" ("id" character varying NOT NULL, "nft_id" character varying, "winning_member_id" character varying, "starting_price" numeric NOT NULL, "buy_now_price" numeric, "auction_type" jsonb NOT NULL, "top_bid_id" character varying, "starts_at_block" integer NOT NULL, "ended_at_block" integer, "is_canceled" boolean NOT NULL, "is_completed" boolean NOT NULL, CONSTRAINT "PK_9dc876c629273e71646cf6dfa67" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_cfb47e97e60c9d1462576f85a8" ON "auction" ("nft_id") `) - await db.query(`CREATE INDEX "IDX_a3127ec87cccc5696b92cac4e0" ON "auction" ("winning_member_id") `) - await db.query(`CREATE INDEX "IDX_1673ad4b059742fbabfc40b275" ON "auction" ("top_bid_id") `) - await db.query(`CREATE TABLE "auction_whitelisted_member" ("id" character varying NOT NULL, "auction_id" character varying, "member_id" character varying, CONSTRAINT "AuctionWhitelistedMember_auction_member" UNIQUE ("auction_id", "member_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_f20264ca8e878696fbc25f11bd5" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_d5ae4854487c7658b64225be30" ON "auction_whitelisted_member" ("member_id") `) - await db.query(`CREATE INDEX "IDX_5468573a96fa51c03743de5912" ON "auction_whitelisted_member" ("auction_id", "member_id") `) - await db.query(`CREATE TABLE "membership" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "handle" text NOT NULL, "handle_raw" text NOT NULL, "controller_account" text NOT NULL, "total_channels_created" integer NOT NULL, CONSTRAINT "Membership_handleRaw" UNIQUE ("handle_raw") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_83c1afebef3059472e7c37e8de8" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_0c5b879f9f2ca57a774f74f7f0" ON "membership" ("handle_raw") `) - await db.query(`CREATE TABLE "event" ("id" character varying NOT NULL, "in_block" integer NOT NULL, "in_extrinsic" text, "index_in_block" integer NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "data" jsonb NOT NULL, CONSTRAINT "PK_30c2f3bbaf6d34a55f8ae6e4614" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_8f3f220c4e717207d841d4e6d4" ON "event" ("in_extrinsic") `) - await db.query(`CREATE INDEX "IDX_2c15918ff289396205521c5f3c" ON "event" ("timestamp") `) - await db.query(`CREATE TABLE "notification" ("id" character varying NOT NULL, "account_id" character varying, "notification_type" jsonb NOT NULL, "event_id" character varying, "status" jsonb NOT NULL, "in_app" boolean NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "recipient" jsonb NOT NULL, CONSTRAINT "PK_705b6c7cdf9b2c2ff7ac7872cb7" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_6bfa96ab97f1a09d73091294ef" ON "notification" ("account_id") `) - await db.query(`CREATE INDEX "IDX_122be1f0696e0255acf95f9e33" ON "notification" ("event_id") `) - await db.query(`CREATE TABLE "account" ("id" character varying NOT NULL, "user_id" character varying NOT NULL, "email" text NOT NULL, "is_email_confirmed" boolean NOT NULL, "is_blocked" boolean NOT NULL, "registered_at" TIMESTAMP WITH TIME ZONE NOT NULL, "membership_id" character varying NOT NULL, "joystream_account" text NOT NULL, "notification_preferences" jsonb NOT NULL, "referrer_channel_id" text, CONSTRAINT "Account_joystreamAccount" UNIQUE ("joystream_account") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "Account_membership" UNIQUE ("membership_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "Account_email" UNIQUE ("email") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "Account_user" UNIQUE ("user_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_efef1e5fdbe318a379c06678c5" UNIQUE ("user_id"), CONSTRAINT "REL_601b93655bcbe73cb58d8c80cd" UNIQUE ("membership_id"), CONSTRAINT "PK_54115ee388cdb6d86bb4bf5b2ea" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_efef1e5fdbe318a379c06678c5" ON "account" ("user_id") `) - await db.query(`CREATE INDEX "IDX_4c8f96ccf523e9a3faefd5bdd4" ON "account" ("email") `) - await db.query(`CREATE INDEX "IDX_601b93655bcbe73cb58d8c80cd" ON "account" ("membership_id") `) - await db.query(`CREATE INDEX "IDX_df4da05a7a80c1afd18b8f0990" ON "account" ("joystream_account") `) - await db.query(`CREATE TABLE "encryption_artifacts" ("id" character varying NOT NULL, "account_id" character varying NOT NULL, "cipher_iv" text NOT NULL, "encrypted_seed" text NOT NULL, CONSTRAINT "EncryptionArtifacts_account" UNIQUE ("account_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_ec8f68a544aadc4fbdadefe4a0" UNIQUE ("account_id"), CONSTRAINT "PK_6441471581ba6d149ad75655bd0" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_ec8f68a544aadc4fbdadefe4a0" ON "encryption_artifacts" ("account_id") `) - await db.query(`CREATE TABLE "session" ("id" character varying NOT NULL, "browser" text NOT NULL, "os" text NOT NULL, "device" text NOT NULL, "device_type" text, "user_id" character varying, "account_id" character varying, "ip" text NOT NULL, "started_at" TIMESTAMP WITH TIME ZONE NOT NULL, "expiry" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_f55da76ac1c3ac420f444d2ff11" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_30e98e8746699fb9af235410af" ON "session" ("user_id") `) - await db.query(`CREATE INDEX "IDX_fae5a6b4a57f098e9af8520d49" ON "session" ("account_id") `) - await db.query(`CREATE INDEX "IDX_213b5a19bfdbe0ab6e06b1dede" ON "session" ("ip") `) - await db.query(`CREATE TABLE "session_encryption_artifacts" ("id" character varying NOT NULL, "session_id" character varying NOT NULL, "cipher_iv" text NOT NULL, "cipher_key" text NOT NULL, CONSTRAINT "SessionEncryptionArtifacts_session" UNIQUE ("session_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_3612880efd8926a17eba5ab0e1" UNIQUE ("session_id"), CONSTRAINT "PK_e328da2643599e265a848219885" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_3612880efd8926a17eba5ab0e1" ON "session_encryption_artifacts" ("session_id") `) - await db.query(`CREATE TABLE "token" ("id" character varying NOT NULL, "type" character varying(18) NOT NULL, "issued_at" TIMESTAMP WITH TIME ZONE NOT NULL, "expiry" TIMESTAMP WITH TIME ZONE NOT NULL, "issued_for_id" character varying, CONSTRAINT "PK_82fae97f905930df5d62a702fc9" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_a6fe18c105f85a63d761ccb078" ON "token" ("issued_for_id") `) - await db.query(`CREATE TABLE "nft_history_entry" ("id" character varying NOT NULL, "nft_id" character varying, "event_id" character varying, CONSTRAINT "PK_9018e80b335a965a54959c4c6e2" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_57f51d35ecab042478fe2e31c1" ON "nft_history_entry" ("nft_id") `) - await db.query(`CREATE INDEX "IDX_d1a28b178f5d028d048d40ce20" ON "nft_history_entry" ("event_id") `) - await db.query(`CREATE TABLE "nft_activity" ("id" character varying NOT NULL, "member_id" character varying, "event_id" character varying, CONSTRAINT "PK_1553b1bbf8000039875a6e31536" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_18a65713a9fd0715c7a980f5d5" ON "nft_activity" ("member_id") `) - await db.query(`CREATE INDEX "IDX_94d325a753f2c08fdd416eb095" ON "nft_activity" ("event_id") `) - await db.query(`CREATE TABLE "email_delivery_attempt" ("id" character varying NOT NULL, "notification_delivery_id" character varying, "status" jsonb NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_876948339083a2f1092245f7a32" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_f985b9b362249af72cac0f52a3" ON "email_delivery_attempt" ("notification_delivery_id") `) - await db.query(`CREATE TABLE "notification_email_delivery" ("id" character varying NOT NULL, "notification_id" character varying, "discard" boolean NOT NULL, CONSTRAINT "PK_60dc7ff42a7abf7b0d44bf60516" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_3b756627c3146db150d66d1292" ON "notification_email_delivery" ("notification_id") `) - await db.query(`CREATE TABLE "video_hero" ("id" character varying NOT NULL, "video_id" character varying, "hero_title" text NOT NULL, "hero_video_cut_url" text NOT NULL, "hero_poster_url" text NOT NULL, "activated_at" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_f3b63979879773378afac0b9495" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_9feac5d9713a9f07e32eb8ba7a" ON "video_hero" ("video_id") `) - await db.query(`CREATE TABLE "video_media_encoding" ("id" character varying NOT NULL, "codec_name" text, "container" text, "mime_media_type" text, CONSTRAINT "PK_52e25874f8d8a381e154d1125e0" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "video_media_metadata" ("id" character varying NOT NULL, "encoding_id" character varying, "pixel_width" integer, "pixel_height" integer, "size" numeric, "video_id" character varying NOT NULL, "created_in_block" integer NOT NULL, CONSTRAINT "VideoMediaMetadata_video" UNIQUE ("video_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_4dc101240e8e1536b770aee202" UNIQUE ("video_id"), CONSTRAINT "PK_86a13815734e589cd86d0465e2d" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_5944dc5896cb16bd395414a0ce" ON "video_media_metadata" ("encoding_id") `) - await db.query(`CREATE INDEX "IDX_4dc101240e8e1536b770aee202" ON "video_media_metadata" ("video_id") `) - await db.query(`CREATE TABLE "gateway_config" ("id" character varying NOT NULL, "value" text NOT NULL, "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_db1fa5a857fb6292eee4c493e6f" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "exclusion" ("id" character varying NOT NULL, "channel_id" text, "video_id" text, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "rationale" text NOT NULL, CONSTRAINT "PK_7f8dcde2e607a96d66dce002e74" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_efba55b85909822c2b7655dfb8" ON "exclusion" ("channel_id") `) - await db.query(`CREATE INDEX "IDX_2729041b2f528a6c5833fdb3e5" ON "exclusion" ("video_id") `) - await db.query(`CREATE TABLE "storage_bucket_operator_metadata" ("id" character varying NOT NULL, "storage_bucket_id" character varying NOT NULL, "node_endpoint" text, "node_location" jsonb, "extra" text, CONSTRAINT "StorageBucketOperatorMetadata_storageBucket" UNIQUE ("storage_bucket_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_7beffc9530b3f307bc1169cb52" UNIQUE ("storage_bucket_id"), CONSTRAINT "PK_9846a397400ae1a39b21fbd02d4" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_7beffc9530b3f307bc1169cb52" ON "storage_bucket_operator_metadata" ("storage_bucket_id") `) - await db.query(`CREATE TABLE "distribution_bucket_family_metadata" ("id" character varying NOT NULL, "family_id" character varying NOT NULL, "region" text, "description" text, "areas" jsonb, "latency_test_targets" text array, CONSTRAINT "DistributionBucketFamilyMetadata_family" UNIQUE ("family_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_dd93ca0ea24f3e7a02f11c4c14" UNIQUE ("family_id"), CONSTRAINT "PK_df7a270835bb313d3ef17bdee2f" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_dd93ca0ea24f3e7a02f11c4c14" ON "distribution_bucket_family_metadata" ("family_id") `) - await db.query(`CREATE INDEX "IDX_5510d3b244a63d6ec702faa426" ON "distribution_bucket_family_metadata" ("region") `) - await db.query(`CREATE TABLE "distribution_bucket_operator_metadata" ("id" character varying NOT NULL, "distirbution_bucket_operator_id" character varying NOT NULL, "node_endpoint" text, "node_location" jsonb, "extra" text, CONSTRAINT "DistributionBucketOperatorMetadata_distirbutionBucketOperator" UNIQUE ("distirbution_bucket_operator_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_69ec9bdc975b95f7dff94a7106" UNIQUE ("distirbution_bucket_operator_id"), CONSTRAINT "PK_9bbecaa12f30e3826922688274f" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_69ec9bdc975b95f7dff94a7106" ON "distribution_bucket_operator_metadata" ("distirbution_bucket_operator_id") `) - await db.query(`CREATE TABLE "channel_verification" ("id" character varying NOT NULL, "channel_id" character varying, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_0a61c78b114ed3e92300e09afaa" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_f13d5d785670f46de668575139" ON "channel_verification" ("channel_id") `) - await db.query(`CREATE TABLE "channel_suspension" ("id" character varying NOT NULL, "channel_id" character varying, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_226679cee9a8d0e5af18f70a1da" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_e30ebff1042c010ff88b87f4f7" ON "channel_suspension" ("channel_id") `) - await db.query(`CREATE TABLE "curator_group" ("id" character varying NOT NULL, "is_active" boolean NOT NULL, CONSTRAINT "PK_0b4c0ab279d72bcbf4e16b65ff1" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "curator" ("id" character varying NOT NULL, CONSTRAINT "PK_5791051a62d2c2dfc593d38ab57" PRIMARY KEY ("id"))`) - await db.query(`CREATE TABLE "member_metadata" ("id" character varying NOT NULL, "name" text, "avatar" jsonb, "about" text, "member_id" character varying NOT NULL, CONSTRAINT "MemberMetadata_member" UNIQUE ("member_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_e7e4d350f82ae2383894f465ed" UNIQUE ("member_id"), CONSTRAINT "PK_d3fcc374696465f3c0ac3ba8708" PRIMARY KEY ("id"))`) - await db.query(`CREATE INDEX "IDX_e7e4d350f82ae2383894f465ed" ON "member_metadata" ("member_id") `) - await db.query(`CREATE TABLE "next_entity_id" ("entity_name" character varying NOT NULL, "next_id" bigint NOT NULL, CONSTRAINT "PK_09a3b40db622a65096e7344d7ae" PRIMARY KEY ("entity_name"))`) - await db.query(`ALTER TABLE "channel_follow" ADD CONSTRAINT "FK_822778b4b1ea8e3b60b127cb8b1" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_view_event" ADD CONSTRAINT "FK_31e1e798ec387ad905cf98d33b0" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "report" ADD CONSTRAINT "FK_c6686efa4cd49fa9a429f01bac8" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "nft_featuring_request" ADD CONSTRAINT "FK_519be2a41216c278c35f254dcba" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "storage_bucket_bag" ADD CONSTRAINT "FK_791e2f82e3919ffcef8712aa1b9" FOREIGN KEY ("storage_bucket_id") REFERENCES "storage_bucket"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "storage_bucket_bag" ADD CONSTRAINT "FK_aaf00b2c7d0cba49f97da14fbba" FOREIGN KEY ("bag_id") REFERENCES "storage_bag"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "distribution_bucket_operator" ADD CONSTRAINT "FK_678dc5427cdde0cd4fef2c07a43" FOREIGN KEY ("distribution_bucket_id") REFERENCES "distribution_bucket"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "distribution_bucket" ADD CONSTRAINT "FK_8cb7454d1ec34b0d3bb7ecdee4e" FOREIGN KEY ("family_id") REFERENCES "distribution_bucket_family"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "distribution_bucket_bag" ADD CONSTRAINT "FK_8a807921f1aae60d4ba94895826" FOREIGN KEY ("distribution_bucket_id") REFERENCES "distribution_bucket"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "distribution_bucket_bag" ADD CONSTRAINT "FK_a9810100aee7584680f197c8ff0" FOREIGN KEY ("bag_id") REFERENCES "storage_bag"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "storage_data_object" ADD CONSTRAINT "FK_ff8014300b8039dbaed764f51bc" FOREIGN KEY ("storage_bag_id") REFERENCES "storage_bag"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "banned_member" ADD CONSTRAINT "FK_b94ea874da235d9b6fbc35cf58e" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "banned_member" ADD CONSTRAINT "FK_ed36c6c26bf5410796c2fc21f74" FOREIGN KEY ("channel_id") REFERENCES "channel"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "app" ADD CONSTRAINT "FK_c9cc395bbc485f70a15be64553e" FOREIGN KEY ("owner_member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "channel" ADD CONSTRAINT "FK_25c85bc448b5e236a4c1a5f7895" FOREIGN KEY ("owner_member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "channel" ADD CONSTRAINT "FK_a77e12f3d8c6ced020e179a5e94" FOREIGN KEY ("cover_photo_id") REFERENCES "storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "channel" ADD CONSTRAINT "FK_6997e94413b3f2f25a84e4a96f8" FOREIGN KEY ("avatar_photo_id") REFERENCES "storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "channel" ADD CONSTRAINT "FK_118ecfa0199aeb5a014906933e8" FOREIGN KEY ("entry_app_id") REFERENCES "app"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_featured_in_category" ADD CONSTRAINT "FK_7b16ddad43901921a8d3c8eab71" FOREIGN KEY ("video_id") REFERENCES "video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_featured_in_category" ADD CONSTRAINT "FK_0e6bb49ce9d022cd872f3ab4288" FOREIGN KEY ("category_id") REFERENCES "video_category"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_category" ADD CONSTRAINT "FK_da26b34f037c0d59d3c0d0646e9" FOREIGN KEY ("parent_category_id") REFERENCES "video_category"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_subtitle" ADD CONSTRAINT "FK_2203674f18d8052ed6bac396252" FOREIGN KEY ("video_id") REFERENCES "video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_subtitle" ADD CONSTRAINT "FK_b6eabfb8de4128b28d73681020f" FOREIGN KEY ("asset_id") REFERENCES "storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "comment_reaction" ADD CONSTRAINT "FK_15080d9fb7cf8b563103dd9d900" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "comment_reaction" ADD CONSTRAINT "FK_962582f04d3f639e33f43c54bbc" FOREIGN KEY ("comment_id") REFERENCES "comment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "comment_reaction" ADD CONSTRAINT "FK_d7995b1d57614a6fbd0c103874d" FOREIGN KEY ("video_id") REFERENCES "video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "comment" ADD CONSTRAINT "FK_3ce66469b26697baa097f8da923" FOREIGN KEY ("author_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "comment" ADD CONSTRAINT "FK_1ff03403fd31dfeaba0623a89cf" FOREIGN KEY ("video_id") REFERENCES "video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "comment" ADD CONSTRAINT "FK_ac69bddf8202b7c0752d9dc8f32" FOREIGN KEY ("parent_comment_id") REFERENCES "comment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_reaction" ADD CONSTRAINT "FK_73dda64f53bbc7ec7035d5e7f09" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_reaction" ADD CONSTRAINT "FK_436a3836eb47acb5e1e3c88ddea" FOREIGN KEY ("video_id") REFERENCES "video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video" ADD CONSTRAINT "FK_81b11ef99a9db9ef1aed040d750" FOREIGN KEY ("channel_id") REFERENCES "channel"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video" ADD CONSTRAINT "FK_2a5c61f32e9636ee10821e9a58d" FOREIGN KEY ("category_id") REFERENCES "video_category"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video" ADD CONSTRAINT "FK_8530d052cc79b420f7ce2b4e09d" FOREIGN KEY ("thumbnail_photo_id") REFERENCES "storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video" ADD CONSTRAINT "FK_3ec633ae5d0477f512b4ed957d6" FOREIGN KEY ("license_id") REFERENCES "license"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video" ADD CONSTRAINT "FK_2db879ed42e3308fe65e6796729" FOREIGN KEY ("media_id") REFERENCES "storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video" ADD CONSTRAINT "FK_54f88a7decf7d22fd9bd9fa439a" FOREIGN KEY ("pinned_comment_id") REFERENCES "comment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video" ADD CONSTRAINT "FK_6c49ad08c44d36d11f77c426e43" FOREIGN KEY ("entry_app_id") REFERENCES "app"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "bid" ADD CONSTRAINT "FK_9e594e5a61c0f3cb25679f6ba8d" FOREIGN KEY ("auction_id") REFERENCES "auction"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "bid" ADD CONSTRAINT "FK_3caf2d6b31d2fe45a2b85b81912" FOREIGN KEY ("nft_id") REFERENCES "owned_nft"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "bid" ADD CONSTRAINT "FK_e7618559409a903a897164156b7" FOREIGN KEY ("bidder_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "bid" ADD CONSTRAINT "FK_32cb73025ec49c87f4c594a265f" FOREIGN KEY ("previous_top_bid_id") REFERENCES "bid"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "owned_nft" ADD CONSTRAINT "FK_466896e39b9ec953f4f2545622d" FOREIGN KEY ("video_id") REFERENCES "video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "auction" ADD CONSTRAINT "FK_cfb47e97e60c9d1462576f85a88" FOREIGN KEY ("nft_id") REFERENCES "owned_nft"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "auction" ADD CONSTRAINT "FK_a3127ec87cccc5696b92cac4e09" FOREIGN KEY ("winning_member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "auction" ADD CONSTRAINT "FK_1673ad4b059742fbabfc40b275c" FOREIGN KEY ("top_bid_id") REFERENCES "bid"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "auction_whitelisted_member" ADD CONSTRAINT "FK_aad797677bc7c7c7dc1f1d397f5" FOREIGN KEY ("auction_id") REFERENCES "auction"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "auction_whitelisted_member" ADD CONSTRAINT "FK_d5ae4854487c7658b64225be305" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_6bfa96ab97f1a09d73091294efc" FOREIGN KEY ("account_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_122be1f0696e0255acf95f9e336" FOREIGN KEY ("event_id") REFERENCES "event"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "account" ADD CONSTRAINT "FK_efef1e5fdbe318a379c06678c51" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "account" ADD CONSTRAINT "FK_601b93655bcbe73cb58d8c80cd3" FOREIGN KEY ("membership_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "encryption_artifacts" ADD CONSTRAINT "FK_ec8f68a544aadc4fbdadefe4a0a" FOREIGN KEY ("account_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "session" ADD CONSTRAINT "FK_30e98e8746699fb9af235410aff" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "session" ADD CONSTRAINT "FK_fae5a6b4a57f098e9af8520d499" FOREIGN KEY ("account_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "session_encryption_artifacts" ADD CONSTRAINT "FK_3612880efd8926a17eba5ab0e1a" FOREIGN KEY ("session_id") REFERENCES "session"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "token" ADD CONSTRAINT "FK_a6fe18c105f85a63d761ccb0780" FOREIGN KEY ("issued_for_id") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "nft_history_entry" ADD CONSTRAINT "FK_57f51d35ecab042478fe2e31c19" FOREIGN KEY ("nft_id") REFERENCES "owned_nft"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "nft_history_entry" ADD CONSTRAINT "FK_d1a28b178f5d028d048d40ce208" FOREIGN KEY ("event_id") REFERENCES "event"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "nft_activity" ADD CONSTRAINT "FK_18a65713a9fd0715c7a980f5d54" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "nft_activity" ADD CONSTRAINT "FK_94d325a753f2c08fdd416eb095f" FOREIGN KEY ("event_id") REFERENCES "event"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "email_delivery_attempt" ADD CONSTRAINT "FK_f985b9b362249af72cac0f52a3b" FOREIGN KEY ("notification_delivery_id") REFERENCES "notification_email_delivery"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "notification_email_delivery" ADD CONSTRAINT "FK_3b756627c3146db150d66d12929" FOREIGN KEY ("notification_id") REFERENCES "notification"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_hero" ADD CONSTRAINT "FK_9feac5d9713a9f07e32eb8ba7a1" FOREIGN KEY ("video_id") REFERENCES "video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_media_metadata" ADD CONSTRAINT "FK_5944dc5896cb16bd395414a0ce0" FOREIGN KEY ("encoding_id") REFERENCES "video_media_encoding"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "video_media_metadata" ADD CONSTRAINT "FK_4dc101240e8e1536b770aee202a" FOREIGN KEY ("video_id") REFERENCES "video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "storage_bucket_operator_metadata" ADD CONSTRAINT "FK_7beffc9530b3f307bc1169cb524" FOREIGN KEY ("storage_bucket_id") REFERENCES "storage_bucket"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "distribution_bucket_family_metadata" ADD CONSTRAINT "FK_dd93ca0ea24f3e7a02f11c4c149" FOREIGN KEY ("family_id") REFERENCES "distribution_bucket_family"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "distribution_bucket_operator_metadata" ADD CONSTRAINT "FK_69ec9bdc975b95f7dff94a71069" FOREIGN KEY ("distirbution_bucket_operator_id") REFERENCES "distribution_bucket_operator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "channel_verification" ADD CONSTRAINT "FK_f13d5d785670f46de668575139c" FOREIGN KEY ("channel_id") REFERENCES "channel"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "channel_suspension" ADD CONSTRAINT "FK_e30ebff1042c010ff88b87f4f7a" FOREIGN KEY ("channel_id") REFERENCES "channel"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - await db.query(`ALTER TABLE "member_metadata" ADD CONSTRAINT "FK_e7e4d350f82ae2383894f465ede" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) - } - - async down(db) { - await db.query(`DROP TABLE "channel_follow"`) - await db.query(`DROP INDEX "public"."IDX_822778b4b1ea8e3b60b127cb8b"`) - await db.query(`DROP INDEX "public"."IDX_9bc0651dda94437ec18764a260"`) - await db.query(`DROP TABLE "video_view_event"`) - await db.query(`DROP INDEX "public"."IDX_2e29fba63e12a2b1818e0782d7"`) - await db.query(`DROP INDEX "public"."IDX_31e1e798ec387ad905cf98d33b"`) - await db.query(`DROP TABLE "report"`) - await db.query(`DROP INDEX "public"."IDX_c6686efa4cd49fa9a429f01bac"`) - await db.query(`DROP INDEX "public"."IDX_893057921f4b5cc37a0ef36684"`) - await db.query(`DROP INDEX "public"."IDX_f732b6f82095a935db68c9491f"`) - await db.query(`DROP TABLE "nft_featuring_request"`) - await db.query(`DROP INDEX "public"."IDX_519be2a41216c278c35f254dcb"`) - await db.query(`DROP INDEX "public"."IDX_76d87e26cce72ac2e7ffa28dfb"`) - await db.query(`DROP TABLE "user"`) - await db.query(`DROP TABLE "storage_bucket"`) - await db.query(`DROP TABLE "storage_bucket_bag"`) - await db.query(`DROP INDEX "public"."IDX_aaf00b2c7d0cba49f97da14fbb"`) - await db.query(`DROP INDEX "public"."IDX_4c475f6c9300284b095859eec3"`) - await db.query(`DROP TABLE "distribution_bucket_family"`) - await db.query(`DROP TABLE "distribution_bucket_operator"`) - await db.query(`DROP INDEX "public"."IDX_678dc5427cdde0cd4fef2c07a4"`) - await db.query(`DROP TABLE "distribution_bucket"`) - await db.query(`DROP INDEX "public"."IDX_8cb7454d1ec34b0d3bb7ecdee4"`) - await db.query(`DROP TABLE "distribution_bucket_bag"`) - await db.query(`DROP INDEX "public"."IDX_a9810100aee7584680f197c8ff"`) - await db.query(`DROP INDEX "public"."IDX_32e552d352848d64ab82d38e9a"`) - await db.query(`DROP TABLE "storage_bag"`) - await db.query(`DROP TABLE "storage_data_object"`) - await db.query(`DROP INDEX "public"."IDX_ff8014300b8039dbaed764f51b"`) - await db.query(`DROP TABLE "banned_member"`) - await db.query(`DROP INDEX "public"."IDX_ed36c6c26bf5410796c2fc21f7"`) - await db.query(`DROP INDEX "public"."IDX_f29ff095bdb945975deca021ad"`) - await db.query(`DROP TABLE "app"`) - await db.query(`DROP INDEX "public"."IDX_f36adbb7b096ceeb6f3e80ad14"`) - await db.query(`DROP INDEX "public"."IDX_c9cc395bbc485f70a15be64553"`) - await db.query(`DROP TABLE "channel"`) - await db.query(`DROP INDEX "public"."IDX_a4752a0a0899dedc4d18077dd0"`) - await db.query(`DROP INDEX "public"."IDX_25c85bc448b5e236a4c1a5f789"`) - await db.query(`DROP INDEX "public"."IDX_a77e12f3d8c6ced020e179a5e9"`) - await db.query(`DROP INDEX "public"."IDX_6997e94413b3f2f25a84e4a96f"`) - await db.query(`DROP INDEX "public"."IDX_e58a2e1d78b8eccf40531a7fdb"`) - await db.query(`DROP INDEX "public"."IDX_118ecfa0199aeb5a014906933e"`) - await db.query(`DROP TABLE "video_featured_in_category"`) - await db.query(`DROP INDEX "public"."IDX_7b16ddad43901921a8d3c8eab7"`) - await db.query(`DROP INDEX "public"."IDX_6d0917e1ac0cc06c8075bcf256"`) - await db.query(`DROP TABLE "video_category"`) - await db.query(`DROP INDEX "public"."IDX_cbe7e5d162a819e4ee2e2f6105"`) - await db.query(`DROP INDEX "public"."IDX_da26b34f037c0d59d3c0d0646e"`) - await db.query(`DROP TABLE "license"`) - await db.query(`DROP TABLE "video_subtitle"`) - await db.query(`DROP INDEX "public"."IDX_2203674f18d8052ed6bac39625"`) - await db.query(`DROP INDEX "public"."IDX_ffa63c28188eecc32af921bfc3"`) - await db.query(`DROP INDEX "public"."IDX_b6eabfb8de4128b28d73681020"`) - await db.query(`DROP TABLE "comment_reaction"`) - await db.query(`DROP INDEX "public"."IDX_15080d9fb7cf8b563103dd9d90"`) - await db.query(`DROP INDEX "public"."IDX_962582f04d3f639e33f43c54bb"`) - await db.query(`DROP INDEX "public"."IDX_d7995b1d57614a6fbd0c103874"`) - await db.query(`DROP TABLE "comment"`) - await db.query(`DROP INDEX "public"."IDX_3ce66469b26697baa097f8da92"`) - await db.query(`DROP INDEX "public"."IDX_1ff03403fd31dfeaba0623a89c"`) - await db.query(`DROP INDEX "public"."IDX_c3c2abe750c76c7c8e305f71f2"`) - await db.query(`DROP INDEX "public"."IDX_ac69bddf8202b7c0752d9dc8f3"`) - await db.query(`DROP TABLE "video_reaction"`) - await db.query(`DROP INDEX "public"."IDX_73dda64f53bbc7ec7035d5e7f0"`) - await db.query(`DROP INDEX "public"."IDX_436a3836eb47acb5e1e3c88dde"`) - await db.query(`DROP TABLE "video"`) - await db.query(`DROP INDEX "public"."IDX_fe2b4b6aace15f1b6610830846"`) - await db.query(`DROP INDEX "public"."IDX_81b11ef99a9db9ef1aed040d75"`) - await db.query(`DROP INDEX "public"."IDX_2a5c61f32e9636ee10821e9a58"`) - await db.query(`DROP INDEX "public"."IDX_8530d052cc79b420f7ce2b4e09"`) - await db.query(`DROP INDEX "public"."IDX_57b335fa0a960877caf6d2fc29"`) - await db.query(`DROP INDEX "public"."IDX_3ec633ae5d0477f512b4ed957d"`) - await db.query(`DROP INDEX "public"."IDX_2db879ed42e3308fe65e679672"`) - await db.query(`DROP INDEX "public"."IDX_54f88a7decf7d22fd9bd9fa439"`) - await db.query(`DROP INDEX "public"."IDX_6c49ad08c44d36d11f77c426e4"`) - await db.query(`DROP INDEX "public"."IDX_f33816960d690ac836f5d5c28a"`) - await db.query(`DROP TABLE "bid"`) - await db.query(`DROP INDEX "public"."IDX_9e594e5a61c0f3cb25679f6ba8"`) - await db.query(`DROP INDEX "public"."IDX_3caf2d6b31d2fe45a2b85b8191"`) - await db.query(`DROP INDEX "public"."IDX_e7618559409a903a897164156b"`) - await db.query(`DROP INDEX "public"."IDX_32cb73025ec49c87f4c594a265"`) - await db.query(`DROP TABLE "owned_nft"`) - await db.query(`DROP INDEX "public"."IDX_8c7201ed7d4765dcbcc3609356"`) - await db.query(`DROP INDEX "public"."IDX_466896e39b9ec953f4f2545622"`) - await db.query(`DROP TABLE "auction"`) - await db.query(`DROP INDEX "public"."IDX_cfb47e97e60c9d1462576f85a8"`) - await db.query(`DROP INDEX "public"."IDX_a3127ec87cccc5696b92cac4e0"`) - await db.query(`DROP INDEX "public"."IDX_1673ad4b059742fbabfc40b275"`) - await db.query(`DROP TABLE "auction_whitelisted_member"`) - await db.query(`DROP INDEX "public"."IDX_d5ae4854487c7658b64225be30"`) - await db.query(`DROP INDEX "public"."IDX_5468573a96fa51c03743de5912"`) - await db.query(`DROP TABLE "membership"`) - await db.query(`DROP INDEX "public"."IDX_0c5b879f9f2ca57a774f74f7f0"`) - await db.query(`DROP TABLE "event"`) - await db.query(`DROP INDEX "public"."IDX_8f3f220c4e717207d841d4e6d4"`) - await db.query(`DROP INDEX "public"."IDX_2c15918ff289396205521c5f3c"`) - await db.query(`DROP TABLE "notification"`) - await db.query(`DROP INDEX "public"."IDX_6bfa96ab97f1a09d73091294ef"`) - await db.query(`DROP INDEX "public"."IDX_122be1f0696e0255acf95f9e33"`) - await db.query(`DROP TABLE "account"`) - await db.query(`DROP INDEX "public"."IDX_efef1e5fdbe318a379c06678c5"`) - await db.query(`DROP INDEX "public"."IDX_4c8f96ccf523e9a3faefd5bdd4"`) - await db.query(`DROP INDEX "public"."IDX_601b93655bcbe73cb58d8c80cd"`) - await db.query(`DROP INDEX "public"."IDX_df4da05a7a80c1afd18b8f0990"`) - await db.query(`DROP TABLE "encryption_artifacts"`) - await db.query(`DROP INDEX "public"."IDX_ec8f68a544aadc4fbdadefe4a0"`) - await db.query(`DROP TABLE "session"`) - await db.query(`DROP INDEX "public"."IDX_30e98e8746699fb9af235410af"`) - await db.query(`DROP INDEX "public"."IDX_fae5a6b4a57f098e9af8520d49"`) - await db.query(`DROP INDEX "public"."IDX_213b5a19bfdbe0ab6e06b1dede"`) - await db.query(`DROP TABLE "session_encryption_artifacts"`) - await db.query(`DROP INDEX "public"."IDX_3612880efd8926a17eba5ab0e1"`) - await db.query(`DROP TABLE "token"`) - await db.query(`DROP INDEX "public"."IDX_a6fe18c105f85a63d761ccb078"`) - await db.query(`DROP TABLE "nft_history_entry"`) - await db.query(`DROP INDEX "public"."IDX_57f51d35ecab042478fe2e31c1"`) - await db.query(`DROP INDEX "public"."IDX_d1a28b178f5d028d048d40ce20"`) - await db.query(`DROP TABLE "nft_activity"`) - await db.query(`DROP INDEX "public"."IDX_18a65713a9fd0715c7a980f5d5"`) - await db.query(`DROP INDEX "public"."IDX_94d325a753f2c08fdd416eb095"`) - await db.query(`DROP TABLE "email_delivery_attempt"`) - await db.query(`DROP INDEX "public"."IDX_f985b9b362249af72cac0f52a3"`) - await db.query(`DROP TABLE "notification_email_delivery"`) - await db.query(`DROP INDEX "public"."IDX_3b756627c3146db150d66d1292"`) - await db.query(`DROP TABLE "video_hero"`) - await db.query(`DROP INDEX "public"."IDX_9feac5d9713a9f07e32eb8ba7a"`) - await db.query(`DROP TABLE "video_media_encoding"`) - await db.query(`DROP TABLE "video_media_metadata"`) - await db.query(`DROP INDEX "public"."IDX_5944dc5896cb16bd395414a0ce"`) - await db.query(`DROP INDEX "public"."IDX_4dc101240e8e1536b770aee202"`) - await db.query(`DROP TABLE "gateway_config"`) - await db.query(`DROP TABLE "exclusion"`) - await db.query(`DROP INDEX "public"."IDX_efba55b85909822c2b7655dfb8"`) - await db.query(`DROP INDEX "public"."IDX_2729041b2f528a6c5833fdb3e5"`) - await db.query(`DROP TABLE "storage_bucket_operator_metadata"`) - await db.query(`DROP INDEX "public"."IDX_7beffc9530b3f307bc1169cb52"`) - await db.query(`DROP TABLE "distribution_bucket_family_metadata"`) - await db.query(`DROP INDEX "public"."IDX_dd93ca0ea24f3e7a02f11c4c14"`) - await db.query(`DROP INDEX "public"."IDX_5510d3b244a63d6ec702faa426"`) - await db.query(`DROP TABLE "distribution_bucket_operator_metadata"`) - await db.query(`DROP INDEX "public"."IDX_69ec9bdc975b95f7dff94a7106"`) - await db.query(`DROP TABLE "channel_verification"`) - await db.query(`DROP INDEX "public"."IDX_f13d5d785670f46de668575139"`) - await db.query(`DROP TABLE "channel_suspension"`) - await db.query(`DROP INDEX "public"."IDX_e30ebff1042c010ff88b87f4f7"`) - await db.query(`DROP TABLE "curator_group"`) - await db.query(`DROP TABLE "curator"`) - await db.query(`DROP TABLE "member_metadata"`) - await db.query(`DROP INDEX "public"."IDX_e7e4d350f82ae2383894f465ed"`) - await db.query(`DROP TABLE "next_entity_id"`) - await db.query(`ALTER TABLE "channel_follow" DROP CONSTRAINT "FK_822778b4b1ea8e3b60b127cb8b1"`) - await db.query(`ALTER TABLE "video_view_event" DROP CONSTRAINT "FK_31e1e798ec387ad905cf98d33b0"`) - await db.query(`ALTER TABLE "report" DROP CONSTRAINT "FK_c6686efa4cd49fa9a429f01bac8"`) - await db.query(`ALTER TABLE "nft_featuring_request" DROP CONSTRAINT "FK_519be2a41216c278c35f254dcba"`) - await db.query(`ALTER TABLE "storage_bucket_bag" DROP CONSTRAINT "FK_791e2f82e3919ffcef8712aa1b9"`) - await db.query(`ALTER TABLE "storage_bucket_bag" DROP CONSTRAINT "FK_aaf00b2c7d0cba49f97da14fbba"`) - await db.query(`ALTER TABLE "distribution_bucket_operator" DROP CONSTRAINT "FK_678dc5427cdde0cd4fef2c07a43"`) - await db.query(`ALTER TABLE "distribution_bucket" DROP CONSTRAINT "FK_8cb7454d1ec34b0d3bb7ecdee4e"`) - await db.query(`ALTER TABLE "distribution_bucket_bag" DROP CONSTRAINT "FK_8a807921f1aae60d4ba94895826"`) - await db.query(`ALTER TABLE "distribution_bucket_bag" DROP CONSTRAINT "FK_a9810100aee7584680f197c8ff0"`) - await db.query(`ALTER TABLE "storage_data_object" DROP CONSTRAINT "FK_ff8014300b8039dbaed764f51bc"`) - await db.query(`ALTER TABLE "banned_member" DROP CONSTRAINT "FK_b94ea874da235d9b6fbc35cf58e"`) - await db.query(`ALTER TABLE "banned_member" DROP CONSTRAINT "FK_ed36c6c26bf5410796c2fc21f74"`) - await db.query(`ALTER TABLE "app" DROP CONSTRAINT "FK_c9cc395bbc485f70a15be64553e"`) - await db.query(`ALTER TABLE "channel" DROP CONSTRAINT "FK_25c85bc448b5e236a4c1a5f7895"`) - await db.query(`ALTER TABLE "channel" DROP CONSTRAINT "FK_a77e12f3d8c6ced020e179a5e94"`) - await db.query(`ALTER TABLE "channel" DROP CONSTRAINT "FK_6997e94413b3f2f25a84e4a96f8"`) - await db.query(`ALTER TABLE "channel" DROP CONSTRAINT "FK_118ecfa0199aeb5a014906933e8"`) - await db.query(`ALTER TABLE "video_featured_in_category" DROP CONSTRAINT "FK_7b16ddad43901921a8d3c8eab71"`) - await db.query(`ALTER TABLE "video_featured_in_category" DROP CONSTRAINT "FK_0e6bb49ce9d022cd872f3ab4288"`) - await db.query(`ALTER TABLE "video_category" DROP CONSTRAINT "FK_da26b34f037c0d59d3c0d0646e9"`) - await db.query(`ALTER TABLE "video_subtitle" DROP CONSTRAINT "FK_2203674f18d8052ed6bac396252"`) - await db.query(`ALTER TABLE "video_subtitle" DROP CONSTRAINT "FK_b6eabfb8de4128b28d73681020f"`) - await db.query(`ALTER TABLE "comment_reaction" DROP CONSTRAINT "FK_15080d9fb7cf8b563103dd9d900"`) - await db.query(`ALTER TABLE "comment_reaction" DROP CONSTRAINT "FK_962582f04d3f639e33f43c54bbc"`) - await db.query(`ALTER TABLE "comment_reaction" DROP CONSTRAINT "FK_d7995b1d57614a6fbd0c103874d"`) - await db.query(`ALTER TABLE "comment" DROP CONSTRAINT "FK_3ce66469b26697baa097f8da923"`) - await db.query(`ALTER TABLE "comment" DROP CONSTRAINT "FK_1ff03403fd31dfeaba0623a89cf"`) - await db.query(`ALTER TABLE "comment" DROP CONSTRAINT "FK_ac69bddf8202b7c0752d9dc8f32"`) - await db.query(`ALTER TABLE "video_reaction" DROP CONSTRAINT "FK_73dda64f53bbc7ec7035d5e7f09"`) - await db.query(`ALTER TABLE "video_reaction" DROP CONSTRAINT "FK_436a3836eb47acb5e1e3c88ddea"`) - await db.query(`ALTER TABLE "video" DROP CONSTRAINT "FK_81b11ef99a9db9ef1aed040d750"`) - await db.query(`ALTER TABLE "video" DROP CONSTRAINT "FK_2a5c61f32e9636ee10821e9a58d"`) - await db.query(`ALTER TABLE "video" DROP CONSTRAINT "FK_8530d052cc79b420f7ce2b4e09d"`) - await db.query(`ALTER TABLE "video" DROP CONSTRAINT "FK_3ec633ae5d0477f512b4ed957d6"`) - await db.query(`ALTER TABLE "video" DROP CONSTRAINT "FK_2db879ed42e3308fe65e6796729"`) - await db.query(`ALTER TABLE "video" DROP CONSTRAINT "FK_54f88a7decf7d22fd9bd9fa439a"`) - await db.query(`ALTER TABLE "video" DROP CONSTRAINT "FK_6c49ad08c44d36d11f77c426e43"`) - await db.query(`ALTER TABLE "bid" DROP CONSTRAINT "FK_9e594e5a61c0f3cb25679f6ba8d"`) - await db.query(`ALTER TABLE "bid" DROP CONSTRAINT "FK_3caf2d6b31d2fe45a2b85b81912"`) - await db.query(`ALTER TABLE "bid" DROP CONSTRAINT "FK_e7618559409a903a897164156b7"`) - await db.query(`ALTER TABLE "bid" DROP CONSTRAINT "FK_32cb73025ec49c87f4c594a265f"`) - await db.query(`ALTER TABLE "owned_nft" DROP CONSTRAINT "FK_466896e39b9ec953f4f2545622d"`) - await db.query(`ALTER TABLE "auction" DROP CONSTRAINT "FK_cfb47e97e60c9d1462576f85a88"`) - await db.query(`ALTER TABLE "auction" DROP CONSTRAINT "FK_a3127ec87cccc5696b92cac4e09"`) - await db.query(`ALTER TABLE "auction" DROP CONSTRAINT "FK_1673ad4b059742fbabfc40b275c"`) - await db.query(`ALTER TABLE "auction_whitelisted_member" DROP CONSTRAINT "FK_aad797677bc7c7c7dc1f1d397f5"`) - await db.query(`ALTER TABLE "auction_whitelisted_member" DROP CONSTRAINT "FK_d5ae4854487c7658b64225be305"`) - await db.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_6bfa96ab97f1a09d73091294efc"`) - await db.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_122be1f0696e0255acf95f9e336"`) - await db.query(`ALTER TABLE "account" DROP CONSTRAINT "FK_efef1e5fdbe318a379c06678c51"`) - await db.query(`ALTER TABLE "account" DROP CONSTRAINT "FK_601b93655bcbe73cb58d8c80cd3"`) - await db.query(`ALTER TABLE "encryption_artifacts" DROP CONSTRAINT "FK_ec8f68a544aadc4fbdadefe4a0a"`) - await db.query(`ALTER TABLE "session" DROP CONSTRAINT "FK_30e98e8746699fb9af235410aff"`) - await db.query(`ALTER TABLE "session" DROP CONSTRAINT "FK_fae5a6b4a57f098e9af8520d499"`) - await db.query(`ALTER TABLE "session_encryption_artifacts" DROP CONSTRAINT "FK_3612880efd8926a17eba5ab0e1a"`) - await db.query(`ALTER TABLE "token" DROP CONSTRAINT "FK_a6fe18c105f85a63d761ccb0780"`) - await db.query(`ALTER TABLE "nft_history_entry" DROP CONSTRAINT "FK_57f51d35ecab042478fe2e31c19"`) - await db.query(`ALTER TABLE "nft_history_entry" DROP CONSTRAINT "FK_d1a28b178f5d028d048d40ce208"`) - await db.query(`ALTER TABLE "nft_activity" DROP CONSTRAINT "FK_18a65713a9fd0715c7a980f5d54"`) - await db.query(`ALTER TABLE "nft_activity" DROP CONSTRAINT "FK_94d325a753f2c08fdd416eb095f"`) - await db.query(`ALTER TABLE "email_delivery_attempt" DROP CONSTRAINT "FK_f985b9b362249af72cac0f52a3b"`) - await db.query(`ALTER TABLE "notification_email_delivery" DROP CONSTRAINT "FK_3b756627c3146db150d66d12929"`) - await db.query(`ALTER TABLE "video_hero" DROP CONSTRAINT "FK_9feac5d9713a9f07e32eb8ba7a1"`) - await db.query(`ALTER TABLE "video_media_metadata" DROP CONSTRAINT "FK_5944dc5896cb16bd395414a0ce0"`) - await db.query(`ALTER TABLE "video_media_metadata" DROP CONSTRAINT "FK_4dc101240e8e1536b770aee202a"`) - await db.query(`ALTER TABLE "storage_bucket_operator_metadata" DROP CONSTRAINT "FK_7beffc9530b3f307bc1169cb524"`) - await db.query(`ALTER TABLE "distribution_bucket_family_metadata" DROP CONSTRAINT "FK_dd93ca0ea24f3e7a02f11c4c149"`) - await db.query(`ALTER TABLE "distribution_bucket_operator_metadata" DROP CONSTRAINT "FK_69ec9bdc975b95f7dff94a71069"`) - await db.query(`ALTER TABLE "channel_verification" DROP CONSTRAINT "FK_f13d5d785670f46de668575139c"`) - await db.query(`ALTER TABLE "channel_suspension" DROP CONSTRAINT "FK_e30ebff1042c010ff88b87f4f7a"`) - await db.query(`ALTER TABLE "member_metadata" DROP CONSTRAINT "FK_e7e4d350f82ae2383894f465ede"`) - } -} diff --git a/db/migrations/1708169663879-Data.js b/db/migrations/1708169663879-Data.js new file mode 100644 index 000000000..0057bff07 --- /dev/null +++ b/db/migrations/1708169663879-Data.js @@ -0,0 +1,453 @@ +module.exports = class Data1708169663879 { + name = 'Data1708169663879' + + async up(db) { + await db.query(`CREATE TABLE "admin"."channel_follow" ("id" character varying NOT NULL, "user_id" character varying, "channel_id" text NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_9410df2b9a316af3f0d216f9487" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_822778b4b1ea8e3b60b127cb8b" ON "admin"."channel_follow" ("user_id") `) + await db.query(`CREATE INDEX "IDX_9bc0651dda94437ec18764a260" ON "admin"."channel_follow" ("channel_id") `) + await db.query(`CREATE TABLE "admin"."video_view_event" ("id" character varying NOT NULL, "video_id" text NOT NULL, "user_id" character varying, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_2efd85597a6a7a704fc4d0f7701" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_2e29fba63e12a2b1818e0782d7" ON "admin"."video_view_event" ("video_id") `) + await db.query(`CREATE INDEX "IDX_31e1e798ec387ad905cf98d33b" ON "admin"."video_view_event" ("user_id") `) + await db.query(`CREATE TABLE "admin"."report" ("id" character varying NOT NULL, "user_id" character varying, "channel_id" text, "video_id" text, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "rationale" text NOT NULL, CONSTRAINT "PK_99e4d0bea58cba73c57f935a546" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_c6686efa4cd49fa9a429f01bac" ON "admin"."report" ("user_id") `) + await db.query(`CREATE INDEX "IDX_893057921f4b5cc37a0ef36684" ON "admin"."report" ("channel_id") `) + await db.query(`CREATE INDEX "IDX_f732b6f82095a935db68c9491f" ON "admin"."report" ("video_id") `) + await db.query(`CREATE TABLE "admin"."nft_featuring_request" ("id" character varying NOT NULL, "user_id" character varying, "nft_id" text NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "rationale" text NOT NULL, CONSTRAINT "PK_d0b1ccb74336b30b9575387d328" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_519be2a41216c278c35f254dcb" ON "admin"."nft_featuring_request" ("user_id") `) + await db.query(`CREATE INDEX "IDX_76d87e26cce72ac2e7ffa28dfb" ON "admin"."nft_featuring_request" ("nft_id") `) + await db.query(`CREATE TABLE "admin"."user" ("id" character varying NOT NULL, "is_root" boolean NOT NULL, "permissions" character varying(34) array, CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "storage_bucket" ("id" character varying NOT NULL, "operator_status" jsonb NOT NULL, "accepting_new_bags" boolean NOT NULL, "data_objects_size_limit" numeric NOT NULL, "data_object_count_limit" numeric NOT NULL, "data_objects_count" numeric NOT NULL, "data_objects_size" numeric NOT NULL, CONSTRAINT "PK_97cd0c3fe7f51e34216822e5f91" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "storage_bucket_bag" ("id" character varying NOT NULL, "storage_bucket_id" character varying, "bag_id" character varying, CONSTRAINT "StorageBucketBag_storageBucket_bag" UNIQUE ("storage_bucket_id", "bag_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_9d54c04557134225652d566cc82" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_aaf00b2c7d0cba49f97da14fbb" ON "storage_bucket_bag" ("bag_id") `) + await db.query(`CREATE INDEX "IDX_4c475f6c9300284b095859eec3" ON "storage_bucket_bag" ("storage_bucket_id", "bag_id") `) + await db.query(`CREATE TABLE "distribution_bucket_family" ("id" character varying NOT NULL, CONSTRAINT "PK_8cb7454d1ec34b0d3bb7ecdee4e" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "distribution_bucket_operator" ("id" character varying NOT NULL, "distribution_bucket_id" character varying, "worker_id" integer NOT NULL, "status" character varying(7) NOT NULL, CONSTRAINT "PK_03b87e6e972f414bab94c142285" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_678dc5427cdde0cd4fef2c07a4" ON "distribution_bucket_operator" ("distribution_bucket_id") `) + await db.query(`CREATE TABLE "distribution_bucket" ("id" character varying NOT NULL, "family_id" character varying, "bucket_index" integer NOT NULL, "accepting_new_bags" boolean NOT NULL, "distributing" boolean NOT NULL, CONSTRAINT "PK_c90d25fff461f2f5fa9082e2fb7" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_8cb7454d1ec34b0d3bb7ecdee4" ON "distribution_bucket" ("family_id") `) + await db.query(`CREATE TABLE "distribution_bucket_bag" ("id" character varying NOT NULL, "distribution_bucket_id" character varying, "bag_id" character varying, CONSTRAINT "DistributionBucketBag_distributionBucket_bag" UNIQUE ("distribution_bucket_id", "bag_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_02cb97c17ccabf42e8f5154d002" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_a9810100aee7584680f197c8ff" ON "distribution_bucket_bag" ("bag_id") `) + await db.query(`CREATE INDEX "IDX_32e552d352848d64ab82d38e9a" ON "distribution_bucket_bag" ("distribution_bucket_id", "bag_id") `) + await db.query(`CREATE TABLE "storage_bag" ("id" character varying NOT NULL, "owner" jsonb NOT NULL, CONSTRAINT "PK_242aecdc788d9b22bcbb9ade19a" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "admin"."storage_data_object" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "is_accepted" boolean NOT NULL, "size" numeric NOT NULL, "storage_bag_id" character varying, "ipfs_hash" text NOT NULL, "type" jsonb, "state_bloat_bond" numeric NOT NULL, "unset_at" TIMESTAMP WITH TIME ZONE, "resolved_urls" text array NOT NULL, CONSTRAINT "PK_61f224a4aef08f580a5ab4aadf0" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_ff8014300b8039dbaed764f51b" ON "admin"."storage_data_object" ("storage_bag_id") `) + await db.query(`CREATE TABLE "admin"."banned_member" ("id" character varying NOT NULL, "member_id" character varying, "channel_id" character varying, CONSTRAINT "BannedMember_member_channel" UNIQUE ("member_id", "channel_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_ebdf9a9c6d88f1116a5f2d0815d" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_ed36c6c26bf5410796c2fc21f7" ON "admin"."banned_member" ("channel_id") `) + await db.query(`CREATE INDEX "IDX_f29ff095bdb945975deca021ad" ON "admin"."banned_member" ("member_id", "channel_id") `) + await db.query(`CREATE TABLE "app" ("id" character varying NOT NULL, "name" text NOT NULL, "owner_member_id" character varying, "website_url" text, "use_uri" text, "small_icon" text, "medium_icon" text, "big_icon" text, "one_liner" text, "description" text, "terms_of_service" text, "platforms" text array, "category" text, "auth_key" text, CONSTRAINT "App_name" UNIQUE ("name") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_9478629fc093d229df09e560aea" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_f36adbb7b096ceeb6f3e80ad14" ON "app" ("name") `) + await db.query(`CREATE INDEX "IDX_c9cc395bbc485f70a15be64553" ON "app" ("owner_member_id") `) + await db.query(`CREATE TABLE "admin"."channel" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "owner_member_id" character varying, "title" text, "description" text, "cover_photo_id" character varying, "avatar_photo_id" character varying, "is_public" boolean, "is_censored" boolean NOT NULL, "is_excluded" boolean NOT NULL, "language" text, "created_in_block" integer NOT NULL, "reward_account" text NOT NULL, "channel_state_bloat_bond" numeric NOT NULL, "follows_num" integer NOT NULL, "video_views_num" integer NOT NULL, "entry_app_id" character varying, "total_videos_created" integer NOT NULL, "cumulative_reward_claimed" numeric NOT NULL, "cumulative_reward" numeric NOT NULL, "channel_weight" numeric, "ypp_status" jsonb NOT NULL, CONSTRAINT "PK_590f33ee6ee7d76437acf362e39" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_a4752a0a0899dedc4d18077dd0" ON "admin"."channel" ("created_at") `) + await db.query(`CREATE INDEX "IDX_25c85bc448b5e236a4c1a5f789" ON "admin"."channel" ("owner_member_id") `) + await db.query(`CREATE INDEX "IDX_a77e12f3d8c6ced020e179a5e9" ON "admin"."channel" ("cover_photo_id") `) + await db.query(`CREATE INDEX "IDX_6997e94413b3f2f25a84e4a96f" ON "admin"."channel" ("avatar_photo_id") `) + await db.query(`CREATE INDEX "IDX_e58a2e1d78b8eccf40531a7fdb" ON "admin"."channel" ("language") `) + await db.query(`CREATE INDEX "IDX_118ecfa0199aeb5a014906933e" ON "admin"."channel" ("entry_app_id") `) + await db.query(`CREATE TABLE "admin"."video_featured_in_category" ("id" character varying NOT NULL, "video_id" character varying, "category_id" character varying, "video_cut_url" text, CONSTRAINT "VideoFeaturedInCategory_category_video" UNIQUE ("category_id", "video_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_f84d38b5cdb7567ac04d6e9d209" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_7b16ddad43901921a8d3c8eab7" ON "admin"."video_featured_in_category" ("video_id") `) + await db.query(`CREATE INDEX "IDX_6d0917e1ac0cc06c8075bcf256" ON "admin"."video_featured_in_category" ("category_id", "video_id") `) + await db.query(`CREATE TABLE "admin"."video_category" ("id" character varying NOT NULL, "name" text, "description" text, "parent_category_id" character varying, "is_supported" boolean NOT NULL, "created_in_block" integer NOT NULL, CONSTRAINT "PK_2a5c61f32e9636ee10821e9a58d" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_cbe7e5d162a819e4ee2e2f6105" ON "admin"."video_category" ("name") `) + await db.query(`CREATE INDEX "IDX_da26b34f037c0d59d3c0d0646e" ON "admin"."video_category" ("parent_category_id") `) + await db.query(`CREATE TABLE "admin"."license" ("id" character varying NOT NULL, "code" integer, "attribution" text, "custom_text" text, CONSTRAINT "PK_f168ac1ca5ba87286d03b2ef905" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "admin"."video_subtitle" ("id" character varying NOT NULL, "video_id" character varying, "type" text NOT NULL, "language" text, "mime_type" text NOT NULL, "asset_id" character varying, CONSTRAINT "PK_2ac3e585fc608e673e7fbf94d8e" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_2203674f18d8052ed6bac39625" ON "admin"."video_subtitle" ("video_id") `) + await db.query(`CREATE INDEX "IDX_ffa63c28188eecc32af921bfc3" ON "admin"."video_subtitle" ("language") `) + await db.query(`CREATE INDEX "IDX_b6eabfb8de4128b28d73681020" ON "admin"."video_subtitle" ("asset_id") `) + await db.query(`CREATE TABLE "admin"."comment_reaction" ("id" character varying NOT NULL, "reaction_id" integer NOT NULL, "member_id" character varying, "comment_id" character varying, "video_id" character varying, CONSTRAINT "PK_87f27d282c06eb61b1e0cde2d24" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_15080d9fb7cf8b563103dd9d90" ON "admin"."comment_reaction" ("member_id") `) + await db.query(`CREATE INDEX "IDX_962582f04d3f639e33f43c54bb" ON "admin"."comment_reaction" ("comment_id") `) + await db.query(`CREATE INDEX "IDX_d7995b1d57614a6fbd0c103874" ON "admin"."comment_reaction" ("video_id") `) + await db.query(`CREATE TABLE "admin"."comment" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "author_id" character varying, "text" text NOT NULL, "video_id" character varying, "status" character varying(9) NOT NULL, "reactions_count_by_reaction_id" jsonb, "parent_comment_id" character varying, "replies_count" integer NOT NULL, "reactions_count" integer NOT NULL, "reactions_and_replies_count" integer NOT NULL, "is_edited" boolean NOT NULL, "is_excluded" boolean NOT NULL, CONSTRAINT "PK_0b0e4bbc8415ec426f87f3a88e2" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_3ce66469b26697baa097f8da92" ON "admin"."comment" ("author_id") `) + await db.query(`CREATE INDEX "IDX_1ff03403fd31dfeaba0623a89c" ON "admin"."comment" ("video_id") `) + await db.query(`CREATE INDEX "IDX_c3c2abe750c76c7c8e305f71f2" ON "admin"."comment" ("status") `) + await db.query(`CREATE INDEX "IDX_ac69bddf8202b7c0752d9dc8f3" ON "admin"."comment" ("parent_comment_id") `) + await db.query(`CREATE TABLE "admin"."video_reaction" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "reaction" character varying(6) NOT NULL, "member_id" character varying, "video_id" character varying, CONSTRAINT "PK_504876585c394f4ab33665dd44b" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_73dda64f53bbc7ec7035d5e7f0" ON "admin"."video_reaction" ("member_id") `) + await db.query(`CREATE INDEX "IDX_436a3836eb47acb5e1e3c88dde" ON "admin"."video_reaction" ("video_id") `) + await db.query(`CREATE TABLE "admin"."video" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "channel_id" character varying, "category_id" character varying, "title" text, "description" text, "duration" integer, "thumbnail_photo_id" character varying, "language" text, "orion_language" text, "has_marketing" boolean, "published_before_joystream" TIMESTAMP WITH TIME ZONE, "is_public" boolean, "is_censored" boolean NOT NULL, "is_excluded" boolean NOT NULL, "is_explicit" boolean, "license_id" character varying, "media_id" character varying, "video_state_bloat_bond" numeric NOT NULL, "created_in_block" integer NOT NULL, "is_comment_section_enabled" boolean NOT NULL, "pinned_comment_id" character varying, "comments_count" integer NOT NULL, "is_reaction_feature_enabled" boolean NOT NULL, "reactions_count_by_reaction_id" jsonb, "reactions_count" integer NOT NULL, "views_num" integer NOT NULL, "entry_app_id" character varying, "yt_video_id" text, "video_relevance" numeric NOT NULL, CONSTRAINT "PK_1a2f3856250765d72e7e1636c8e" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_fe2b4b6aace15f1b6610830846" ON "admin"."video" ("created_at") `) + await db.query(`CREATE INDEX "IDX_81b11ef99a9db9ef1aed040d75" ON "admin"."video" ("channel_id") `) + await db.query(`CREATE INDEX "IDX_2a5c61f32e9636ee10821e9a58" ON "admin"."video" ("category_id") `) + await db.query(`CREATE INDEX "IDX_8530d052cc79b420f7ce2b4e09" ON "admin"."video" ("thumbnail_photo_id") `) + await db.query(`CREATE INDEX "IDX_57b335fa0a960877caf6d2fc29" ON "admin"."video" ("orion_language") `) + await db.query(`CREATE INDEX "IDX_3ec633ae5d0477f512b4ed957d" ON "admin"."video" ("license_id") `) + await db.query(`CREATE INDEX "IDX_2db879ed42e3308fe65e679672" ON "admin"."video" ("media_id") `) + await db.query(`CREATE INDEX "IDX_54f88a7decf7d22fd9bd9fa439" ON "admin"."video" ("pinned_comment_id") `) + await db.query(`CREATE INDEX "IDX_6c49ad08c44d36d11f77c426e4" ON "admin"."video" ("entry_app_id") `) + await db.query(`CREATE INDEX "IDX_f33816960d690ac836f5d5c28a" ON "admin"."video" ("video_relevance") `) + await db.query(`CREATE TABLE "admin"."bid" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "auction_id" character varying, "nft_id" character varying, "bidder_id" character varying, "amount" numeric NOT NULL, "is_canceled" boolean NOT NULL, "created_in_block" integer NOT NULL, "index_in_block" integer NOT NULL, "previous_top_bid_id" character varying, CONSTRAINT "PK_ed405dda320051aca2dcb1a50bb" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_9e594e5a61c0f3cb25679f6ba8" ON "admin"."bid" ("auction_id") `) + await db.query(`CREATE INDEX "IDX_3caf2d6b31d2fe45a2b85b8191" ON "admin"."bid" ("nft_id") `) + await db.query(`CREATE INDEX "IDX_e7618559409a903a897164156b" ON "admin"."bid" ("bidder_id") `) + await db.query(`CREATE INDEX "IDX_32cb73025ec49c87f4c594a265" ON "admin"."bid" ("previous_top_bid_id") `) + await db.query(`CREATE TABLE "admin"."owned_nft" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "video_id" character varying NOT NULL, "owner" jsonb NOT NULL, "transactional_status" jsonb, "creator_royalty" numeric, "last_sale_price" numeric, "last_sale_date" TIMESTAMP WITH TIME ZONE, "is_featured" boolean NOT NULL, CONSTRAINT "OwnedNft_video" UNIQUE ("video_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_466896e39b9ec953f4f2545622" UNIQUE ("video_id"), CONSTRAINT "PK_5e0c289b350e863668fff44bb56" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_8c7201ed7d4765dcbcc3609356" ON "admin"."owned_nft" ("created_at") `) + await db.query(`CREATE INDEX "IDX_466896e39b9ec953f4f2545622" ON "admin"."owned_nft" ("video_id") `) + await db.query(`CREATE TABLE "admin"."auction" ("id" character varying NOT NULL, "nft_id" character varying, "winning_member_id" character varying, "starting_price" numeric NOT NULL, "buy_now_price" numeric, "auction_type" jsonb NOT NULL, "top_bid_id" character varying, "starts_at_block" integer NOT NULL, "ended_at_block" integer, "is_canceled" boolean NOT NULL, "is_completed" boolean NOT NULL, CONSTRAINT "PK_9dc876c629273e71646cf6dfa67" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_cfb47e97e60c9d1462576f85a8" ON "admin"."auction" ("nft_id") `) + await db.query(`CREATE INDEX "IDX_a3127ec87cccc5696b92cac4e0" ON "admin"."auction" ("winning_member_id") `) + await db.query(`CREATE INDEX "IDX_1673ad4b059742fbabfc40b275" ON "admin"."auction" ("top_bid_id") `) + await db.query(`CREATE TABLE "auction_whitelisted_member" ("id" character varying NOT NULL, "auction_id" character varying, "member_id" character varying, CONSTRAINT "AuctionWhitelistedMember_auction_member" UNIQUE ("auction_id", "member_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_f20264ca8e878696fbc25f11bd5" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_d5ae4854487c7658b64225be30" ON "auction_whitelisted_member" ("member_id") `) + await db.query(`CREATE INDEX "IDX_5468573a96fa51c03743de5912" ON "auction_whitelisted_member" ("auction_id", "member_id") `) + await db.query(`CREATE TABLE "membership" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "handle" text NOT NULL, "handle_raw" text NOT NULL, "controller_account" text NOT NULL, "total_channels_created" integer NOT NULL, CONSTRAINT "Membership_handleRaw" UNIQUE ("handle_raw") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "PK_83c1afebef3059472e7c37e8de8" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_0c5b879f9f2ca57a774f74f7f0" ON "membership" ("handle_raw") `) + await db.query(`CREATE TABLE "admin"."event" ("id" character varying NOT NULL, "in_block" integer NOT NULL, "in_extrinsic" text, "index_in_block" integer NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "data" jsonb NOT NULL, CONSTRAINT "PK_30c2f3bbaf6d34a55f8ae6e4614" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_8f3f220c4e717207d841d4e6d4" ON "admin"."event" ("in_extrinsic") `) + await db.query(`CREATE INDEX "IDX_2c15918ff289396205521c5f3c" ON "admin"."event" ("timestamp") `) + await db.query(`CREATE TABLE "notification" ("id" character varying NOT NULL, "account_id" character varying, "notification_type" jsonb NOT NULL, "event_id" character varying, "status" jsonb NOT NULL, "in_app" boolean NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, "recipient" jsonb NOT NULL, CONSTRAINT "PK_705b6c7cdf9b2c2ff7ac7872cb7" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_6bfa96ab97f1a09d73091294ef" ON "notification" ("account_id") `) + await db.query(`CREATE INDEX "IDX_122be1f0696e0255acf95f9e33" ON "notification" ("event_id") `) + await db.query(`CREATE TABLE "admin"."account" ("id" character varying NOT NULL, "user_id" character varying NOT NULL, "email" text NOT NULL, "is_email_confirmed" boolean NOT NULL, "is_blocked" boolean NOT NULL, "registered_at" TIMESTAMP WITH TIME ZONE NOT NULL, "membership_id" character varying NOT NULL, "joystream_account" text NOT NULL, "notification_preferences" jsonb NOT NULL, "referrer_channel_id" text, CONSTRAINT "Account_joystreamAccount" UNIQUE ("joystream_account") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "Account_membership" UNIQUE ("membership_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "Account_email" UNIQUE ("email") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "Account_user" UNIQUE ("user_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_efef1e5fdbe318a379c06678c5" UNIQUE ("user_id"), CONSTRAINT "REL_601b93655bcbe73cb58d8c80cd" UNIQUE ("membership_id"), CONSTRAINT "PK_54115ee388cdb6d86bb4bf5b2ea" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_efef1e5fdbe318a379c06678c5" ON "admin"."account" ("user_id") `) + await db.query(`CREATE INDEX "IDX_4c8f96ccf523e9a3faefd5bdd4" ON "admin"."account" ("email") `) + await db.query(`CREATE INDEX "IDX_601b93655bcbe73cb58d8c80cd" ON "admin"."account" ("membership_id") `) + await db.query(`CREATE INDEX "IDX_df4da05a7a80c1afd18b8f0990" ON "admin"."account" ("joystream_account") `) + await db.query(`CREATE TABLE "encryption_artifacts" ("id" character varying NOT NULL, "account_id" character varying NOT NULL, "cipher_iv" text NOT NULL, "encrypted_seed" text NOT NULL, CONSTRAINT "EncryptionArtifacts_account" UNIQUE ("account_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_ec8f68a544aadc4fbdadefe4a0" UNIQUE ("account_id"), CONSTRAINT "PK_6441471581ba6d149ad75655bd0" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_ec8f68a544aadc4fbdadefe4a0" ON "encryption_artifacts" ("account_id") `) + await db.query(`CREATE TABLE "admin"."session" ("id" character varying NOT NULL, "browser" text NOT NULL, "os" text NOT NULL, "device" text NOT NULL, "device_type" text, "user_id" character varying, "account_id" character varying, "ip" text NOT NULL, "started_at" TIMESTAMP WITH TIME ZONE NOT NULL, "expiry" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_f55da76ac1c3ac420f444d2ff11" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_30e98e8746699fb9af235410af" ON "admin"."session" ("user_id") `) + await db.query(`CREATE INDEX "IDX_fae5a6b4a57f098e9af8520d49" ON "admin"."session" ("account_id") `) + await db.query(`CREATE INDEX "IDX_213b5a19bfdbe0ab6e06b1dede" ON "admin"."session" ("ip") `) + await db.query(`CREATE TABLE "session_encryption_artifacts" ("id" character varying NOT NULL, "session_id" character varying NOT NULL, "cipher_iv" text NOT NULL, "cipher_key" text NOT NULL, CONSTRAINT "SessionEncryptionArtifacts_session" UNIQUE ("session_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_3612880efd8926a17eba5ab0e1" UNIQUE ("session_id"), CONSTRAINT "PK_e328da2643599e265a848219885" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_3612880efd8926a17eba5ab0e1" ON "session_encryption_artifacts" ("session_id") `) + await db.query(`CREATE TABLE "admin"."token" ("id" character varying NOT NULL, "type" character varying(18) NOT NULL, "issued_at" TIMESTAMP WITH TIME ZONE NOT NULL, "expiry" TIMESTAMP WITH TIME ZONE NOT NULL, "issued_for_id" character varying, CONSTRAINT "PK_82fae97f905930df5d62a702fc9" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_a6fe18c105f85a63d761ccb078" ON "admin"."token" ("issued_for_id") `) + await db.query(`CREATE TABLE "admin"."nft_history_entry" ("id" character varying NOT NULL, "nft_id" character varying, "event_id" character varying, CONSTRAINT "PK_9018e80b335a965a54959c4c6e2" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_57f51d35ecab042478fe2e31c1" ON "admin"."nft_history_entry" ("nft_id") `) + await db.query(`CREATE INDEX "IDX_d1a28b178f5d028d048d40ce20" ON "admin"."nft_history_entry" ("event_id") `) + await db.query(`CREATE TABLE "admin"."nft_activity" ("id" character varying NOT NULL, "member_id" character varying, "event_id" character varying, CONSTRAINT "PK_1553b1bbf8000039875a6e31536" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_18a65713a9fd0715c7a980f5d5" ON "admin"."nft_activity" ("member_id") `) + await db.query(`CREATE INDEX "IDX_94d325a753f2c08fdd416eb095" ON "admin"."nft_activity" ("event_id") `) + await db.query(`CREATE TABLE "admin"."email_delivery_attempt" ("id" character varying NOT NULL, "notification_delivery_id" character varying, "status" jsonb NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_876948339083a2f1092245f7a32" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_f985b9b362249af72cac0f52a3" ON "admin"."email_delivery_attempt" ("notification_delivery_id") `) + await db.query(`CREATE TABLE "admin"."notification_email_delivery" ("id" character varying NOT NULL, "notification_id" character varying, "discard" boolean NOT NULL, CONSTRAINT "PK_60dc7ff42a7abf7b0d44bf60516" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_3b756627c3146db150d66d1292" ON "admin"."notification_email_delivery" ("notification_id") `) + await db.query(`CREATE TABLE "admin"."video_hero" ("id" character varying NOT NULL, "video_id" character varying, "hero_title" text NOT NULL, "hero_video_cut_url" text NOT NULL, "hero_poster_url" text NOT NULL, "activated_at" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_f3b63979879773378afac0b9495" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_9feac5d9713a9f07e32eb8ba7a" ON "admin"."video_hero" ("video_id") `) + await db.query(`CREATE TABLE "admin"."video_media_encoding" ("id" character varying NOT NULL, "codec_name" text, "container" text, "mime_media_type" text, CONSTRAINT "PK_52e25874f8d8a381e154d1125e0" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "admin"."video_media_metadata" ("id" character varying NOT NULL, "encoding_id" character varying, "pixel_width" integer, "pixel_height" integer, "size" numeric, "video_id" character varying NOT NULL, "created_in_block" integer NOT NULL, CONSTRAINT "VideoMediaMetadata_video" UNIQUE ("video_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_4dc101240e8e1536b770aee202" UNIQUE ("video_id"), CONSTRAINT "PK_86a13815734e589cd86d0465e2d" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_5944dc5896cb16bd395414a0ce" ON "admin"."video_media_metadata" ("encoding_id") `) + await db.query(`CREATE INDEX "IDX_4dc101240e8e1536b770aee202" ON "admin"."video_media_metadata" ("video_id") `) + await db.query(`CREATE TABLE "admin"."gateway_config" ("id" character varying NOT NULL, "value" text NOT NULL, "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_db1fa5a857fb6292eee4c493e6f" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "admin"."exclusion" ("id" character varying NOT NULL, "channel_id" text, "video_id" text, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "rationale" text NOT NULL, CONSTRAINT "PK_7f8dcde2e607a96d66dce002e74" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_efba55b85909822c2b7655dfb8" ON "admin"."exclusion" ("channel_id") `) + await db.query(`CREATE INDEX "IDX_2729041b2f528a6c5833fdb3e5" ON "admin"."exclusion" ("video_id") `) + await db.query(`CREATE TABLE "storage_bucket_operator_metadata" ("id" character varying NOT NULL, "storage_bucket_id" character varying NOT NULL, "node_endpoint" text, "node_location" jsonb, "extra" text, CONSTRAINT "StorageBucketOperatorMetadata_storageBucket" UNIQUE ("storage_bucket_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_7beffc9530b3f307bc1169cb52" UNIQUE ("storage_bucket_id"), CONSTRAINT "PK_9846a397400ae1a39b21fbd02d4" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_7beffc9530b3f307bc1169cb52" ON "storage_bucket_operator_metadata" ("storage_bucket_id") `) + await db.query(`CREATE TABLE "distribution_bucket_family_metadata" ("id" character varying NOT NULL, "family_id" character varying NOT NULL, "region" text, "description" text, "areas" jsonb, "latency_test_targets" text array, CONSTRAINT "DistributionBucketFamilyMetadata_family" UNIQUE ("family_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_dd93ca0ea24f3e7a02f11c4c14" UNIQUE ("family_id"), CONSTRAINT "PK_df7a270835bb313d3ef17bdee2f" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_dd93ca0ea24f3e7a02f11c4c14" ON "distribution_bucket_family_metadata" ("family_id") `) + await db.query(`CREATE INDEX "IDX_5510d3b244a63d6ec702faa426" ON "distribution_bucket_family_metadata" ("region") `) + await db.query(`CREATE TABLE "distribution_bucket_operator_metadata" ("id" character varying NOT NULL, "distirbution_bucket_operator_id" character varying NOT NULL, "node_endpoint" text, "node_location" jsonb, "extra" text, CONSTRAINT "DistributionBucketOperatorMetadata_distirbutionBucketOperator" UNIQUE ("distirbution_bucket_operator_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_69ec9bdc975b95f7dff94a7106" UNIQUE ("distirbution_bucket_operator_id"), CONSTRAINT "PK_9bbecaa12f30e3826922688274f" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_69ec9bdc975b95f7dff94a7106" ON "distribution_bucket_operator_metadata" ("distirbution_bucket_operator_id") `) + await db.query(`CREATE TABLE "admin"."channel_verification" ("id" character varying NOT NULL, "channel_id" character varying, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_0a61c78b114ed3e92300e09afaa" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_f13d5d785670f46de668575139" ON "admin"."channel_verification" ("channel_id") `) + await db.query(`CREATE TABLE "admin"."channel_suspension" ("id" character varying NOT NULL, "channel_id" character varying, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "PK_226679cee9a8d0e5af18f70a1da" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_e30ebff1042c010ff88b87f4f7" ON "admin"."channel_suspension" ("channel_id") `) + await db.query(`CREATE TABLE "curator_group" ("id" character varying NOT NULL, "is_active" boolean NOT NULL, CONSTRAINT "PK_0b4c0ab279d72bcbf4e16b65ff1" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "curator" ("id" character varying NOT NULL, CONSTRAINT "PK_5791051a62d2c2dfc593d38ab57" PRIMARY KEY ("id"))`) + await db.query(`CREATE TABLE "member_metadata" ("id" character varying NOT NULL, "name" text, "avatar" jsonb, "about" text, "member_id" character varying NOT NULL, CONSTRAINT "MemberMetadata_member" UNIQUE ("member_id") DEFERRABLE INITIALLY DEFERRED, CONSTRAINT "REL_e7e4d350f82ae2383894f465ed" UNIQUE ("member_id"), CONSTRAINT "PK_d3fcc374696465f3c0ac3ba8708" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_e7e4d350f82ae2383894f465ed" ON "member_metadata" ("member_id") `) + await db.query(`CREATE TABLE "next_entity_id" ("entity_name" character varying NOT NULL, "next_id" bigint NOT NULL, CONSTRAINT "PK_09a3b40db622a65096e7344d7ae" PRIMARY KEY ("entity_name"))`) + await db.query(`ALTER TABLE "admin"."channel_follow" ADD CONSTRAINT "FK_822778b4b1ea8e3b60b127cb8b1" FOREIGN KEY ("user_id") REFERENCES "admin"."user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_view_event" ADD CONSTRAINT "FK_31e1e798ec387ad905cf98d33b0" FOREIGN KEY ("user_id") REFERENCES "admin"."user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."report" ADD CONSTRAINT "FK_c6686efa4cd49fa9a429f01bac8" FOREIGN KEY ("user_id") REFERENCES "admin"."user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."nft_featuring_request" ADD CONSTRAINT "FK_519be2a41216c278c35f254dcba" FOREIGN KEY ("user_id") REFERENCES "admin"."user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "storage_bucket_bag" ADD CONSTRAINT "FK_791e2f82e3919ffcef8712aa1b9" FOREIGN KEY ("storage_bucket_id") REFERENCES "storage_bucket"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "storage_bucket_bag" ADD CONSTRAINT "FK_aaf00b2c7d0cba49f97da14fbba" FOREIGN KEY ("bag_id") REFERENCES "storage_bag"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "distribution_bucket_operator" ADD CONSTRAINT "FK_678dc5427cdde0cd4fef2c07a43" FOREIGN KEY ("distribution_bucket_id") REFERENCES "distribution_bucket"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "distribution_bucket" ADD CONSTRAINT "FK_8cb7454d1ec34b0d3bb7ecdee4e" FOREIGN KEY ("family_id") REFERENCES "distribution_bucket_family"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "distribution_bucket_bag" ADD CONSTRAINT "FK_8a807921f1aae60d4ba94895826" FOREIGN KEY ("distribution_bucket_id") REFERENCES "distribution_bucket"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "distribution_bucket_bag" ADD CONSTRAINT "FK_a9810100aee7584680f197c8ff0" FOREIGN KEY ("bag_id") REFERENCES "storage_bag"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."storage_data_object" ADD CONSTRAINT "FK_ff8014300b8039dbaed764f51bc" FOREIGN KEY ("storage_bag_id") REFERENCES "storage_bag"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."banned_member" ADD CONSTRAINT "FK_b94ea874da235d9b6fbc35cf58e" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."banned_member" ADD CONSTRAINT "FK_ed36c6c26bf5410796c2fc21f74" FOREIGN KEY ("channel_id") REFERENCES "admin"."channel"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "app" ADD CONSTRAINT "FK_c9cc395bbc485f70a15be64553e" FOREIGN KEY ("owner_member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."channel" ADD CONSTRAINT "FK_25c85bc448b5e236a4c1a5f7895" FOREIGN KEY ("owner_member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."channel" ADD CONSTRAINT "FK_a77e12f3d8c6ced020e179a5e94" FOREIGN KEY ("cover_photo_id") REFERENCES "admin"."storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."channel" ADD CONSTRAINT "FK_6997e94413b3f2f25a84e4a96f8" FOREIGN KEY ("avatar_photo_id") REFERENCES "admin"."storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."channel" ADD CONSTRAINT "FK_118ecfa0199aeb5a014906933e8" FOREIGN KEY ("entry_app_id") REFERENCES "app"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_featured_in_category" ADD CONSTRAINT "FK_7b16ddad43901921a8d3c8eab71" FOREIGN KEY ("video_id") REFERENCES "admin"."video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_featured_in_category" ADD CONSTRAINT "FK_0e6bb49ce9d022cd872f3ab4288" FOREIGN KEY ("category_id") REFERENCES "admin"."video_category"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_category" ADD CONSTRAINT "FK_da26b34f037c0d59d3c0d0646e9" FOREIGN KEY ("parent_category_id") REFERENCES "admin"."video_category"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_subtitle" ADD CONSTRAINT "FK_2203674f18d8052ed6bac396252" FOREIGN KEY ("video_id") REFERENCES "admin"."video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_subtitle" ADD CONSTRAINT "FK_b6eabfb8de4128b28d73681020f" FOREIGN KEY ("asset_id") REFERENCES "admin"."storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."comment_reaction" ADD CONSTRAINT "FK_15080d9fb7cf8b563103dd9d900" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."comment_reaction" ADD CONSTRAINT "FK_962582f04d3f639e33f43c54bbc" FOREIGN KEY ("comment_id") REFERENCES "admin"."comment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."comment_reaction" ADD CONSTRAINT "FK_d7995b1d57614a6fbd0c103874d" FOREIGN KEY ("video_id") REFERENCES "admin"."video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."comment" ADD CONSTRAINT "FK_3ce66469b26697baa097f8da923" FOREIGN KEY ("author_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."comment" ADD CONSTRAINT "FK_1ff03403fd31dfeaba0623a89cf" FOREIGN KEY ("video_id") REFERENCES "admin"."video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."comment" ADD CONSTRAINT "FK_ac69bddf8202b7c0752d9dc8f32" FOREIGN KEY ("parent_comment_id") REFERENCES "admin"."comment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_reaction" ADD CONSTRAINT "FK_73dda64f53bbc7ec7035d5e7f09" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_reaction" ADD CONSTRAINT "FK_436a3836eb47acb5e1e3c88ddea" FOREIGN KEY ("video_id") REFERENCES "admin"."video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video" ADD CONSTRAINT "FK_81b11ef99a9db9ef1aed040d750" FOREIGN KEY ("channel_id") REFERENCES "admin"."channel"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video" ADD CONSTRAINT "FK_2a5c61f32e9636ee10821e9a58d" FOREIGN KEY ("category_id") REFERENCES "admin"."video_category"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video" ADD CONSTRAINT "FK_8530d052cc79b420f7ce2b4e09d" FOREIGN KEY ("thumbnail_photo_id") REFERENCES "admin"."storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video" ADD CONSTRAINT "FK_3ec633ae5d0477f512b4ed957d6" FOREIGN KEY ("license_id") REFERENCES "admin"."license"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video" ADD CONSTRAINT "FK_2db879ed42e3308fe65e6796729" FOREIGN KEY ("media_id") REFERENCES "admin"."storage_data_object"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video" ADD CONSTRAINT "FK_54f88a7decf7d22fd9bd9fa439a" FOREIGN KEY ("pinned_comment_id") REFERENCES "admin"."comment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video" ADD CONSTRAINT "FK_6c49ad08c44d36d11f77c426e43" FOREIGN KEY ("entry_app_id") REFERENCES "app"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."bid" ADD CONSTRAINT "FK_9e594e5a61c0f3cb25679f6ba8d" FOREIGN KEY ("auction_id") REFERENCES "admin"."auction"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."bid" ADD CONSTRAINT "FK_3caf2d6b31d2fe45a2b85b81912" FOREIGN KEY ("nft_id") REFERENCES "admin"."owned_nft"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."bid" ADD CONSTRAINT "FK_e7618559409a903a897164156b7" FOREIGN KEY ("bidder_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."bid" ADD CONSTRAINT "FK_32cb73025ec49c87f4c594a265f" FOREIGN KEY ("previous_top_bid_id") REFERENCES "admin"."bid"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."owned_nft" ADD CONSTRAINT "FK_466896e39b9ec953f4f2545622d" FOREIGN KEY ("video_id") REFERENCES "admin"."video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."auction" ADD CONSTRAINT "FK_cfb47e97e60c9d1462576f85a88" FOREIGN KEY ("nft_id") REFERENCES "admin"."owned_nft"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."auction" ADD CONSTRAINT "FK_a3127ec87cccc5696b92cac4e09" FOREIGN KEY ("winning_member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."auction" ADD CONSTRAINT "FK_1673ad4b059742fbabfc40b275c" FOREIGN KEY ("top_bid_id") REFERENCES "admin"."bid"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "auction_whitelisted_member" ADD CONSTRAINT "FK_aad797677bc7c7c7dc1f1d397f5" FOREIGN KEY ("auction_id") REFERENCES "admin"."auction"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "auction_whitelisted_member" ADD CONSTRAINT "FK_d5ae4854487c7658b64225be305" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_6bfa96ab97f1a09d73091294efc" FOREIGN KEY ("account_id") REFERENCES "admin"."account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_122be1f0696e0255acf95f9e336" FOREIGN KEY ("event_id") REFERENCES "admin"."event"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."account" ADD CONSTRAINT "FK_efef1e5fdbe318a379c06678c51" FOREIGN KEY ("user_id") REFERENCES "admin"."user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."account" ADD CONSTRAINT "FK_601b93655bcbe73cb58d8c80cd3" FOREIGN KEY ("membership_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "encryption_artifacts" ADD CONSTRAINT "FK_ec8f68a544aadc4fbdadefe4a0a" FOREIGN KEY ("account_id") REFERENCES "admin"."account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."session" ADD CONSTRAINT "FK_30e98e8746699fb9af235410aff" FOREIGN KEY ("user_id") REFERENCES "admin"."user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."session" ADD CONSTRAINT "FK_fae5a6b4a57f098e9af8520d499" FOREIGN KEY ("account_id") REFERENCES "admin"."account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "session_encryption_artifacts" ADD CONSTRAINT "FK_3612880efd8926a17eba5ab0e1a" FOREIGN KEY ("session_id") REFERENCES "admin"."session"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."token" ADD CONSTRAINT "FK_a6fe18c105f85a63d761ccb0780" FOREIGN KEY ("issued_for_id") REFERENCES "admin"."account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."nft_history_entry" ADD CONSTRAINT "FK_57f51d35ecab042478fe2e31c19" FOREIGN KEY ("nft_id") REFERENCES "admin"."owned_nft"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."nft_history_entry" ADD CONSTRAINT "FK_d1a28b178f5d028d048d40ce208" FOREIGN KEY ("event_id") REFERENCES "admin"."event"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."nft_activity" ADD CONSTRAINT "FK_18a65713a9fd0715c7a980f5d54" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."nft_activity" ADD CONSTRAINT "FK_94d325a753f2c08fdd416eb095f" FOREIGN KEY ("event_id") REFERENCES "admin"."event"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."email_delivery_attempt" ADD CONSTRAINT "FK_f985b9b362249af72cac0f52a3b" FOREIGN KEY ("notification_delivery_id") REFERENCES "admin"."notification_email_delivery"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."notification_email_delivery" ADD CONSTRAINT "FK_3b756627c3146db150d66d12929" FOREIGN KEY ("notification_id") REFERENCES "notification"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_hero" ADD CONSTRAINT "FK_9feac5d9713a9f07e32eb8ba7a1" FOREIGN KEY ("video_id") REFERENCES "admin"."video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_media_metadata" ADD CONSTRAINT "FK_5944dc5896cb16bd395414a0ce0" FOREIGN KEY ("encoding_id") REFERENCES "admin"."video_media_encoding"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."video_media_metadata" ADD CONSTRAINT "FK_4dc101240e8e1536b770aee202a" FOREIGN KEY ("video_id") REFERENCES "admin"."video"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "storage_bucket_operator_metadata" ADD CONSTRAINT "FK_7beffc9530b3f307bc1169cb524" FOREIGN KEY ("storage_bucket_id") REFERENCES "storage_bucket"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "distribution_bucket_family_metadata" ADD CONSTRAINT "FK_dd93ca0ea24f3e7a02f11c4c149" FOREIGN KEY ("family_id") REFERENCES "distribution_bucket_family"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "distribution_bucket_operator_metadata" ADD CONSTRAINT "FK_69ec9bdc975b95f7dff94a71069" FOREIGN KEY ("distirbution_bucket_operator_id") REFERENCES "distribution_bucket_operator"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."channel_verification" ADD CONSTRAINT "FK_f13d5d785670f46de668575139c" FOREIGN KEY ("channel_id") REFERENCES "admin"."channel"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "admin"."channel_suspension" ADD CONSTRAINT "FK_e30ebff1042c010ff88b87f4f7a" FOREIGN KEY ("channel_id") REFERENCES "admin"."channel"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + await db.query(`ALTER TABLE "member_metadata" ADD CONSTRAINT "FK_e7e4d350f82ae2383894f465ede" FOREIGN KEY ("member_id") REFERENCES "membership"("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED`) + } + + async down(db) { + await db.query(`DROP TABLE "admin"."channel_follow"`) + await db.query(`DROP INDEX "admin"."IDX_822778b4b1ea8e3b60b127cb8b"`) + await db.query(`DROP INDEX "admin"."IDX_9bc0651dda94437ec18764a260"`) + await db.query(`DROP TABLE "admin"."video_view_event"`) + await db.query(`DROP INDEX "admin"."IDX_2e29fba63e12a2b1818e0782d7"`) + await db.query(`DROP INDEX "admin"."IDX_31e1e798ec387ad905cf98d33b"`) + await db.query(`DROP TABLE "admin"."report"`) + await db.query(`DROP INDEX "admin"."IDX_c6686efa4cd49fa9a429f01bac"`) + await db.query(`DROP INDEX "admin"."IDX_893057921f4b5cc37a0ef36684"`) + await db.query(`DROP INDEX "admin"."IDX_f732b6f82095a935db68c9491f"`) + await db.query(`DROP TABLE "admin"."nft_featuring_request"`) + await db.query(`DROP INDEX "admin"."IDX_519be2a41216c278c35f254dcb"`) + await db.query(`DROP INDEX "admin"."IDX_76d87e26cce72ac2e7ffa28dfb"`) + await db.query(`DROP TABLE "admin"."user"`) + await db.query(`DROP TABLE "storage_bucket"`) + await db.query(`DROP TABLE "storage_bucket_bag"`) + await db.query(`DROP INDEX "public"."IDX_aaf00b2c7d0cba49f97da14fbb"`) + await db.query(`DROP INDEX "public"."IDX_4c475f6c9300284b095859eec3"`) + await db.query(`DROP TABLE "distribution_bucket_family"`) + await db.query(`DROP TABLE "distribution_bucket_operator"`) + await db.query(`DROP INDEX "public"."IDX_678dc5427cdde0cd4fef2c07a4"`) + await db.query(`DROP TABLE "distribution_bucket"`) + await db.query(`DROP INDEX "public"."IDX_8cb7454d1ec34b0d3bb7ecdee4"`) + await db.query(`DROP TABLE "distribution_bucket_bag"`) + await db.query(`DROP INDEX "public"."IDX_a9810100aee7584680f197c8ff"`) + await db.query(`DROP INDEX "public"."IDX_32e552d352848d64ab82d38e9a"`) + await db.query(`DROP TABLE "storage_bag"`) + await db.query(`DROP TABLE "admin"."storage_data_object"`) + await db.query(`DROP INDEX "admin"."IDX_ff8014300b8039dbaed764f51b"`) + await db.query(`DROP TABLE "admin"."banned_member"`) + await db.query(`DROP INDEX "admin"."IDX_ed36c6c26bf5410796c2fc21f7"`) + await db.query(`DROP INDEX "admin"."IDX_f29ff095bdb945975deca021ad"`) + await db.query(`DROP TABLE "app"`) + await db.query(`DROP INDEX "public"."IDX_f36adbb7b096ceeb6f3e80ad14"`) + await db.query(`DROP INDEX "public"."IDX_c9cc395bbc485f70a15be64553"`) + await db.query(`DROP TABLE "admin"."channel"`) + await db.query(`DROP INDEX "admin"."IDX_a4752a0a0899dedc4d18077dd0"`) + await db.query(`DROP INDEX "admin"."IDX_25c85bc448b5e236a4c1a5f789"`) + await db.query(`DROP INDEX "admin"."IDX_a77e12f3d8c6ced020e179a5e9"`) + await db.query(`DROP INDEX "admin"."IDX_6997e94413b3f2f25a84e4a96f"`) + await db.query(`DROP INDEX "admin"."IDX_e58a2e1d78b8eccf40531a7fdb"`) + await db.query(`DROP INDEX "admin"."IDX_118ecfa0199aeb5a014906933e"`) + await db.query(`DROP TABLE "admin"."video_featured_in_category"`) + await db.query(`DROP INDEX "admin"."IDX_7b16ddad43901921a8d3c8eab7"`) + await db.query(`DROP INDEX "admin"."IDX_6d0917e1ac0cc06c8075bcf256"`) + await db.query(`DROP TABLE "admin"."video_category"`) + await db.query(`DROP INDEX "admin"."IDX_cbe7e5d162a819e4ee2e2f6105"`) + await db.query(`DROP INDEX "admin"."IDX_da26b34f037c0d59d3c0d0646e"`) + await db.query(`DROP TABLE "admin"."license"`) + await db.query(`DROP TABLE "admin"."video_subtitle"`) + await db.query(`DROP INDEX "admin"."IDX_2203674f18d8052ed6bac39625"`) + await db.query(`DROP INDEX "admin"."IDX_ffa63c28188eecc32af921bfc3"`) + await db.query(`DROP INDEX "admin"."IDX_b6eabfb8de4128b28d73681020"`) + await db.query(`DROP TABLE "admin"."comment_reaction"`) + await db.query(`DROP INDEX "admin"."IDX_15080d9fb7cf8b563103dd9d90"`) + await db.query(`DROP INDEX "admin"."IDX_962582f04d3f639e33f43c54bb"`) + await db.query(`DROP INDEX "admin"."IDX_d7995b1d57614a6fbd0c103874"`) + await db.query(`DROP TABLE "admin"."comment"`) + await db.query(`DROP INDEX "admin"."IDX_3ce66469b26697baa097f8da92"`) + await db.query(`DROP INDEX "admin"."IDX_1ff03403fd31dfeaba0623a89c"`) + await db.query(`DROP INDEX "admin"."IDX_c3c2abe750c76c7c8e305f71f2"`) + await db.query(`DROP INDEX "admin"."IDX_ac69bddf8202b7c0752d9dc8f3"`) + await db.query(`DROP TABLE "admin"."video_reaction"`) + await db.query(`DROP INDEX "admin"."IDX_73dda64f53bbc7ec7035d5e7f0"`) + await db.query(`DROP INDEX "admin"."IDX_436a3836eb47acb5e1e3c88dde"`) + await db.query(`DROP TABLE "admin"."video"`) + await db.query(`DROP INDEX "admin"."IDX_fe2b4b6aace15f1b6610830846"`) + await db.query(`DROP INDEX "admin"."IDX_81b11ef99a9db9ef1aed040d75"`) + await db.query(`DROP INDEX "admin"."IDX_2a5c61f32e9636ee10821e9a58"`) + await db.query(`DROP INDEX "admin"."IDX_8530d052cc79b420f7ce2b4e09"`) + await db.query(`DROP INDEX "admin"."IDX_57b335fa0a960877caf6d2fc29"`) + await db.query(`DROP INDEX "admin"."IDX_3ec633ae5d0477f512b4ed957d"`) + await db.query(`DROP INDEX "admin"."IDX_2db879ed42e3308fe65e679672"`) + await db.query(`DROP INDEX "admin"."IDX_54f88a7decf7d22fd9bd9fa439"`) + await db.query(`DROP INDEX "admin"."IDX_6c49ad08c44d36d11f77c426e4"`) + await db.query(`DROP INDEX "admin"."IDX_f33816960d690ac836f5d5c28a"`) + await db.query(`DROP TABLE "admin"."bid"`) + await db.query(`DROP INDEX "admin"."IDX_9e594e5a61c0f3cb25679f6ba8"`) + await db.query(`DROP INDEX "admin"."IDX_3caf2d6b31d2fe45a2b85b8191"`) + await db.query(`DROP INDEX "admin"."IDX_e7618559409a903a897164156b"`) + await db.query(`DROP INDEX "admin"."IDX_32cb73025ec49c87f4c594a265"`) + await db.query(`DROP TABLE "admin"."owned_nft"`) + await db.query(`DROP INDEX "admin"."IDX_8c7201ed7d4765dcbcc3609356"`) + await db.query(`DROP INDEX "admin"."IDX_466896e39b9ec953f4f2545622"`) + await db.query(`DROP TABLE "admin"."auction"`) + await db.query(`DROP INDEX "admin"."IDX_cfb47e97e60c9d1462576f85a8"`) + await db.query(`DROP INDEX "admin"."IDX_a3127ec87cccc5696b92cac4e0"`) + await db.query(`DROP INDEX "admin"."IDX_1673ad4b059742fbabfc40b275"`) + await db.query(`DROP TABLE "auction_whitelisted_member"`) + await db.query(`DROP INDEX "public"."IDX_d5ae4854487c7658b64225be30"`) + await db.query(`DROP INDEX "public"."IDX_5468573a96fa51c03743de5912"`) + await db.query(`DROP TABLE "membership"`) + await db.query(`DROP INDEX "public"."IDX_0c5b879f9f2ca57a774f74f7f0"`) + await db.query(`DROP TABLE "admin"."event"`) + await db.query(`DROP INDEX "admin"."IDX_8f3f220c4e717207d841d4e6d4"`) + await db.query(`DROP INDEX "admin"."IDX_2c15918ff289396205521c5f3c"`) + await db.query(`DROP TABLE "notification"`) + await db.query(`DROP INDEX "public"."IDX_6bfa96ab97f1a09d73091294ef"`) + await db.query(`DROP INDEX "public"."IDX_122be1f0696e0255acf95f9e33"`) + await db.query(`DROP TABLE "admin"."account"`) + await db.query(`DROP INDEX "admin"."IDX_efef1e5fdbe318a379c06678c5"`) + await db.query(`DROP INDEX "admin"."IDX_4c8f96ccf523e9a3faefd5bdd4"`) + await db.query(`DROP INDEX "admin"."IDX_601b93655bcbe73cb58d8c80cd"`) + await db.query(`DROP INDEX "admin"."IDX_df4da05a7a80c1afd18b8f0990"`) + await db.query(`DROP TABLE "encryption_artifacts"`) + await db.query(`DROP INDEX "public"."IDX_ec8f68a544aadc4fbdadefe4a0"`) + await db.query(`DROP TABLE "admin"."session"`) + await db.query(`DROP INDEX "admin"."IDX_30e98e8746699fb9af235410af"`) + await db.query(`DROP INDEX "admin"."IDX_fae5a6b4a57f098e9af8520d49"`) + await db.query(`DROP INDEX "admin"."IDX_213b5a19bfdbe0ab6e06b1dede"`) + await db.query(`DROP TABLE "session_encryption_artifacts"`) + await db.query(`DROP INDEX "public"."IDX_3612880efd8926a17eba5ab0e1"`) + await db.query(`DROP TABLE "admin"."token"`) + await db.query(`DROP INDEX "admin"."IDX_a6fe18c105f85a63d761ccb078"`) + await db.query(`DROP TABLE "admin"."nft_history_entry"`) + await db.query(`DROP INDEX "admin"."IDX_57f51d35ecab042478fe2e31c1"`) + await db.query(`DROP INDEX "admin"."IDX_d1a28b178f5d028d048d40ce20"`) + await db.query(`DROP TABLE "admin"."nft_activity"`) + await db.query(`DROP INDEX "admin"."IDX_18a65713a9fd0715c7a980f5d5"`) + await db.query(`DROP INDEX "admin"."IDX_94d325a753f2c08fdd416eb095"`) + await db.query(`DROP TABLE "admin"."email_delivery_attempt"`) + await db.query(`DROP INDEX "admin"."IDX_f985b9b362249af72cac0f52a3"`) + await db.query(`DROP TABLE "admin"."notification_email_delivery"`) + await db.query(`DROP INDEX "admin"."IDX_3b756627c3146db150d66d1292"`) + await db.query(`DROP TABLE "admin"."video_hero"`) + await db.query(`DROP INDEX "admin"."IDX_9feac5d9713a9f07e32eb8ba7a"`) + await db.query(`DROP TABLE "admin"."video_media_encoding"`) + await db.query(`DROP TABLE "admin"."video_media_metadata"`) + await db.query(`DROP INDEX "admin"."IDX_5944dc5896cb16bd395414a0ce"`) + await db.query(`DROP INDEX "admin"."IDX_4dc101240e8e1536b770aee202"`) + await db.query(`DROP TABLE "admin"."gateway_config"`) + await db.query(`DROP TABLE "admin"."exclusion"`) + await db.query(`DROP INDEX "admin"."IDX_efba55b85909822c2b7655dfb8"`) + await db.query(`DROP INDEX "admin"."IDX_2729041b2f528a6c5833fdb3e5"`) + await db.query(`DROP TABLE "storage_bucket_operator_metadata"`) + await db.query(`DROP INDEX "public"."IDX_7beffc9530b3f307bc1169cb52"`) + await db.query(`DROP TABLE "distribution_bucket_family_metadata"`) + await db.query(`DROP INDEX "public"."IDX_dd93ca0ea24f3e7a02f11c4c14"`) + await db.query(`DROP INDEX "public"."IDX_5510d3b244a63d6ec702faa426"`) + await db.query(`DROP TABLE "distribution_bucket_operator_metadata"`) + await db.query(`DROP INDEX "public"."IDX_69ec9bdc975b95f7dff94a7106"`) + await db.query(`DROP TABLE "admin"."channel_verification"`) + await db.query(`DROP INDEX "admin"."IDX_f13d5d785670f46de668575139"`) + await db.query(`DROP TABLE "admin"."channel_suspension"`) + await db.query(`DROP INDEX "admin"."IDX_e30ebff1042c010ff88b87f4f7"`) + await db.query(`DROP TABLE "curator_group"`) + await db.query(`DROP TABLE "curator"`) + await db.query(`DROP TABLE "member_metadata"`) + await db.query(`DROP INDEX "public"."IDX_e7e4d350f82ae2383894f465ed"`) + await db.query(`DROP TABLE "next_entity_id"`) + await db.query(`ALTER TABLE "admin"."channel_follow" DROP CONSTRAINT "FK_822778b4b1ea8e3b60b127cb8b1"`) + await db.query(`ALTER TABLE "admin"."video_view_event" DROP CONSTRAINT "FK_31e1e798ec387ad905cf98d33b0"`) + await db.query(`ALTER TABLE "admin"."report" DROP CONSTRAINT "FK_c6686efa4cd49fa9a429f01bac8"`) + await db.query(`ALTER TABLE "admin"."nft_featuring_request" DROP CONSTRAINT "FK_519be2a41216c278c35f254dcba"`) + await db.query(`ALTER TABLE "storage_bucket_bag" DROP CONSTRAINT "FK_791e2f82e3919ffcef8712aa1b9"`) + await db.query(`ALTER TABLE "storage_bucket_bag" DROP CONSTRAINT "FK_aaf00b2c7d0cba49f97da14fbba"`) + await db.query(`ALTER TABLE "distribution_bucket_operator" DROP CONSTRAINT "FK_678dc5427cdde0cd4fef2c07a43"`) + await db.query(`ALTER TABLE "distribution_bucket" DROP CONSTRAINT "FK_8cb7454d1ec34b0d3bb7ecdee4e"`) + await db.query(`ALTER TABLE "distribution_bucket_bag" DROP CONSTRAINT "FK_8a807921f1aae60d4ba94895826"`) + await db.query(`ALTER TABLE "distribution_bucket_bag" DROP CONSTRAINT "FK_a9810100aee7584680f197c8ff0"`) + await db.query(`ALTER TABLE "admin"."storage_data_object" DROP CONSTRAINT "FK_ff8014300b8039dbaed764f51bc"`) + await db.query(`ALTER TABLE "admin"."banned_member" DROP CONSTRAINT "FK_b94ea874da235d9b6fbc35cf58e"`) + await db.query(`ALTER TABLE "admin"."banned_member" DROP CONSTRAINT "FK_ed36c6c26bf5410796c2fc21f74"`) + await db.query(`ALTER TABLE "app" DROP CONSTRAINT "FK_c9cc395bbc485f70a15be64553e"`) + await db.query(`ALTER TABLE "admin"."channel" DROP CONSTRAINT "FK_25c85bc448b5e236a4c1a5f7895"`) + await db.query(`ALTER TABLE "admin"."channel" DROP CONSTRAINT "FK_a77e12f3d8c6ced020e179a5e94"`) + await db.query(`ALTER TABLE "admin"."channel" DROP CONSTRAINT "FK_6997e94413b3f2f25a84e4a96f8"`) + await db.query(`ALTER TABLE "admin"."channel" DROP CONSTRAINT "FK_118ecfa0199aeb5a014906933e8"`) + await db.query(`ALTER TABLE "admin"."video_featured_in_category" DROP CONSTRAINT "FK_7b16ddad43901921a8d3c8eab71"`) + await db.query(`ALTER TABLE "admin"."video_featured_in_category" DROP CONSTRAINT "FK_0e6bb49ce9d022cd872f3ab4288"`) + await db.query(`ALTER TABLE "admin"."video_category" DROP CONSTRAINT "FK_da26b34f037c0d59d3c0d0646e9"`) + await db.query(`ALTER TABLE "admin"."video_subtitle" DROP CONSTRAINT "FK_2203674f18d8052ed6bac396252"`) + await db.query(`ALTER TABLE "admin"."video_subtitle" DROP CONSTRAINT "FK_b6eabfb8de4128b28d73681020f"`) + await db.query(`ALTER TABLE "admin"."comment_reaction" DROP CONSTRAINT "FK_15080d9fb7cf8b563103dd9d900"`) + await db.query(`ALTER TABLE "admin"."comment_reaction" DROP CONSTRAINT "FK_962582f04d3f639e33f43c54bbc"`) + await db.query(`ALTER TABLE "admin"."comment_reaction" DROP CONSTRAINT "FK_d7995b1d57614a6fbd0c103874d"`) + await db.query(`ALTER TABLE "admin"."comment" DROP CONSTRAINT "FK_3ce66469b26697baa097f8da923"`) + await db.query(`ALTER TABLE "admin"."comment" DROP CONSTRAINT "FK_1ff03403fd31dfeaba0623a89cf"`) + await db.query(`ALTER TABLE "admin"."comment" DROP CONSTRAINT "FK_ac69bddf8202b7c0752d9dc8f32"`) + await db.query(`ALTER TABLE "admin"."video_reaction" DROP CONSTRAINT "FK_73dda64f53bbc7ec7035d5e7f09"`) + await db.query(`ALTER TABLE "admin"."video_reaction" DROP CONSTRAINT "FK_436a3836eb47acb5e1e3c88ddea"`) + await db.query(`ALTER TABLE "admin"."video" DROP CONSTRAINT "FK_81b11ef99a9db9ef1aed040d750"`) + await db.query(`ALTER TABLE "admin"."video" DROP CONSTRAINT "FK_2a5c61f32e9636ee10821e9a58d"`) + await db.query(`ALTER TABLE "admin"."video" DROP CONSTRAINT "FK_8530d052cc79b420f7ce2b4e09d"`) + await db.query(`ALTER TABLE "admin"."video" DROP CONSTRAINT "FK_3ec633ae5d0477f512b4ed957d6"`) + await db.query(`ALTER TABLE "admin"."video" DROP CONSTRAINT "FK_2db879ed42e3308fe65e6796729"`) + await db.query(`ALTER TABLE "admin"."video" DROP CONSTRAINT "FK_54f88a7decf7d22fd9bd9fa439a"`) + await db.query(`ALTER TABLE "admin"."video" DROP CONSTRAINT "FK_6c49ad08c44d36d11f77c426e43"`) + await db.query(`ALTER TABLE "admin"."bid" DROP CONSTRAINT "FK_9e594e5a61c0f3cb25679f6ba8d"`) + await db.query(`ALTER TABLE "admin"."bid" DROP CONSTRAINT "FK_3caf2d6b31d2fe45a2b85b81912"`) + await db.query(`ALTER TABLE "admin"."bid" DROP CONSTRAINT "FK_e7618559409a903a897164156b7"`) + await db.query(`ALTER TABLE "admin"."bid" DROP CONSTRAINT "FK_32cb73025ec49c87f4c594a265f"`) + await db.query(`ALTER TABLE "admin"."owned_nft" DROP CONSTRAINT "FK_466896e39b9ec953f4f2545622d"`) + await db.query(`ALTER TABLE "admin"."auction" DROP CONSTRAINT "FK_cfb47e97e60c9d1462576f85a88"`) + await db.query(`ALTER TABLE "admin"."auction" DROP CONSTRAINT "FK_a3127ec87cccc5696b92cac4e09"`) + await db.query(`ALTER TABLE "admin"."auction" DROP CONSTRAINT "FK_1673ad4b059742fbabfc40b275c"`) + await db.query(`ALTER TABLE "auction_whitelisted_member" DROP CONSTRAINT "FK_aad797677bc7c7c7dc1f1d397f5"`) + await db.query(`ALTER TABLE "auction_whitelisted_member" DROP CONSTRAINT "FK_d5ae4854487c7658b64225be305"`) + await db.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_6bfa96ab97f1a09d73091294efc"`) + await db.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_122be1f0696e0255acf95f9e336"`) + await db.query(`ALTER TABLE "admin"."account" DROP CONSTRAINT "FK_efef1e5fdbe318a379c06678c51"`) + await db.query(`ALTER TABLE "admin"."account" DROP CONSTRAINT "FK_601b93655bcbe73cb58d8c80cd3"`) + await db.query(`ALTER TABLE "encryption_artifacts" DROP CONSTRAINT "FK_ec8f68a544aadc4fbdadefe4a0a"`) + await db.query(`ALTER TABLE "admin"."session" DROP CONSTRAINT "FK_30e98e8746699fb9af235410aff"`) + await db.query(`ALTER TABLE "admin"."session" DROP CONSTRAINT "FK_fae5a6b4a57f098e9af8520d499"`) + await db.query(`ALTER TABLE "session_encryption_artifacts" DROP CONSTRAINT "FK_3612880efd8926a17eba5ab0e1a"`) + await db.query(`ALTER TABLE "admin"."token" DROP CONSTRAINT "FK_a6fe18c105f85a63d761ccb0780"`) + await db.query(`ALTER TABLE "admin"."nft_history_entry" DROP CONSTRAINT "FK_57f51d35ecab042478fe2e31c19"`) + await db.query(`ALTER TABLE "admin"."nft_history_entry" DROP CONSTRAINT "FK_d1a28b178f5d028d048d40ce208"`) + await db.query(`ALTER TABLE "admin"."nft_activity" DROP CONSTRAINT "FK_18a65713a9fd0715c7a980f5d54"`) + await db.query(`ALTER TABLE "admin"."nft_activity" DROP CONSTRAINT "FK_94d325a753f2c08fdd416eb095f"`) + await db.query(`ALTER TABLE "admin"."email_delivery_attempt" DROP CONSTRAINT "FK_f985b9b362249af72cac0f52a3b"`) + await db.query(`ALTER TABLE "admin"."notification_email_delivery" DROP CONSTRAINT "FK_3b756627c3146db150d66d12929"`) + await db.query(`ALTER TABLE "admin"."video_hero" DROP CONSTRAINT "FK_9feac5d9713a9f07e32eb8ba7a1"`) + await db.query(`ALTER TABLE "admin"."video_media_metadata" DROP CONSTRAINT "FK_5944dc5896cb16bd395414a0ce0"`) + await db.query(`ALTER TABLE "admin"."video_media_metadata" DROP CONSTRAINT "FK_4dc101240e8e1536b770aee202a"`) + await db.query(`ALTER TABLE "storage_bucket_operator_metadata" DROP CONSTRAINT "FK_7beffc9530b3f307bc1169cb524"`) + await db.query(`ALTER TABLE "distribution_bucket_family_metadata" DROP CONSTRAINT "FK_dd93ca0ea24f3e7a02f11c4c149"`) + await db.query(`ALTER TABLE "distribution_bucket_operator_metadata" DROP CONSTRAINT "FK_69ec9bdc975b95f7dff94a71069"`) + await db.query(`ALTER TABLE "admin"."channel_verification" DROP CONSTRAINT "FK_f13d5d785670f46de668575139c"`) + await db.query(`ALTER TABLE "admin"."channel_suspension" DROP CONSTRAINT "FK_e30ebff1042c010ff88b87f4f7a"`) + await db.query(`ALTER TABLE "member_metadata" DROP CONSTRAINT "FK_e7e4d350f82ae2383894f465ede"`) + } +} diff --git a/db/migrations/1708169664028-Views.js b/db/migrations/1708169664028-Views.js new file mode 100644 index 000000000..2504f241d --- /dev/null +++ b/db/migrations/1708169664028-Views.js @@ -0,0 +1,31 @@ + +const { getViewDefinitions } = require('../viewDefinitions') + +module.exports = class Views1708169664028 { + name = 'Views1708169664028' + + async up(db) { + const viewDefinitions = getViewDefinitions(db); + for (const [tableName, viewConditions] of Object.entries(viewDefinitions)) { + if (Array.isArray(viewConditions)) { + await db.query(` + CREATE OR REPLACE VIEW "${tableName}" AS + SELECT * + FROM "admin"."${tableName}" AS "this" + WHERE ${viewConditions.map(cond => `(${cond})`).join(' AND ')} + `); + } else { + await db.query(` + CREATE OR REPLACE VIEW "${tableName}" AS (${viewConditions}) + `); + } + } + } + + async down(db) { + const viewDefinitions = this.getViewDefinitions(db) + for (const viewName of Object.keys(viewDefinitions)) { + await db.query(`DROP VIEW "${viewName}"`) + } + } +} diff --git a/db/migrations/2000000000000-Views.js b/db/migrations/2000000000000-Views.js deleted file mode 100644 index a12612734..000000000 --- a/db/migrations/2000000000000-Views.js +++ /dev/null @@ -1,121 +0,0 @@ -const noCategoryVideosSupportedByDefault = - process.env.SUPPORT_NO_CATEGORY_VIDEOS === 'true' || - process.env.SUPPORT_NO_CATEGORY_VIDEOS === '1' - -module.exports = class Views2000000000000 { - name = 'Views2000000000000' - - getViewDefinitions(db) { - return { - channel: [`is_excluded='0'`, `is_censored='0'`], - banned_member: [`EXISTS(SELECT 1 FROM "channel" WHERE "id"="channel_id")`], - video: [ - `is_excluded='0'`, - `is_censored='0'`, - `EXISTS(SELECT 1 FROM "channel" WHERE "id"="channel_id")`, - `EXISTS(SELECT 1 FROM "video_category" WHERE "id"="category_id" AND "is_supported"='1') - OR ( - "category_id" IS NULL - AND COALESCE( - (SELECT "value" FROM "gateway_config" WHERE "id"='SUPPORT_NO_CATEGORY_VIDEOS'), - ${noCategoryVideosSupportedByDefault ? "'1'" : "'0'"} - )='1' - )` - ], - video_category: [`"is_supported" = '1'`], - owned_nft: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], - auction: [`EXISTS(SELECT 1 FROM "owned_nft" WHERE "id"="nft_id")`], - bid: [`EXISTS(SELECT 1 FROM "owned_nft" WHERE "id"="nft_id")`], - comment: ` - SELECT - ${db.connection - .getMetadata('Comment') - .columns.filter((c) => c.databaseName !== 'text') - .map((c) => `"${c.databaseName}"`) - .join(',')}, - CASE WHEN "is_excluded" = '1' THEN '' ELSE "comment"."text" END as "text" - FROM - "admin"."comment" - WHERE EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id") - `, - comment_reaction: [`EXISTS(SELECT 1 FROM "comment" WHERE "id"="comment_id")`], - license: [`EXISTS(SELECT 1 FROM "video" WHERE "license_id"="this"."id")`], - video_media_metadata: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], - video_media_encoding: [`EXISTS(SELECT 1 FROM "video_media_metadata" WHERE "encoding_id"="this"."id")`], - video_reaction: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], - video_subtitle: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], - video_featured_in_category: [ - `EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`, - `EXISTS(SELECT 1 FROM "video_category" WHERE "id"="category_id")` - ], - video_hero: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], - // TODO: Consider all events having ref to a video they're related to - this will make filtering much easier - event: [ - `("data"->>'channel' IS NULL OR EXISTS(SELECT 1 FROM "channel" WHERE "id"="data"->>'channel'))`, - `("data"->>'video' IS NULL OR EXISTS(SELECT 1 FROM "video" WHERE "id"="data"->>'video'))`, - `("data"->>'nft' IS NULL OR EXISTS(SELECT 1 FROM "owned_nft" WHERE "id"="data"->>'nft'))`, - `("data"->>'auction' IS NULL OR EXISTS(SELECT 1 FROM "auction" WHERE "id"="data"->>'auction'))`, - `("data"->>'bid' IS NULL OR EXISTS(SELECT 1 FROM "bid" WHERE "id"="data"->>'bid'))`, - `("data"->>'winningBid' IS NULL OR EXISTS(SELECT 1 FROM "bid" WHERE "id"="data"->>'winningBid'))`, - `("data"->>'comment' IS NULL OR EXISTS(SELECT 1 FROM "comment" WHERE "id"="data"->>'comment'))` - ], - storage_data_object: [ - `("type"->>'channel' IS NULL OR EXISTS(SELECT 1 FROM "channel" WHERE "id"="type"->>'channel'))`, - `("type"->>'video' IS NULL OR EXISTS(SELECT 1 FROM "video" WHERE "id"="type"->>'video'))` - ], - nft_history_entry: [`EXISTS(SELECT 1 FROM "event" WHERE "id"="event_id")`], - nft_activity: [`EXISTS(SELECT 1 FROM "event" WHERE "id"="event_id")`], - // HIDDEN entities - video_view_event: ['FALSE'], - channel_follow: ['FALSE'], - report: ['FALSE'], - exclusion: ['FALSE'], - session: ['FALSE'], - notification_email_delivery: ['FALSE'], - channel_verification: ['FALSE'], - channel_suspension: ['FALSE'], - user: ['FALSE'], - account: ['FALSE'], - token: ['FALSE'], - nft_featuring_request: ['FALSE'], - gateway_config: ['FALSE'], - email_delivery_attempt: ['FALSE'], - // TODO (notifications v2): make this part of the admin schema with appropriate resolver for queries - // notification: ['FALSE'], - } - } - - async up(db) { - const viewDefinitions = this.getViewDefinitions(db) - // Create a new "admin" schema through which the "hidden" entities can be accessed - await db.query(`CREATE SCHEMA "admin"`) - // Create admin user with "admin" schema in default "search_path" - await db.query(`CREATE USER "${process.env.DB_ADMIN_USER}" WITH PASSWORD '${process.env.DB_ADMIN_PASS}'`) - await db.query(`GRANT pg_read_all_data TO "${process.env.DB_ADMIN_USER}"`) - await db.query(`GRANT pg_write_all_data TO "${process.env.DB_ADMIN_USER}"`) - await db.query(`ALTER USER "${process.env.DB_ADMIN_USER}" SET search_path TO admin,public`) - for (const [tableName, viewConditions] of Object.entries(viewDefinitions)) { - await db.query(`ALTER TABLE "${tableName}" SET SCHEMA "admin"`) - if (Array.isArray(viewConditions)) { - await db.query(` - CREATE VIEW "${tableName}" AS - SELECT * - FROM "admin"."${tableName}" AS "this" - WHERE ${viewConditions.map(cond => `(${cond})`).join(" AND\n")} - `) - } else { - await db.query(` - CREATE VIEW "${tableName}" AS (${viewConditions})`) - } - } - } - - async down(db) { - const viewDefinitions = this.getViewDefinitions(db) - for (const viewName of Object.keys(viewDefinitions)) { - await db.query(`DROP VIEW "${viewName}"`) - await db.query(`ALTER TABLE "admin"."${viewName}" SET SCHEMA "public"`) - } - await db.query(`DROP SCHEMA "admin"`) - } -} diff --git a/db/migrations/2100000000000-Indexes.js b/db/migrations/2200000000000-Indexes.js similarity index 97% rename from db/migrations/2100000000000-Indexes.js rename to db/migrations/2200000000000-Indexes.js index 347b3ce50..ab5795f5a 100644 --- a/db/migrations/2100000000000-Indexes.js +++ b/db/migrations/2200000000000-Indexes.js @@ -1,5 +1,5 @@ -module.exports = class Indexes2000000000000 { - name = 'Indexes2000000000000' +module.exports = class Indexes2200000000000 { + name = 'Indexes2200000000000' async up(db) { await db.query(`CREATE INDEX "events_video" ON "admin"."event" USING BTREE (("data"->>'video'));`) diff --git a/db/migrations/2200000000000-Operator.js b/db/migrations/2300000000000-Operator.js similarity index 83% rename from db/migrations/2200000000000-Operator.js rename to db/migrations/2300000000000-Operator.js index c6a0d008b..a6886f6eb 100644 --- a/db/migrations/2200000000000-Operator.js +++ b/db/migrations/2300000000000-Operator.js @@ -1,6 +1,7 @@ const { randomAsHex } = require("@polkadot/util-crypto") const { existsSync } = require("fs") const path = require('path') +const { OffchainState } = require('../../lib/utils/offchainState') module.exports = class Operator2300000000000 { name = 'Operator2300000000000' @@ -9,7 +10,8 @@ module.exports = class Operator2300000000000 { // Support only one operator account at the moment to avoid confusion const exportFilePath = path.join(__dirname, '../export/export.json') if (existsSync(exportFilePath)) { - const exportData = require(exportFilePath) + const offchainState = new OffchainState() + const exportData = await offchainState.readExportJsonFile(exportFilePath) if (exportData.data.User) { // If export exists and contains user data, skip this migration return diff --git a/db/viewDefinitions.js b/db/viewDefinitions.js new file mode 100644 index 000000000..1b14f2cbb --- /dev/null +++ b/db/viewDefinitions.js @@ -0,0 +1,93 @@ +const noCategoryVideosSupportedByDefault = + process.env.SUPPORT_NO_CATEGORY_VIDEOS === 'true' || + process.env.SUPPORT_NO_CATEGORY_VIDEOS === '1' + +// Add public 'VIEW' definitions for hidden entities created by +// applying `@schema(name: "admin") directive to the Graphql entities +function getViewDefinitions(db) { + return { + channel: [`is_excluded='0'`, `is_censored='0'`], + banned_member: [`EXISTS(SELECT 1 FROM "channel" WHERE "id"="channel_id")`], + video: [ + `is_excluded='0'`, + `is_censored='0'`, + `EXISTS(SELECT 1 FROM "channel" WHERE "id"="channel_id")`, + `EXISTS(SELECT 1 FROM "admin"."video_category" WHERE "id"="category_id" AND "is_supported"='1') + OR ( + "category_id" IS NULL + AND COALESCE( + (SELECT "value" FROM "admin"."gateway_config" WHERE "id"='SUPPORT_NO_CATEGORY_VIDEOS'), + ${noCategoryVideosSupportedByDefault ? "'1'" : "'0'"} + )='1' + )`, + ], + video_category: [`"is_supported" = '1'`], + owned_nft: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], + auction: [`EXISTS(SELECT 1 FROM "owned_nft" WHERE "id"="nft_id")`], + bid: [`EXISTS(SELECT 1 FROM "owned_nft" WHERE "id"="nft_id")`], + comment: ` + SELECT + ${db.connection + .getMetadata('Comment') + .columns.filter((c) => c.databaseName !== 'text') + .map((c) => `"${c.databaseName}"`) + .join(',')}, + CASE WHEN "is_excluded" = '1' THEN '' ELSE "comment"."text" END as "text" + FROM + "admin"."comment" + WHERE EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id") + `, + comment_reaction: [`EXISTS(SELECT 1 FROM "comment" WHERE "id"="comment_id")`], + license: [`EXISTS(SELECT 1 FROM "video" WHERE "license_id"="this"."id")`], + video_media_metadata: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], + video_media_encoding: [ + `EXISTS(SELECT 1 FROM "video_media_metadata" WHERE "encoding_id"="this"."id")`, + ], + video_reaction: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], + video_subtitle: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], + video_featured_in_category: [ + `EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`, + `EXISTS(SELECT 1 FROM "video_category" WHERE "id"="category_id")`, + ], + video_hero: [`EXISTS(SELECT 1 FROM "video" WHERE "id"="video_id")`], + // TODO: Consider all events having ref to a video they're related to - this will make filtering much easier + event: [ + `("data"->>'channel' IS NULL OR EXISTS(SELECT 1 FROM "channel" WHERE "id"="data"->>'channel'))`, + `("data"->>'video' IS NULL OR EXISTS(SELECT 1 FROM "video" WHERE "id"="data"->>'video'))`, + `("data"->>'nft' IS NULL OR EXISTS(SELECT 1 FROM "owned_nft" WHERE "id"="data"->>'nft'))`, + `("data"->>'auction' IS NULL OR EXISTS(SELECT 1 FROM "auction" WHERE "id"="data"->>'auction'))`, + `("data"->>'bid' IS NULL OR EXISTS(SELECT 1 FROM "bid" WHERE "id"="data"->>'bid'))`, + `("data"->>'winningBid' IS NULL OR EXISTS(SELECT 1 FROM "bid" WHERE "id"="data"->>'winningBid'))`, + `("data"->>'comment' IS NULL OR EXISTS(SELECT 1 FROM "comment" WHERE "id"="data"->>'comment'))`, + ], + storage_data_object: [ + `("type"->>'channel' IS NULL OR EXISTS(SELECT 1 FROM "channel" WHERE "id"="type"->>'channel'))`, + `("type"->>'video' IS NULL OR EXISTS(SELECT 1 FROM "video" WHERE "id"="type"->>'video'))`, + ], + nft_history_entry: [`EXISTS(SELECT 1 FROM "event" WHERE "id"="event_id")`], + nft_activity: [`EXISTS(SELECT 1 FROM "event" WHERE "id"="event_id")`], + // *** HIDDEN entities *** + // Even though the following entities are hidden by default (because they are part of "admin" schema) + // we still define these in the views definitions to create their VIEW in the public schema as they are + // exposed by the GRAPHQL API, so that when querying the GRAPHQL API, the response is just empty object + // instead of `"relation does not exist"` error. + video_view_event: ['FALSE'], + channel_follow: ['FALSE'], + report: ['FALSE'], + exclusion: ['FALSE'], + session: ['FALSE'], + notification_email_delivery: ['FALSE'], + channel_verification: ['FALSE'], + channel_suspension: ['FALSE'], + user: ['FALSE'], + account: ['FALSE'], + token: ['FALSE'], + nft_featuring_request: ['FALSE'], + gateway_config: ['FALSE'], + email_delivery_attempt: ['FALSE'], + // TODO (notifications v2): make this part of the admin schema with appropriate resolver for queries + // notification: ['FALSE'], + } +} + +module.exports = { getViewDefinitions } diff --git a/docs/developer-guide/tutorials/entity-visibility.md b/docs/developer-guide/tutorials/entity-visibility.md index e49a23465..810ef0e66 100644 --- a/docs/developer-guide/tutorials/entity-visibility.md +++ b/docs/developer-guide/tutorials/entity-visibility.md @@ -28,7 +28,7 @@ SET LOCAL search_path TO admin,public; SET LOCAL search_path TO DEFAULT ``` -Some database users can also have different `search_path` set as their default. If you inspect `db/migrations/2000000000000-Views.js` file, you'll notice that we're creating an `admin` user with the `admin` schema set as the default one. The `admin` user credentials can be configured via `DB_ADMIN_USER` and `DB_ADMIN_PASSWORD` environment variables. +Some database users can also have different `search_path` set as their default. If you inspect `db/migrations/1000000000000-Admin.js` file, you'll notice that we're creating an `admin` user with the `admin` schema set as the default one. The `admin` user credentials can be configured via `DB_ADMIN_USER` and `DB_ADMIN_PASSWORD` environment variables. The general rules about what schema is being used in which context are as follows: - `admin` schema is by default used by Orion's event processor, as it needs to be able to process events related to hidden/censored entities as well. @@ -38,7 +38,9 @@ The general rules about what schema is being used in which context are as follow ## Managing entity visibility -In order to adjust the visibility of the data, either because you're introducing new entities / fields or because you'd like to change the existing rules, you can modify the `getViewDefinitions` method in `db/migrations/2000000000000-Views.js`. +If you want an entity (either one or all of it's fields) to be not part of the `public` schema, then while creating the Graphql definition of given entity decorate it with the `@schema(name: "admin")` directive. This will ensure that the entity/table is part of `admin` schema and so the GraphQL API wont expose any data associated with such entities + +Dy decorating the GRAPHQL entity with `@schema(name: "admin")` directive, the entity data will be entirely invisible. To adjust the visibility of the data, either because you want to expose some of the fields, you need to add the visibility rules by modifying the `getViewDefinitions` method in `db/viewDefinitions.js`. This method returns an object which maps the database table name to one of the following: - an **array** of `WHERE` conditions that will be applied to the public view of that table. Those `WHERE` conditions are used to filter out the hidden entities from the public view. They will be joined using `AND` operator. In case you wish to hide the whole table, you can set the conditions to `['FALSE']`, which will result in a view that always returns an empty result set. @@ -46,7 +48,7 @@ This method returns an object which maps the database table name to one of the f Suppose you introduced a new `UserOpinion` entity, which will hold user's feedback about the Gateway. The input schema for this entity may look like this: ```graphql -type UserOpinion { +type UserOpinion @schema(name: "admin") { id: ID! userAccount: Account! opinion: String! @@ -56,7 +58,7 @@ type UserOpinion { } ``` -Since `Account` is already a hidden entity (it has a view definition with WHERE conditions set to `['FALSE']`), if someone (who's not an authenticated Gateway operator) tries to access the `userAccount` field of `UserOpinion` through a GraphQL API query, they will get an error like this: +Since `Account` is already a hidden entity (it is decorated with `@schema(name: "admin")` directive), if someone (who's not an authenticated Gateway operator) tries to access the `userAccount` field of `UserOpinion` through a GraphQL API query, they will get an error like this: ![image](../assets/user-opinions-error.png) diff --git a/docs/operator-guide/tutorials/upgrading-orion.md b/docs/operator-guide/tutorials/upgrading-orion.md index bfa1cad80..69c9ab922 100644 --- a/docs/operator-guide/tutorials/upgrading-orion.md +++ b/docs/operator-guide/tutorials/upgrading-orion.md @@ -22,15 +22,15 @@ Always make sure the versions of Orion and Atlas you're planing to upgrade to ar 1. **Backup the databse** before the upgrade. You can do that by executing the following command on the production server: ```bash - docker exec orion-db pg_dumpall -U postgres > "orion-production-$(date '+%Y-%m-%d').bak" + docker exec orion_db pg_dumpall -U postgres -p 23798 > "orion-production-$(date '+%Y-%m-%d').bak" ``` - Make sure the backup file was succesfully created in the current directory. + Make sure the backup file was successfully created in the current directory. 1. Stop the processor and create [Offchain data export](../../developer-guide/tutorials/preserving-offchain-state.md) file: ```bash - docker-compose stop orion-processor - docker-compose run --rm orion-processor npm run offchain-state:export + docker-compose stop orion_processor + docker-compose run --rm orion_processor npm run offchain-state:export ``` - Make sure the export file was created succesfully under `./db/export/export.json` + Make sure the export file was created successfully under `./db/export/export.json` 1. Download the latest Orion docker image: ```bash docker tag joystream/orion:latest joystream/orion:previous @@ -46,9 +46,9 @@ Always make sure the versions of Orion and Atlas you're planing to upgrade to ar ``` 1. Wait for the Orion processor to catch up with the Joystream blockchain before disabling the _kill switch_. You can follow the processor logs using: ```bash - docker logs -f --tail 10 orion-processor + docker logs -f --tail 10 orion_processor ``` - You can also check the logs of other docker services, ie. `orion-graphql-api`, `orion-auth-api` and `orion-db` to make sure they are running as expected. + You can also check the logs of other docker services, ie. `orion_graphql-api`, `orion_auth-api` and `orion_db` to make sure they are running as expected. 1. After the processor is synced, you can run some test queries on `https://query.mygateway.com/graphql` (first you'll need to authenticate, for example through `https://auth.mygateway.com/playground`) to make sure the new version is working as expected. 1. Once you're confident that the release was successful, disable the _kill switch_ by executing `setKillSwitch(isKilled: false)` operator mutation using Orion's GraphQL API. @@ -63,12 +63,12 @@ In case something goes wrong during the upgrade, you can restore the database fr # Switch back to the previous version of joystream/orion docker image docker tag joystream/orion:previous joystream/orion:latest # Start the orion-db service - docker-compose up -d orion-db + docker-compose up -d orion_db # Copy the backup file to the orion-db container # Replace the YYYY-mm-dd with the date of the backup you wish to restore - docker cp "orion-production-YYYY-mm-dd.bak" orion-db:/tmp/orion-production.bak + docker cp "orion-production-YYYY-mm-dd.bak" orion_db:/tmp/orion-production.bak # Restore the database - docker exec orion-db psql -f /tmp/orion-production.bak -U postgres postgres + docker exec orion_db psql -f /tmp/orion-production.bak -U postgres -p 23798 postgres # Bring up the Orion services docker-compose up -d ``` \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b4616cdcb..582c88572 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orion", - "version": "3.2.1", + "version": "3.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "orion", - "version": "3.2.1", + "version": "3.4.0", "hasInstallScript": true, "dependencies": { "@joystream/js": "^1.4.0", @@ -33,6 +33,7 @@ "ajv": "^6.11.0", "async-lock": "^1.3.1", "axios": "^1.2.1", + "big-json": "^3.2.0", "cookie-parser": "^1.4.6", "csv-stringify": "^6.3.0", "dayjs": "^1.11.7", @@ -69,6 +70,7 @@ "@subsquid/substrate-typegen": "^2.1.0", "@subsquid/typeorm-codegen": "^0.3.1", "@types/async-lock": "^1.1.3", + "@types/big-json": "^3.2.4", "@types/chai": "^4.3.5", "@types/cookie-parser": "^1.4.3", "@types/express-rate-limit": "^6.0.0", @@ -9997,6 +9999,15 @@ "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.81.tgz", "integrity": "sha512-C1rFKGVZ8KwqhwBOYlpoybTSRtxu2433ea6JaO3amc6ubEe08yQoFsPa9aU9YqvX7ppeZ25CnCtC4AH9mhtxsQ==" }, + "node_modules/@types/big-json": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@types/big-json/-/big-json-3.2.4.tgz", + "integrity": "sha512-9j4OYGHfHazBz7WxRs1tqXy2qccjYAa4ej3vfT0uIPFvlX6nYw9Mvgxijvww6OKZE0aK6kFHTXDxR0uVJiRhLw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/bn.js": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", @@ -11863,6 +11874,14 @@ "node": ">=12.0.0" } }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -12098,6 +12117,28 @@ "node": ">=10.0.0" } }, + "node_modules/big-json": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big-json/-/big-json-3.2.0.tgz", + "integrity": "sha512-2Etdurszm1CAFxqpH08lItXyf5CI1OBKRn7imCeI8Lh+a2UvdN2WpuSduxB/3ccao6v93SxiS5fIlE/v1QLoPg==", + "dependencies": { + "assert-plus": "^1.0.0", + "into-stream": "^5.1.0", + "json-stream-stringify": "^2.0.1", + "JSONStream": "^1.3.1", + "once": "^1.4.0", + "through2": "^3.0.1" + } + }, + "node_modules/big-json/node_modules/through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, "node_modules/bignumber.js": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", @@ -15975,6 +16016,47 @@ "node": ">= 0.6" } }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/from2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/from2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/from2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/from2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -17663,6 +17745,18 @@ "node": ">= 0.4" } }, + "node_modules/into-stream": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz", + "integrity": "sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==", + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -20146,6 +20240,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-stream-stringify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-2.0.4.tgz", + "integrity": "sha512-gIPoa6K5w6j/RnQ3fOtmvICKNJGViI83A7dnTIL+0QJ/1GKuNvCPFvbFWxt0agruF4iGgDFJvge4Gua4ZoiggQ==" + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -20216,6 +20315,21 @@ "node >= 0.2.0" ] }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/jsonstream-next": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/jsonstream-next/-/jsonstream-next-3.0.0.tgz", @@ -22800,6 +22914,14 @@ "p-defer": "^3.0.0" } }, + "node_modules/p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -34905,6 +35027,15 @@ "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.81.tgz", "integrity": "sha512-C1rFKGVZ8KwqhwBOYlpoybTSRtxu2433ea6JaO3amc6ubEe08yQoFsPa9aU9YqvX7ppeZ25CnCtC4AH9mhtxsQ==" }, + "@types/big-json": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@types/big-json/-/big-json-3.2.4.tgz", + "integrity": "sha512-9j4OYGHfHazBz7WxRs1tqXy2qccjYAa4ej3vfT0uIPFvlX6nYw9Mvgxijvww6OKZE0aK6kFHTXDxR0uVJiRhLw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/bn.js": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", @@ -36384,6 +36515,11 @@ "tslib": "^2.4.0" } }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" + }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -36568,6 +36704,30 @@ "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==", "dev": true }, + "big-json": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big-json/-/big-json-3.2.0.tgz", + "integrity": "sha512-2Etdurszm1CAFxqpH08lItXyf5CI1OBKRn7imCeI8Lh+a2UvdN2WpuSduxB/3ccao6v93SxiS5fIlE/v1QLoPg==", + "requires": { + "assert-plus": "^1.0.0", + "into-stream": "^5.1.0", + "json-stream-stringify": "^2.0.1", + "JSONStream": "^1.3.1", + "once": "^1.4.0", + "through2": "^3.0.1" + }, + "dependencies": { + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + } + } + }, "bignumber.js": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", @@ -39631,6 +39791,49 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -40919,6 +41122,15 @@ "side-channel": "^1.0.4" } }, + "into-stream": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz", + "integrity": "sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==", + "requires": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -42879,6 +43091,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "json-stream-stringify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-2.0.4.tgz", + "integrity": "sha512-gIPoa6K5w6j/RnQ3fOtmvICKNJGViI83A7dnTIL+0QJ/1GKuNvCPFvbFWxt0agruF4iGgDFJvge4Gua4ZoiggQ==" + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -42937,6 +43154,15 @@ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==" }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, "jsonstream-next": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/jsonstream-next/-/jsonstream-next-3.0.0.tgz", @@ -45040,6 +45266,11 @@ "p-defer": "^3.0.0" } }, + "p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==" + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", diff --git a/package.json b/package.json index c3a5bbab4..a31ce529b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orion", - "version": "3.3.0", + "version": "3.4.0", "engines": { "node": ">=16" }, @@ -65,6 +65,7 @@ "ajv": "^6.11.0", "async-lock": "^1.3.1", "axios": "^1.2.1", + "big-json": "^3.2.0", "cookie-parser": "^1.4.6", "csv-stringify": "^6.3.0", "dayjs": "^1.11.7", @@ -101,6 +102,7 @@ "@subsquid/substrate-typegen": "^2.1.0", "@subsquid/typeorm-codegen": "^0.3.1", "@types/async-lock": "^1.1.3", + "@types/big-json": "^3.2.4", "@types/chai": "^4.3.5", "@types/cookie-parser": "^1.4.3", "@types/express-rate-limit": "^6.0.0", diff --git a/schema/NFTs.graphql b/schema/NFTs.graphql index 113e8c3a2..3d398b041 100644 --- a/schema/NFTs.graphql +++ b/schema/NFTs.graphql @@ -30,7 +30,7 @@ type TransactionalStatusAuction { } "Represents NFT details" -type OwnedNft @entity { +type OwnedNft @entity @schema(name: "admin") { "Timestamp of the block the NFT was created at" createdAt: DateTime! @index @@ -87,7 +87,7 @@ type AuctionTypeOpen @variant { } "Represents NFT auction" -type Auction @entity { +type Auction @entity @schema(name: "admin") { "Unique identifier" id: ID! @@ -137,7 +137,7 @@ type AuctionWhitelistedMember @entity @index(fields: ["auction", "member"], uniq } "Represents bid in NFT auction" -type Bid @entity { +type Bid @entity @schema(name: "admin") { "Unique identifier" id: ID! diff --git a/schema/auth.graphql b/schema/auth.graphql index 3b48c4035..3f6e47667 100644 --- a/schema/auth.graphql +++ b/schema/auth.graphql @@ -13,7 +13,7 @@ enum OperatorPermission { RESTORE_CONTENT } -type User @entity { +type User @entity @schema(name: "admin") { "Unique identifier (32-byte string, securely random)" id: ID! @@ -67,7 +67,7 @@ type SessionEncryptionArtifacts @entity { cipherKey: String! } -type Session @entity { +type Session @entity @schema(name: "admin") { "Unique identifier (32-byte string, securely random)" id: ID! @@ -100,7 +100,7 @@ type Session @entity { } "A Gateway Account" -type Account @entity { +type Account @entity @schema(name: "admin") { "Unique identifier (can be sequential)" id: ID! @@ -187,7 +187,7 @@ enum TokenType { EMAIL_CONFIRMATION } -type Token @entity { +type Token @entity @schema(name: "admin") { "The token itself (32-byte string, securely random)" id: ID! diff --git a/schema/channels.graphql b/schema/channels.graphql index 2fd4a206c..10d6e92a0 100644 --- a/schema/channels.graphql +++ b/schema/channels.graphql @@ -1,4 +1,4 @@ -type Channel @entity { +type Channel @entity @schema(name: "admin") { "Runtime entity identifier (EntityId)" id: ID! @@ -86,14 +86,17 @@ type YppSuspended { suspension: ChannelSuspension! } -type BannedMember @entity @index(fields: ["member", "channel"], unique: true) { +type BannedMember + @entity + @schema(name: "admin") + @index(fields: ["member", "channel"], unique: true) { "{memberId}-{channelId}" id: ID! member: Membership! channel: Channel! } -type ChannelVerification @entity { +type ChannelVerification @entity @schema(name: "admin") { "unique Id" id: ID! @@ -104,7 +107,7 @@ type ChannelVerification @entity { timestamp: DateTime! } -type ChannelSuspension @entity { +type ChannelSuspension @entity @schema(name: "admin") { "unique Id" id: ID! diff --git a/schema/events.graphql b/schema/events.graphql index 9a5a23deb..7d32c5492 100644 --- a/schema/events.graphql +++ b/schema/events.graphql @@ -1,4 +1,4 @@ -type Event @entity { +type Event @entity @schema(name: "admin") { "{blockNumber}-{indexInBlock}" id: ID! @@ -18,7 +18,7 @@ type Event @entity { data: EventData! } -type NftHistoryEntry @entity { +type NftHistoryEntry @entity @schema(name: "admin") { "Autoincremented" id: ID! @@ -29,7 +29,7 @@ type NftHistoryEntry @entity { event: Event! } -type NftActivity @entity { +type NftActivity @entity @schema(name: "admin") { "Autoincremented" id: ID! diff --git a/schema/hidden.graphql b/schema/hidden.graphql index 97cb6527e..b6624a1fb 100644 --- a/schema/hidden.graphql +++ b/schema/hidden.graphql @@ -1,4 +1,4 @@ -type VideoViewEvent @entity { +type VideoViewEvent @entity @schema(name: "admin") { "Unique identifier of the video view event" id: ID! @@ -12,7 +12,7 @@ type VideoViewEvent @entity { timestamp: DateTime! } -type Report @entity { +type Report @entity @schema(name: "admin") { "Unique identifier of the report" id: ID! @@ -32,7 +32,7 @@ type Report @entity { rationale: String! } -type NftFeaturingRequest @entity { +type NftFeaturingRequest @entity @schema(name: "admin") { "Unique identifier of the request" id: ID! @@ -49,7 +49,7 @@ type NftFeaturingRequest @entity { rationale: String! } -type ChannelFollow @entity { +type ChannelFollow @entity @schema(name: "admin") { "Unique identifier of the follow" id: ID! @@ -63,7 +63,7 @@ type ChannelFollow @entity { timestamp: DateTime! } -type GatewayConfig @entity { +type GatewayConfig @entity @schema(name: "admin") { "Unique name of the configuration variable" id: ID! @@ -74,7 +74,7 @@ type GatewayConfig @entity { updatedAt: DateTime! } -type Exclusion @entity { +type Exclusion @entity @schema(name: "admin") { "Unique identifier of the exclusion" id: ID! diff --git a/schema/notifications.graphql b/schema/notifications.graphql index 536d43280..2989c2b11 100644 --- a/schema/notifications.graphql +++ b/schema/notifications.graphql @@ -1,4 +1,4 @@ -type NotificationEmailDelivery @entity { +type NotificationEmailDelivery @entity @schema(name: "admin") { "UUID" id: ID! @@ -12,7 +12,7 @@ type NotificationEmailDelivery @entity { discard: Boolean! } -type EmailDeliveryAttempt @entity { +type EmailDeliveryAttempt @entity @schema(name: "admin") { "UUID" id: ID! diff --git a/schema/storage.graphql b/schema/storage.graphql index 5b09bbbc7..3ff2914cf 100644 --- a/schema/storage.graphql +++ b/schema/storage.graphql @@ -208,7 +208,7 @@ union DataObjectType = | DataObjectTypeVideoSubtitle | DataObjectTypeChannelPayoutsPayload -type StorageDataObject @entity { +type StorageDataObject @entity @schema(name: "admin") { "Data object runtime id" id: ID! diff --git a/schema/videoComments.graphql b/schema/videoComments.graphql index 3b937a061..b92a69c31 100644 --- a/schema/videoComments.graphql +++ b/schema/videoComments.graphql @@ -1,4 +1,4 @@ -type CommentReaction @entity { +type CommentReaction @entity @schema(name: "admin") { "{memberId}-{commentId}-{reactionId}" id: ID! @@ -31,7 +31,7 @@ type CommentReactionsCountByReactionId { count: Int! } -type Comment @entity { +type Comment @entity @schema(name: "admin") { "METAPROTOCOL-{network}-{blockNumber}-{indexInBlock}" id: ID! diff --git a/schema/videos.graphql b/schema/videos.graphql index 409ff4225..ea35ec80c 100644 --- a/schema/videos.graphql +++ b/schema/videos.graphql @@ -1,4 +1,4 @@ -type VideoCategory @entity { +type VideoCategory @entity @schema(name: "admin") { "Runtime identifier" id: ID! @@ -21,7 +21,7 @@ type VideoCategory @entity { createdInBlock: Int! } -type Video @entity { +type Video @entity @schema(name: "admin") { "Runtime identifier" id: ID! @@ -128,7 +128,10 @@ type Video @entity { videoRelevance: Float! @index } -type VideoFeaturedInCategory @entity @index(fields: ["category", "video"], unique: true) { +type VideoFeaturedInCategory + @entity + @schema(name: "admin") + @index(fields: ["category", "video"], unique: true) { "{categoryId-videoId}" id: ID! @@ -142,7 +145,7 @@ type VideoFeaturedInCategory @entity @index(fields: ["category", "video"], uniqu videoCutUrl: String } -type VideoHero @entity { +type VideoHero @entity @schema(name: "admin") { "Unique ID" id: ID! @@ -162,7 +165,7 @@ type VideoHero @entity { activatedAt: DateTime } -type VideoMediaMetadata @entity { +type VideoMediaMetadata @entity @schema(name: "admin") { "Unique identifier" id: ID! @@ -183,7 +186,7 @@ type VideoMediaMetadata @entity { createdInBlock: Int! } -type VideoMediaEncoding @entity { +type VideoMediaEncoding @entity @schema(name: "admin") { "Encoding of the video media object" codecName: String @@ -194,7 +197,7 @@ type VideoMediaEncoding @entity { mimeMediaType: String } -type License @entity { +type License @entity @schema(name: "admin") { "Unique identifier" id: ID! @@ -208,7 +211,7 @@ type License @entity { customText: String } -type VideoSubtitle @entity { +type VideoSubtitle @entity @schema(name: "admin") { "{type}-{language}" id: ID! @@ -243,7 +246,7 @@ enum VideoReactionOptions { UNLIKE } -type VideoReaction @entity { +type VideoReaction @entity @schema(name: "admin") { "{memberId}-{videoId}" id: ID! diff --git a/src/processor.ts b/src/processor.ts index bcfe60ab8..41bd51086 100644 --- a/src/processor.ts +++ b/src/processor.ts @@ -5,92 +5,92 @@ import { SubstrateBlock, } from '@subsquid/substrate-processor' import { Store, TypeormDatabase } from '@subsquid/typeorm-store' +import { EntityManager } from 'typeorm' import { Logger } from './logger' import { - processStorageBucketCreatedEvent, - processStorageBucketInvitationAcceptedEvent, - processStorageBucketsUpdatedForBagEvent, - processStorageOperatorMetadataSetEvent, - processStorageBucketVoucherLimitsSetEvent, - processPendingDataObjectsAcceptedEvent, - processStorageBucketInvitationCancelledEvent, - processStorageBucketOperatorInvitedEvent, - processStorageBucketOperatorRemovedEvent, - processStorageBucketStatusUpdatedEvent, - processStorageBucketDeletedEvent, - processVoucherChangedEvent, - processDynamicBagCreatedEvent, - processDynamicBagDeletedEvent, - processDataObjectsUploadedEvent, - processDataObjectsUpdatedEvent, - processDataObjectsMovedEvent, - processDataObjectsDeletedEvent, - processDistributionBucketCreatedEvent, - processDistributionBucketStatusUpdatedEvent, - processDistributionBucketDeletedEvent, - processDistributionBucketsUpdatedForBagEvent, - processDistributionBucketModeUpdatedEvent, - processDistributionBucketOperatorInvitedEvent, - processDistributionBucketInvitationCancelledEvent, - processDistributionBucketInvitationAcceptedEvent, - processDistributionBucketMetadataSetEvent, - processDistributionBucketOperatorRemovedEvent, - processDistributionBucketFamilyCreatedEvent, - processDistributionBucketFamilyMetadataSetEvent, - processDistributionBucketFamilyDeletedEvent, -} from './mappings/storage' -import { + processChannelAgentRemarkedEvent, processChannelCreatedEvent, - processChannelUpdatedEvent, - processChannelDeletedEvent, processChannelDeletedByModeratorEvent, - processChannelVisibilitySetByModeratorEvent, + processChannelDeletedEvent, + processChannelFundsWithdrawnEvent, processChannelOwnerRemarkedEvent, - processChannelAgentRemarkedEvent, processChannelPayoutsUpdatedEvent, - processChannelRewardUpdatedEvent, - processChannelFundsWithdrawnEvent, processChannelRewardClaimedAndWithdrawnEvent, + processChannelRewardUpdatedEvent, + processChannelUpdatedEvent, + processChannelVisibilitySetByModeratorEvent, } from './mappings/content/channel' import { - processVideoCreatedEvent, - processVideoUpdatedEvent, - processVideoDeletedEvent, - processVideoDeletedByModeratorEvent, - processVideoVisibilitySetByModeratorEvent, -} from './mappings/content/video' -import { - processOpenAuctionStartedEvent, - processEnglishAuctionStartedEvent, - processNftIssuedEvent, - processAuctionBidMadeEvent, processAuctionBidCanceledEvent, + processAuctionBidMadeEvent, processAuctionCanceledEvent, - processEnglishAuctionSettledEvent, processBidMadeCompletingAuctionEvent, - processOpenAuctionBidAcceptedEvent, - processOfferStartedEvent, - processOfferAcceptedEvent, - processOfferCanceledEvent, - processNftSellOrderMadeEvent, - processNftBoughtEvent, processBuyNowCanceledEvent, processBuyNowPriceUpdatedEvent, + processEnglishAuctionSettledEvent, + processEnglishAuctionStartedEvent, + processNftBoughtEvent, + processNftIssuedEvent, + processNftSellOrderMadeEvent, processNftSlingedBackToTheOriginalArtistEvent, + processOfferAcceptedEvent, + processOfferCanceledEvent, + processOfferStartedEvent, + processOpenAuctionBidAcceptedEvent, + processOpenAuctionStartedEvent, } from './mappings/content/nft' +import { + processVideoCreatedEvent, + processVideoDeletedByModeratorEvent, + processVideoDeletedEvent, + processVideoUpdatedEvent, + processVideoVisibilitySetByModeratorEvent, +} from './mappings/content/video' import { processMemberAccountsUpdatedEvent, processMemberProfileUpdatedEvent, - processNewMember, processMemberRemarkedEvent, + processNewMember, } from './mappings/membership' +import { + processDataObjectsDeletedEvent, + processDataObjectsMovedEvent, + processDataObjectsUpdatedEvent, + processDataObjectsUploadedEvent, + processDistributionBucketCreatedEvent, + processDistributionBucketDeletedEvent, + processDistributionBucketFamilyCreatedEvent, + processDistributionBucketFamilyDeletedEvent, + processDistributionBucketFamilyMetadataSetEvent, + processDistributionBucketInvitationAcceptedEvent, + processDistributionBucketInvitationCancelledEvent, + processDistributionBucketMetadataSetEvent, + processDistributionBucketModeUpdatedEvent, + processDistributionBucketOperatorInvitedEvent, + processDistributionBucketOperatorRemovedEvent, + processDistributionBucketStatusUpdatedEvent, + processDistributionBucketsUpdatedForBagEvent, + processDynamicBagCreatedEvent, + processDynamicBagDeletedEvent, + processPendingDataObjectsAcceptedEvent, + processStorageBucketCreatedEvent, + processStorageBucketDeletedEvent, + processStorageBucketInvitationAcceptedEvent, + processStorageBucketInvitationCancelledEvent, + processStorageBucketOperatorInvitedEvent, + processStorageBucketOperatorRemovedEvent, + processStorageBucketStatusUpdatedEvent, + processStorageBucketVoucherLimitsSetEvent, + processStorageBucketsUpdatedForBagEvent, + processStorageOperatorMetadataSetEvent, + processVoucherChangedEvent, +} from './mappings/storage' +import { commentCountersManager, videoRelevanceManager } from './mappings/utils' import { Event } from './types/support' +import { EventHandler, EventInstance, EventNames, eventConstructors } from './utils/events' import { assertAssignable } from './utils/misc' -import { EntityManagerOverlay } from './utils/overlay' -import { EventNames, EventHandler, eventConstructors, EventInstance } from './utils/events' -import { commentCountersManager, videoRelevanceManager } from './mappings/utils' -import { EntityManager } from 'typeorm' import { OffchainState } from './utils/offchainState' +import { EntityManagerOverlay } from './utils/overlay' const defaultEventOptions = { data: { @@ -263,9 +263,6 @@ const eventHandlers: { [E in EventNames]: EventHandler } = { 'Members.MemberRemarked': processMemberRemarkedEvent, } -const offchainState = new OffchainState() -const exportBlockNumber = offchainState.getExportBlockNumber() - async function processEvent( ctx: Ctx, name: EventName, @@ -286,9 +283,17 @@ async function afterDbUpdate(em: EntityManager) { await commentCountersManager.updateParentRepliesCounters(em) } +const offchainState = new OffchainState() +let exportBlockNumber: number + processor.run(new TypeormDatabase({ isolationLevel: 'READ COMMITTED' }), async (ctx) => { Logger.set(ctx.log) + // Get the export block number from the offchain state + if (!exportBlockNumber) { + exportBlockNumber = await offchainState.getExportBlockNumber() + } + const overlay = await EntityManagerOverlay.create(ctx.store, afterDbUpdate) for (const block of ctx.blocks) { diff --git a/src/server-extension/resolvers/AdminResolver/index.ts b/src/server-extension/resolvers/AdminResolver/index.ts index 54a4a0d02..5a3b4991e 100644 --- a/src/server-extension/resolvers/AdminResolver/index.ts +++ b/src/server-extension/resolvers/AdminResolver/index.ts @@ -11,23 +11,27 @@ import { GraphQLResolveInfo } from 'graphql' import 'reflect-metadata' import { Args, Ctx, Info, Int, Mutation, Query, Resolver, UseMiddleware } from 'type-graphql' import { EntityManager, In, Not, UpdateResult } from 'typeorm' +import { parseVideoTitle } from '../../../mappings/content/utils' import { videoRelevanceManager } from '../../../mappings/utils' import { + Account, Channel, + ChannelRecipient, + NftFeaturedOnMarketPlace, OperatorPermission, + OwnedNft, User, Video, VideoCategory, - Account, - ChannelRecipient, - NftFeaturedOnMarketPlace, VideoFeaturedInCategory, VideoHero as VideoHeroEntity, } from '../../../model' import { ConfigVariable, config } from '../../../utils/config' +import { addNotification } from '../../../utils/notification' import { withHiddenEntities } from '../../../utils/sql' import { VideoHero } from '../baseTypes' import { OperatorOnly } from '../middleware' +import { model } from '../model' import { AppActionSignatureInput, AppRootDomain, @@ -66,10 +70,7 @@ import { VideoViewPerUserTimeLimit, VideoWeights, } from './types' -import { parseVideoTitle } from '../../../mappings/content/utils' -import { addNotification } from '../../../utils/notification' import { processCommentsCensorshipStatusUpdate } from './utils' -import { model } from '../model' @Resolver() export class AdminResolver { @@ -209,7 +210,7 @@ export class AdminResolver { async (transactionalEntityManager) => { return transactionalEntityManager .createQueryBuilder() - .update(Channel) + .update(Channel) .set({ channelWeight: weight }) .where('id = :id', { id: channelId }) .execute() @@ -364,14 +365,14 @@ export class AdminResolver { if (supportedCategoriesIds) { await em .createQueryBuilder() - .update(`admin.video_category`) - .set({ is_supported: false }) + .update(VideoCategory) + .set({ isSupported: false }) .execute() if (supportedCategoriesIds.length) { const result = await em .createQueryBuilder() - .update(`admin.video_category`) - .set({ is_supported: true }) + .update(VideoCategory) + .set({ isSupported: true }) .where({ id: In(supportedCategoriesIds) }) .execute() newNumberOfCategoriesSupported = result.affected || 0 @@ -483,23 +484,23 @@ export const setFeaturedNftsInner = async (em: EntityManager, featuredNftsIds: s await em .createQueryBuilder() - .update(`admin.owned_nft`) - .set({ is_featured: false }) - .where({ is_featured: true }) + .update(OwnedNft) + .set({ isFeatured: false }) + .where({ isFeatured: true }) .execute() if (featuredNftsIds.length) { const result = await em .createQueryBuilder() - .update(`admin.owned_nft`) - .set({ is_featured: true }) + .update(OwnedNft) + .set({ isFeatured: true }) .where({ id: In(featuredNftsIds) }) .execute() newNumberOfNftsFeatured = result.affected || 0 // fetch all featured nfts and deposit notification for their creators for (const featuredNftId of featuredNftsIds) { - const featuredNft = await em.getRepository('OwnedNft').findOne({ + const featuredNft = await em.getRepository(OwnedNft).findOne({ where: { id: featuredNftId }, relations: { video: { channel: true } }, }) diff --git a/src/utils/customMigrations/setOrionLanguage.ts b/src/utils/customMigrations/setOrionLanguage.ts new file mode 100644 index 000000000..7296ce8d2 --- /dev/null +++ b/src/utils/customMigrations/setOrionLanguage.ts @@ -0,0 +1,50 @@ +import { createLogger } from '@subsquid/logger' +import { IsNull } from 'typeorm' +import { Video } from '../../model' +import { globalEm } from '../globalEm' +import { predictLanguage } from '../language' + +const logger = createLogger('setOrionLanguage') + +async function setOrionLanguage() { + const em = await globalEm + + const batchSize = 10000 + let offset = 0 + let hasMore = true + + while (hasMore) { + const videos = await em.find(Video, { + where: { orionLanguage: IsNull() }, + order: { id: 'ASC' }, + take: batchSize, + skip: offset, + }) + + if (videos.length === 0) { + hasMore = false + } else { + const updates = videos.map((video) => { + const languageText = [video.title ?? '', video.description ?? ''].join(' ') + video.orionLanguage = predictLanguage(languageText) + return video + }) + + // Save all updates in a single transaction + await em.transaction(async (transactionalEntityManager) => { + await transactionalEntityManager.save(updates) + }) + + logger.info(`Updated ${updates.length} videos.`) + + offset += videos.length // Prepare the offset for the next batch + } + } +} + +setOrionLanguage() + .then(() => logger.info('Update process completed.')) + .catch(() => { + logger.error('process failed') + process.exit(1) + }) diff --git a/src/utils/offchainState.ts b/src/utils/offchainState.ts index 7f299a2b6..be15c8bbd 100644 --- a/src/utils/offchainState.ts +++ b/src/utils/offchainState.ts @@ -1,5 +1,6 @@ import { createLogger } from '@subsquid/logger' import assert from 'assert' +import { createParseStream, createStringifyStream } from 'big-json' import fs from 'fs' import path from 'path' import { EntityManager } from 'typeorm' @@ -172,7 +173,11 @@ export class OffchainState { }) this.logger.info(`Saving export data to ${exportFilePath}`) - fs.writeFileSync(exportFilePath, JSON.stringify(exportedState)) + await new Promise((resolve, reject) => { + const writeStream = fs.createWriteStream(exportFilePath) + const stringifyStream = createStringifyStream({ body: exportedState }) + stringifyStream.pipe(writeStream).on('error', reject).on('finish', resolve) + }) this.logger.info('Done') } @@ -200,7 +205,7 @@ export class OffchainState { `Cannot perform offchain data import! Export file ${exportFilePath} does not exist!` ) } - const exportFile = JSON.parse(fs.readFileSync(exportFilePath, 'utf-8')) + const exportFile = await this.readExportJsonFile(exportFilePath) const data = this.prepareExportData(exportFile, em) this.logger.info('Importing offchain state') for (const [entityName, { type, values }] of Object.entries(data)) { @@ -279,14 +284,31 @@ export class OffchainState { this.logger.info('Done') } - public getExportBlockNumber(exportFilePath = DEFAULT_EXPORT_PATH): number { + public async getExportBlockNumber(exportFilePath = DEFAULT_EXPORT_PATH): Promise { if (!fs.existsSync(exportFilePath)) { this.logger.warn(`Export file ${exportFilePath} does not exist`) this._isImported = true return -1 } - const { blockNumber }: ExportedState = JSON.parse(fs.readFileSync(exportFilePath, 'utf-8')) + const { blockNumber }: ExportedState = await this.readExportJsonFile() this.logger.info(`Last export block number established: ${blockNumber}`) return blockNumber } + + public async readExportJsonFile(filePath = DEFAULT_EXPORT_PATH): Promise { + return new Promise((resolve, reject) => { + const readStream = fs.createReadStream(filePath) + const parseStream = createParseStream() + + let exportedState: ExportedState + + parseStream.on('data', (data: ExportedState) => (exportedState = data)) + + parseStream.on('end', () => resolve(exportedState)) + + parseStream.on('error', (error: Error) => reject(error)) + + readStream.pipe(parseStream as any) + }) + } }