forked from DebaucheryLibrarian/traxxx
				
			Normalized database. Updated seed files. Simplified seed upsert.
This commit is contained in:
		
							parent
							
								
									9b17add4e2
								
							
						
					
					
						commit
						31aee71edb
					
				|  | @ -17,6 +17,184 @@ exports.up = knex => Promise.resolve() | |||
|         table.integer('priority', 2) | ||||
|             .defaultTo(0); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('media', (table) => { | ||||
|         table.increments('id', 16); | ||||
| 
 | ||||
|         table.string('path'); | ||||
|         table.string('thumbnail'); | ||||
|         table.integer('index'); | ||||
|         table.string('mime'); | ||||
| 
 | ||||
|         table.string('type'); | ||||
|         table.string('quality', 6); | ||||
| 
 | ||||
|         table.string('hash'); | ||||
|         table.text('comment'); | ||||
|         table.string('source', 1000); | ||||
| 
 | ||||
|         table.unique('hash'); | ||||
|         table.unique('source'); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('tags_groups', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|         table.string('name', 32); | ||||
|         table.text('description'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('tags', (table) => { | ||||
|         table.increments('id', 12); | ||||
|         table.string('name'); | ||||
| 
 | ||||
|         table.text('description'); | ||||
| 
 | ||||
|         table.integer('priority', 2) | ||||
|             .defaultTo(0); | ||||
| 
 | ||||
|         table.integer('group_id', 12) | ||||
|             .references('id') | ||||
|             .inTable('tags_groups'); | ||||
| 
 | ||||
|         table.integer('alias_for', 12) | ||||
|             .references('id') | ||||
|             .inTable('tags'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('tags_posters', (table) => { | ||||
|         table.integer('tag_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('tags'); | ||||
| 
 | ||||
|         table.integer('media_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('media'); | ||||
| 
 | ||||
|         table.unique('tag_id'); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('tags_photos', (table) => { | ||||
|         table.integer('tag_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('tags'); | ||||
| 
 | ||||
|         table.integer('media_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('media'); | ||||
| 
 | ||||
|         table.unique(['tag_id', 'media_id']); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('networks', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|         table.string('name'); | ||||
|         table.string('url'); | ||||
|         table.text('description'); | ||||
|         table.string('parameters'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('networks_social', (table) => { | ||||
|         table.increments('id', 16); | ||||
| 
 | ||||
|         table.string('url'); | ||||
|         table.string('platform'); | ||||
| 
 | ||||
|         table.integer('network_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('networks'); | ||||
| 
 | ||||
|         table.unique(['url', 'network_id']); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('sites', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|         table.integer('network_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('networks'); | ||||
| 
 | ||||
|         table.string('name'); | ||||
|         table.string('url'); | ||||
|         table.text('description'); | ||||
|         table.string('parameters'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('sites_tags', (table) => { | ||||
|         table.integer('tag_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('tags'); | ||||
| 
 | ||||
|         table.integer('site_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('sites'); | ||||
| 
 | ||||
|         table.unique(['tag_id', 'site_id']); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('sites_social', (table) => { | ||||
|         table.increments('id', 16); | ||||
| 
 | ||||
|         table.string('url'); | ||||
|         table.string('platform'); | ||||
| 
 | ||||
|         table.integer('site_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('sites'); | ||||
| 
 | ||||
|         table.unique(['url', 'site_id']); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('studios', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|         table.integer('network_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('networks'); | ||||
| 
 | ||||
|         table.string('name'); | ||||
|         table.string('url'); | ||||
|         table.text('description'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('actors', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|  | @ -70,6 +248,48 @@ exports.up = knex => Promise.resolve() | |||
|         table.datetime('scraped_at'); | ||||
|         table.boolean('scrape_success'); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('actors_avatars', (table) => { | ||||
|         table.integer('actor_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('actors'); | ||||
| 
 | ||||
|         table.integer('media_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('media'); | ||||
| 
 | ||||
|         table.unique('actor_id'); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('actors_photos', (table) => { | ||||
|         table.integer('actor_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('actors'); | ||||
| 
 | ||||
|         table.integer('media_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('media'); | ||||
| 
 | ||||
|         table.unique(['actor_id', 'media_id']); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('actors_social', (table) => { | ||||
|         table.increments('id', 16); | ||||
| 
 | ||||
|         table.string('url'); | ||||
|         table.string('platform'); | ||||
| 
 | ||||
|         table.integer('actor_id', 8) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('actors'); | ||||
| 
 | ||||
|         table.unique(['url', 'actor_id']); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('directors', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|  | @ -84,92 +304,6 @@ exports.up = knex => Promise.resolve() | |||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('tags_groups', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|         table.string('name', 32); | ||||
|         table.text('description'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('tags', (table) => { | ||||
|         table.increments('id', 12); | ||||
|         table.string('name'); | ||||
| 
 | ||||
|         table.text('description'); | ||||
| 
 | ||||
|         table.integer('priority', 2) | ||||
|             .defaultTo(0); | ||||
| 
 | ||||
|         table.integer('group_id', 12) | ||||
|             .references('id') | ||||
|             .inTable('tags_groups'); | ||||
| 
 | ||||
|         table.integer('alias_for', 12) | ||||
|             .references('id') | ||||
|             .inTable('tags'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('networks', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|         table.string('name'); | ||||
|         table.string('url'); | ||||
|         table.text('description'); | ||||
|         table.string('parameters'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('sites', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|         table.integer('network_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('networks'); | ||||
| 
 | ||||
|         table.string('name'); | ||||
|         table.string('url'); | ||||
|         table.text('description'); | ||||
|         table.string('parameters'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('studios', (table) => { | ||||
|         table.increments('id', 12); | ||||
| 
 | ||||
|         table.integer('network_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('networks'); | ||||
| 
 | ||||
|         table.string('name'); | ||||
|         table.string('url'); | ||||
|         table.text('description'); | ||||
| 
 | ||||
|         table.string('slug', 32) | ||||
|             .unique(); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('releases', (table) => { | ||||
|         table.increments('id', 16); | ||||
| 
 | ||||
|  | @ -193,10 +327,6 @@ exports.up = knex => Promise.resolve() | |||
|         table.date('date'); | ||||
|         table.text('description'); | ||||
| 
 | ||||
|         table.integer('director', 12) | ||||
|             .references('id') | ||||
|             .inTable('directors'); | ||||
| 
 | ||||
|         table.integer('duration') | ||||
|             .unsigned(); | ||||
| 
 | ||||
|  | @ -209,48 +339,7 @@ exports.up = knex => Promise.resolve() | |||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('media', (table) => { | ||||
|         table.increments('id', 16); | ||||
| 
 | ||||
|         table.string('path'); | ||||
|         table.string('thumbnail'); | ||||
|         table.integer('index'); | ||||
|         table.string('mime'); | ||||
| 
 | ||||
|         table.string('domain'); | ||||
|         table.integer('target_id', 16); | ||||
| 
 | ||||
|         table.json('target'); | ||||
| 
 | ||||
|         table.string('role'); | ||||
|         table.string('quality', 6); | ||||
| 
 | ||||
|         table.string('hash'); | ||||
|         table.text('comment'); | ||||
|         table.string('source', 1000); | ||||
| 
 | ||||
|         table.unique(['domain', 'target_id', 'role', 'hash']); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('social', (table) => { | ||||
|         table.increments('id', 16); | ||||
| 
 | ||||
|         table.string('url'); | ||||
|         table.string('platform'); | ||||
| 
 | ||||
|         table.string('domain'); | ||||
|         table.integer('target_id', 16); | ||||
| 
 | ||||
|         table.unique(['url', 'domain', 'target_id']); | ||||
| 
 | ||||
|         table.datetime('created_at') | ||||
|             .defaultTo(knex.fn.now()); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('actors_associated', (table) => { | ||||
|         // table.increments('id', 16);
 | ||||
| 
 | ||||
|     .then(() => knex.schema.createTable('releases_actors', (table) => { | ||||
|         table.integer('release_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|  | @ -263,9 +352,7 @@ exports.up = knex => Promise.resolve() | |||
| 
 | ||||
|         table.unique(['release_id', 'actor_id']); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('directors_associated', (table) => { | ||||
|         table.increments('id', 16); | ||||
| 
 | ||||
|     .then(() => knex.schema.createTable('releases_directors', (table) => { | ||||
|         table.integer('release_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|  | @ -278,65 +365,85 @@ exports.up = knex => Promise.resolve() | |||
| 
 | ||||
|         table.unique(['release_id', 'director_id']); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('tags_associated', (table) => { | ||||
|     .then(() => knex.schema.createTable('releases_posters', (table) => { | ||||
|         table.integer('release_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('releases'); | ||||
| 
 | ||||
|         table.integer('media_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('media'); | ||||
| 
 | ||||
|         table.unique('release_id'); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('releases_photos', (table) => { | ||||
|         table.integer('release_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('releases'); | ||||
| 
 | ||||
|         table.integer('media_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('media'); | ||||
| 
 | ||||
|         table.unique(['release_id', 'media_id']); | ||||
|     })) | ||||
|     .then(() => knex.schema.createTable('releases_tags', (table) => { | ||||
|         table.integer('tag_id', 12) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('tags'); | ||||
| 
 | ||||
|         table.string('domain'); | ||||
|         table.integer('target_id', 16); | ||||
|         table.integer('release_id', 16) | ||||
|             .notNullable() | ||||
|             .references('id') | ||||
|             .inTable('releases'); | ||||
| 
 | ||||
|         table.unique(['domain', 'tag_id', 'target_id']); | ||||
|         table.unique(['tag_id', 'release_id']); | ||||
|     })) | ||||
|     .then(() => knex.raw(` | ||||
|         CREATE VIEW releases_media AS SELECT * FROM media WHERE domain = 'releases'; | ||||
|         CREATE VIEW actors_media AS SELECT * FROM media WHERE domain = 'actors'; | ||||
|         CREATE VIEW tags_media AS SELECT * FROM media WHERE domain = 'tags'; | ||||
| 
 | ||||
|         CREATE VIEW releases_tags AS SELECT tags_associated.*,tags.slug FROM tags_associated LEFT JOIN tags ON tags_associated.tag_id = tags.id WHERE domain = 'releases'; | ||||
|         /* used for sorting release actors and tags */ | ||||
|         CREATE VIEW releases_actors AS SELECT actors_associated.*,actors.gender,actors.birthdate FROM actors_associated LEFT JOIN actors ON actors_associated.actor_id = actors.id; | ||||
| 
 | ||||
|         CREATE VIEW actors_social AS SELECT * FROM social WHERE domain = 'actors'; | ||||
| 
 | ||||
|         COMMENT ON VIEW releases_media IS E'@foreignKey (target_id) references releases (id)|@fieldName releaseMedia'; | ||||
|         COMMENT ON VIEW actors_media IS E'@foreignKey (target_id) references actors (id)|@fieldName actorMedia'; | ||||
|         COMMENT ON VIEW tags_media IS E'@foreignKey (target_id) references tags (id)|@fieldName tagMedia'; | ||||
| 
 | ||||
|         COMMENT ON VIEW actors_social IS E'@foreignKey (target_id) references actors (id)|@fieldName actorSocial'; | ||||
| 
 | ||||
|         COMMENT ON VIEW releases_tags IS E'@foreignKey (target_id) references releases (id)|@fieldName tagRelease\n@foreignKey (tag_id) references tags (id)|@fieldName releaseTag'; | ||||
| 
 | ||||
|         /* restore foreign keys in view, used for sorting release actors */ | ||||
|         COMMENT ON VIEW releases_actors IS E'@foreignKey (release_id) references releases (id)|@fieldName actorRelease\n@foreignKey (actor_id) references actors (id)|@fieldName releaseActor'; | ||||
| 
 | ||||
|         /* allow conversion resolver to be added for height and weight */ | ||||
|         COMMENT ON COLUMN actors.height IS E'@omit read,update,create,delete,all,many'; | ||||
|         COMMENT ON COLUMN actors.weight IS E'@omit read,update,create,delete,all,many'; | ||||
| 
 | ||||
|         /* | ||||
|         create function releases_by_tag_slugs(slugs text[]) returns setof releases as $$ | ||||
|             select distinct on (releases.id) releases.* from releases | ||||
|             join releases_tags on (releases_tags.release_id = releases.id) | ||||
|             join tags on (releases_tags.tag_id = tags.id) | ||||
|             where tags.slug = ANY($1); | ||||
|         $$ language sql stable | ||||
|         */ | ||||
|     `));
 | ||||
| 
 | ||||
| exports.down = knex => Promise.resolve() | ||||
|     .then(() => knex.raw(` | ||||
|         DROP VIEW releases_media; | ||||
|         DROP VIEW actors_media; | ||||
|         DROP VIEW tags_media; | ||||
| exports.down = knex => knex.raw(` | ||||
|     DROP FUNCTION IF EXISTS releases_by_tag_slugs; | ||||
| 
 | ||||
|         DROP VIEW releases_tags; | ||||
|         DROP VIEW releases_actors; | ||||
| 
 | ||||
|         DROP VIEW actors_social; | ||||
|     `))
 | ||||
|     .then(() => knex.schema.dropTable('tags_associated')) | ||||
|     .then(() => knex.schema.dropTable('directors_associated')) | ||||
|     .then(() => knex.schema.dropTable('actors_associated')) | ||||
|     .then(() => knex.schema.dropTable('tags')) | ||||
|     .then(() => knex.schema.dropTable('tags_groups')) | ||||
|     .then(() => knex.schema.dropTable('media')) | ||||
|     .then(() => knex.schema.dropTable('social')) | ||||
|     .then(() => knex.schema.dropTable('actors')) | ||||
|     .then(() => knex.schema.dropTable('releases')) | ||||
|     .then(() => knex.schema.dropTable('sites')) | ||||
|     .then(() => knex.schema.dropTable('studios')) | ||||
|     .then(() => knex.schema.dropTable('directors')) | ||||
|     .then(() => knex.schema.dropTable('networks')) | ||||
|     .then(() => knex.schema.dropTable('countries')); | ||||
|     DROP TABLE IF EXISTS releases_actors CASCADE; | ||||
|     DROP TABLE IF EXISTS releases_directors CASCADE; | ||||
|     DROP TABLE IF EXISTS releases_posters CASCADE; | ||||
|     DROP TABLE IF EXISTS releases_photos CASCADE; | ||||
|     DROP TABLE IF EXISTS releases_tags CASCADE; | ||||
|     DROP TABLE IF EXISTS actors_avatars CASCADE; | ||||
|     DROP TABLE IF EXISTS actors_photos CASCADE; | ||||
|     DROP TABLE IF EXISTS actors_social CASCADE; | ||||
|     DROP TABLE IF EXISTS sites_tags CASCADE; | ||||
|     DROP TABLE IF EXISTS sites_social CASCADE; | ||||
|     DROP TABLE IF EXISTS networks_social CASCADE; | ||||
|     DROP TABLE IF EXISTS tags_posters CASCADE; | ||||
|     DROP TABLE IF EXISTS tags_photos CASCADE; | ||||
|     DROP TABLE IF EXISTS releases CASCADE; | ||||
|     DROP TABLE IF EXISTS actors CASCADE; | ||||
|     DROP TABLE IF EXISTS directors CASCADE; | ||||
|     DROP TABLE IF EXISTS tags CASCADE; | ||||
|     DROP TABLE IF EXISTS tags_groups CASCADE; | ||||
|     DROP TABLE IF EXISTS social CASCADE; | ||||
|     DROP TABLE IF EXISTS sites CASCADE; | ||||
|     DROP TABLE IF EXISTS studios CASCADE; | ||||
|     DROP TABLE IF EXISTS media CASCADE; | ||||
|     DROP TABLE IF EXISTS countries CASCADE; | ||||
|     DROP TABLE IF EXISTS networks CASCADE; | ||||
| `);
 | ||||
|  |  | |||
|  | @ -125,10 +125,4 @@ const networks = [ | |||
| ]; | ||||
| 
 | ||||
| exports.seed = knex => Promise.resolve() | ||||
|     .then(async () => { | ||||
|         // find network IDs
 | ||||
|         const duplicates = await knex('networks').select('*'); | ||||
|         const duplicatesBySlug = duplicates.reduce((acc, network) => ({ ...acc, [network.slug]: network }), {}); | ||||
| 
 | ||||
|         return upsert('networks', networks, duplicatesBySlug, 'slug', knex); | ||||
|     }); | ||||
|     .then(async () => upsert('networks', networks, 'slug', knex)); | ||||
|  |  | |||
|  | @ -2428,15 +2428,10 @@ function getSites(networksMap) { | |||
| /* eslint-disable max-len */ | ||||
| exports.seed = knex => Promise.resolve() | ||||
|     .then(async () => { | ||||
|         const [duplicates, networks] = await Promise.all([ | ||||
|             knex('sites').select('*'), | ||||
|             knex('networks').select('*'), | ||||
|         ]); | ||||
| 
 | ||||
|         const duplicatesBySlug = duplicates.reduce((acc, site) => ({ ...acc, [site.slug]: site }), {}); | ||||
|         const networks = await knex('networks').select('*'); | ||||
|         const networksMap = networks.reduce((acc, { id, slug }) => ({ ...acc, [slug]: id }), {}); | ||||
| 
 | ||||
|         const sites = getSites(networksMap); | ||||
| 
 | ||||
|         return upsert('sites', sites, duplicatesBySlug, 'slug', knex); | ||||
|         return upsert('sites', sites, 'slug', knex); | ||||
|     }); | ||||
|  |  | |||
|  | @ -1,5 +1,3 @@ | |||
| 'use strict'; | ||||
| 
 | ||||
| const upsert = require('../src/utils/upsert'); | ||||
| 
 | ||||
| function getStudios(networksMap) { | ||||
|  | @ -9,133 +7,133 @@ function getStudios(networksMap) { | |||
|             slug: 'gonzocom', | ||||
|             name: 'Gonzo.com', | ||||
|             url: 'https://www.legalporno.com/studios/gonzo_com', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'giorgiograndi', | ||||
|             name: 'Giorgio Grandi', | ||||
|             url: 'https://www.legalporno.com/studios/giorgio-grandi', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'hardpornworld', | ||||
|             name: 'Hard Porn World', | ||||
|             url: 'https://www.legalporno.com/studios/hard-porn-world', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'interracialvision', | ||||
|             name: 'Interracial Vision', | ||||
|             url: 'https://www.legalporno.com/studios/interracial-vision', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'giorgioslab', | ||||
|             name: 'Giorgio\'s Lab', | ||||
|             url: 'https://www.legalporno.com/studios/giorgio--s-lab', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'americananal', | ||||
|             name: 'American Anal', | ||||
|             url: 'https://www.legalporno.com/studios/american-anal', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'assablanca', | ||||
|             name: 'Assablanca', | ||||
|             url: 'https://www.legalporno.com/studios/assablanca', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'focus', | ||||
|             name: 'Focus', | ||||
|             url: 'https://www.legalporno.com/studios/focus', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'analforever', | ||||
|             name: 'Anal Forever', | ||||
|             url: 'https://www.legalporno.com/studios/anal-forever', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'gonzoinbrazil', | ||||
|             name: 'Gonzo in Brazil', | ||||
|             url: 'https://www.legalporno.com/studios/gonzo-in-brazil', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'mranal', | ||||
|             name: 'Mr Anal', | ||||
|             url: 'https://www.legalporno.com/studios/mr-anal', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'tarrawhite', | ||||
|             name: 'Tarra White', | ||||
|             url: 'https://www.legalporno.com/studios/tarra-white', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'sineplexsos', | ||||
|             name: 'Sineplex SOS', | ||||
|             url: 'https://www.legalporno.com/studios/sineplex-sos', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'fmodels', | ||||
|             name: 'F Models', | ||||
|             url: 'https://www.legalporno.com/studios/f-models', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'sineplexcz', | ||||
|             name: 'Sineplex CZ', | ||||
|             url: 'https://www.legalporno.com/studios/sineplex-cz', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'gg', | ||||
|             name: 'GG', | ||||
|             url: 'https://www.legalporno.com/studios/gg', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'firstgape', | ||||
|             name: 'First Gape', | ||||
|             url: 'https://www.legalporno.com/studios/first-gape', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'omargalantiproductions', | ||||
|             name: 'Omar Galanti Productions', | ||||
|             url: 'https://www.legalporno.com/studios/omar-galanti-productions', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'norestfortheass', | ||||
|             name: 'No Rest For The Ass', | ||||
|             url: 'https://www.legalporno.com/studios/no-rest-for-the-ass', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'hairygonzo', | ||||
|             name: 'Hairy Gonzo', | ||||
|             url: 'https://www.legalporno.com/studios/hairy-gonzo', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'sineplexclassic', | ||||
|             name: 'Sineplex Classic', | ||||
|             url: 'https://www.legalporno.com/studios/sineplex-classic', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|         { | ||||
|             slug: 'sinemale', | ||||
|             name: 'Sinemale', | ||||
|             url: 'https://www.legalporno.com/studios/sinemale', | ||||
|             network_id: networksMap['legalporno'], | ||||
|             network_id: networksMap.legalporno, | ||||
|         }, | ||||
|     ]; | ||||
| } | ||||
|  | @ -143,15 +141,10 @@ function getStudios(networksMap) { | |||
| /* eslint-disable max-len */ | ||||
| exports.seed = knex => Promise.resolve() | ||||
|     .then(async () => { | ||||
|         const [duplicates, networks] = await Promise.all([ | ||||
|             knex('studios').select('*'), | ||||
|             knex('networks').select('*'), | ||||
|         ]); | ||||
| 
 | ||||
|         const duplicatesBySlug = duplicates.reduce((acc, studio) => ({ ...acc, [studio.slug]: studio }), {}); | ||||
|         const networks = await knex('networks').select('*'); | ||||
|         const networksMap = networks.reduce((acc, { id, slug }) => ({ ...acc, [slug]: id }), {}); | ||||
| 
 | ||||
|         const studios = getStudios(networksMap); | ||||
| 
 | ||||
|         return upsert('studios', studios, duplicatesBySlug, 'slug', knex); | ||||
|         return upsert('studios', studios, 'slug', knex); | ||||
|     }); | ||||
|  |  | |||
|  | @ -69,7 +69,7 @@ function getTags(groupsMap) { | |||
|             name: 'airtight', | ||||
|             slug: 'airtight', | ||||
|             alias_for: null, | ||||
|             description: 'Stuffing one cock in her ass, one in her pussy, and one in her mouth, filling all of her penetrable holes and sealing her airtight like a figurative balloon. In other words, simultaneously getting [double penetrated](/tag/double-penetration), and giving a [blowjob](/tag/blowjob) or getting [facefucked](/tag/facefuck). Being airtight implies being [gangbanged](/tag/gangbang).', | ||||
|             description: 'Stuffing one cock in her ass, one in her pussy, and one in her mouth, filling all of her penetrable holes and sealing her airtight like a figurative balloon. In other words, simultaneously getting [double penetrated](/tag/double-penetration), and giving a [blowjob](/tag/blowjob) or getting [facefucked](/tag/facefuck). Being airtight implies being [gangbanged](/tag/gangbang).', /* eslint-disable-line max-len */ | ||||
|             priority: 9, | ||||
|             group_id: groupsMap.penetration, | ||||
|         }, | ||||
|  | @ -429,7 +429,7 @@ function getTags(groupsMap) { | |||
|         { | ||||
|             name: 'gangbang', | ||||
|             slug: 'gangbang', | ||||
|             description: 'A group of three or more guys fucking a woman, at least two at the same time, often but not necessarily involving a [blowbang](/tag/blowbang), [double penetration](/tag/airtight) and [airtight](/tag/airtight). If she only gets fucked by one guy at a time, it might be considered a [trainbang](/tag/trainbang) instead. In a reverse gangbang, multiple women fuck one man.', | ||||
|             description: 'A group of three or more guys fucking a woman, at least two at the same time, often but not necessarily involving a [blowbang](/tag/blowbang), [double penetration](/tag/airtight) and [airtight](/tag/airtight). If she only gets fucked by one guy at a time, it might be considered a [trainbang](/tag/trainbang) instead. In a reverse gangbang, multiple women fuck one man.', /* eslint-disable-line max-len */ | ||||
|             alias_for: null, | ||||
|             priority: 9, | ||||
|             group_id: groupsMap.group, | ||||
|  | @ -1542,35 +1542,20 @@ function getTagAliases(tagsMap) { | |||
| } | ||||
| 
 | ||||
| exports.seed = knex => Promise.resolve() | ||||
|     .then(async () => upsert('tags_groups', groups, 'slug', knex)) | ||||
|     .then(async () => { | ||||
|         const duplicates = await knex('tags_groups').select('*'); | ||||
|         const duplicatesBySlug = duplicates.reduce((acc, group) => ({ ...acc, [group.slug]: group }), {}); | ||||
| 
 | ||||
|         return upsert('tags_groups', groups, duplicatesBySlug, 'slug', knex); | ||||
|     }) | ||||
|     .then(async () => { | ||||
|         const [duplicates, groupEntries] = await Promise.all([ | ||||
|             knex('tags').select('*'), | ||||
|             knex('tags_groups').select('*'), | ||||
|         ]); | ||||
| 
 | ||||
|         const duplicatesBySlug = duplicates.reduce((acc, tag) => ({ ...acc, [tag.slug]: tag }), {}); | ||||
|         const groupEntries = knex('tags').select('*'); | ||||
|         const groupsMap = groupEntries.reduce((acc, { id, slug }) => ({ ...acc, [slug]: id }), {}); | ||||
| 
 | ||||
|         const tags = getTags(groupsMap); | ||||
| 
 | ||||
|         return upsert('tags', tags, duplicatesBySlug, 'slug', knex); | ||||
|         return upsert('tags', tags, 'slug', knex); | ||||
|     }) | ||||
|     .then(async () => { | ||||
|         const [duplicates, tags] = await Promise.all([ | ||||
|             knex('tags').select('*').whereNotNull('alias_for'), | ||||
|             knex('tags').select('*').where({ alias_for: null }), | ||||
|         ]); | ||||
| 
 | ||||
|         const duplicatesByName = duplicates.reduce((acc, tag) => ({ ...acc, [tag.name]: tag }), {}); | ||||
|         const tags = await knex('tags').select('*').where({ alias_for: null }); | ||||
|         const tagsMap = tags.reduce((acc, { id, slug }) => ({ ...acc, [slug]: id }), {}); | ||||
| 
 | ||||
|         const tagAliases = getTagAliases(tagsMap); | ||||
| 
 | ||||
|         return upsert('tags', tagAliases, duplicatesByName, 'name', knex); | ||||
|         return upsert('tags', tagAliases, 'name', knex); | ||||
|     }); | ||||
|  |  | |||
|  | @ -1,257 +1,241 @@ | |||
| const upsert = require('../src/utils/upsert'); | ||||
| 
 | ||||
| function getMedia(tagsMap) { | ||||
|     return [ | ||||
|         { | ||||
|             path: 'tags/airtight/poster.jpeg', | ||||
|             target_id: tagsMap.airtight, | ||||
|             role: 'poster', | ||||
|             comment: 'Jynx Maze in "Pump My Ass Full of Cum 3" for Jules Jordan', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/airtight/2.jpeg', | ||||
|             target_id: tagsMap.airtight, | ||||
|             comment: 'Dakota Skye in "Dakota Goes Nuts" for ArchAngel', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/airtight/1.jpeg', | ||||
|             target_id: tagsMap.airtight, | ||||
|             comment: 'Chloe Amour in "DP Masters 4" for Jules Jordan', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/airtight/0.jpeg', | ||||
|             domain: 'tags', | ||||
|             target_id: tagsMap.airtight, | ||||
|             comment: 'Sheena Shaw in "Ass Worship 14" for Jules Jordan', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/anal/poster.jpeg', | ||||
|             target_id: tagsMap.anal, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/double-penetration/poster.jpeg', | ||||
|             target_id: tagsMap['double-penetration'], | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/double-anal/poster.jpeg', | ||||
|             target_id: tagsMap['double-anal'], | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/double-vaginal/poster.jpeg', | ||||
|             target_id: tagsMap['double-vaginal'], | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/da-tp/0.jpeg', | ||||
|             target_id: tagsMap['da-tp'], | ||||
|             role: 'poster', | ||||
|             comment: 'Natasha Teen in LegalPorno SZ2164', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/da-tp/3.jpeg', | ||||
|             target_id: tagsMap['da-tp'], | ||||
|             role: 'photo', | ||||
|             comment: 'Evelina Darling in GIO294', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/da-tp/1.jpeg', | ||||
|             target_id: tagsMap['da-tp'], | ||||
|             role: 'photo', | ||||
|             comment: 'Francys Belle in SZ1702 for LegalPorno', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/da-tp/2.jpeg', | ||||
|             target_id: tagsMap['da-tp'], | ||||
|             role: 'photo', | ||||
|             comment: 'Angel Smalls in GIO408 for LegalPorno', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/da-tp/4.jpeg', | ||||
|             target_id: tagsMap['da-tp'], | ||||
|             role: 'photo', | ||||
|             comment: 'Ninel Mojado aka Mira Cuckold in GIO063 for LegalPorno', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/dv-tp/poster.jpeg', | ||||
|             target_id: tagsMap['dv-tp'], | ||||
|             role: 'poster', | ||||
|             comment: 'Juelz Ventura in "Gangbanged 5" for Elegant Angel', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/dv-tp/0.jpeg', | ||||
|             target_id: tagsMap['dv-tp'], | ||||
|             role: 'photo', | ||||
|             comment: 'Luna Rival in LegalPorno SZ1490', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/tattoo/poster.jpeg', | ||||
|             target_id: tagsMap.tattoo, | ||||
|             role: 'poster', | ||||
|             comment: 'Kali Roses in "Goes All In For Anal" for Hussie Pass', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/triple-anal/poster.jpeg', | ||||
|             target_id: tagsMap['triple-anal'], | ||||
|             role: 'poster', | ||||
|             comment: 'Kristy Black in SZ1986 for LegalPorno', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/triple-anal/1.jpeg', | ||||
|             target_id: tagsMap['triple-anal'], | ||||
|             role: 'photo', | ||||
|             comment: 'Natasha Teen in SZ2098 for LegalPorno', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/triple-anal/2.jpeg', | ||||
|             target_id: tagsMap['triple-anal'], | ||||
|             role: 'photo', | ||||
|             comment: 'Kira Thorn in GIO1018 for LegalPorno', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/blowbang/poster.jpeg', | ||||
|             target_id: tagsMap.blowbang, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/gangbang/poster.jpeg', | ||||
|             target_id: tagsMap.gangbang, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/gangbang/1.jpeg', | ||||
|             target_id: tagsMap.gangbang, | ||||
|             role: 'photo', | ||||
|             comment: 'Ginger Lynn in "Gangbang Mystique", a photoset shot by Suze Randall for Puritan No. 10, 1984. This photo pushed the boundaries of pornography at the time, as depicting a woman \'fully occupied\' was unheard of.', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/gangbang/2.jpeg', | ||||
|             target_id: tagsMap.gangbang, | ||||
|             role: 'photo', | ||||
|             comment: 'Riley Reid\'s double anal in "The Gangbang of Riley Reid" for Jules Jordan', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/gangbang/3.jpeg', | ||||
|             target_id: tagsMap.gangbang, | ||||
|             role: 'photo', | ||||
|             comment: 'Kelsi Monroe in "Brazzers House 2, Day 2" for Brazzers', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/mff/poster.jpeg', | ||||
|             target_id: tagsMap.mff, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/mfm/poster.jpeg', | ||||
|             target_id: tagsMap.mfm, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/orgy/poster.jpeg', | ||||
|             target_id: tagsMap.orgy, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/asian/poster.jpeg', | ||||
|             target_id: tagsMap.asian, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/caucasian/poster.jpeg', | ||||
|             target_id: tagsMap.caucasian, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/ebony/poster.jpeg', | ||||
|             target_id: tagsMap.ebony, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/latina/poster.jpeg', | ||||
|             target_id: tagsMap.latina, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/interracial/poster.jpeg', | ||||
|             target_id: tagsMap.interracial, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/facial/poster.jpeg', | ||||
|             target_id: tagsMap.facial, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/bukkake/poster.jpeg', | ||||
|             target_id: tagsMap.bukkake, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/swallowing/poster.jpeg', | ||||
|             target_id: tagsMap.swallowing, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/creampie/poster.jpeg', | ||||
|             target_id: tagsMap.creampie, | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/anal-creampie/poster.jpeg', | ||||
|             target_id: tagsMap['anal-creampie'], | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|         { | ||||
|             path: 'tags/oral-creampie/poster.jpeg', | ||||
|             target_id: tagsMap['oral-creampie'], | ||||
|             role: 'poster', | ||||
|             comment: '', | ||||
|         }, | ||||
|     ] | ||||
|         .map((file, index) => ({ | ||||
|             ...file, | ||||
|             thumbnail: file.thumbnail || file.path.replace('.jpeg', '_thumb.jpeg'), | ||||
|             mime: 'image/jpeg', | ||||
|             index, | ||||
|             domain: file.domain || 'tags', | ||||
|             target: { [file.domain || 'tags']: file.target_id }, | ||||
|             role: file.role || 'photo', | ||||
|         })); | ||||
| } | ||||
| const tagPosters = [ | ||||
|     { | ||||
|         path: 'tags/airtight/poster.jpeg', | ||||
|         tagSlug: 'airtight', | ||||
|         comment: 'Jynx Maze in "Pump My Ass Full of Cum 3" for Jules Jordan', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/anal/poster.jpeg', | ||||
|         tagSlug: 'anal', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/double-penetration/poster.jpeg', | ||||
|         tagSlug: 'double-penetration', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/double-anal/poster.jpeg', | ||||
|         tagSlug: 'double-anal', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/double-vaginal/poster.jpeg', | ||||
|         tagSlug: 'double-vaginal', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/tattoo/poster.jpeg', | ||||
|         tagSlug: 'tattoo', | ||||
|         comment: 'Kali Roses in "Goes All In For Anal" for Hussie Pass', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/triple-anal/poster.jpeg', | ||||
|         tagSlug: 'triple-anal', | ||||
|         comment: 'Kristy Black in SZ1986 for LegalPorno', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/blowbang/poster.jpeg', | ||||
|         tagSlug: 'blowbang', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/gangbang/poster.jpeg', | ||||
|         tagSlug: 'gangbang', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/mff/poster.jpeg', | ||||
|         tagSlug: 'mff', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/mfm/poster.jpeg', | ||||
|         tagSlug: 'mfm', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/orgy/poster.jpeg', | ||||
|         tagSlug: 'orgy', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/asian/poster.jpeg', | ||||
|         tagSlug: 'asian', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/caucasian/poster.jpeg', | ||||
|         tagSlug: 'caucasian', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/ebony/poster.jpeg', | ||||
|         tagSlug: 'ebony', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/latina/poster.jpeg', | ||||
|         tagSlug: 'latina', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/interracial/poster.jpeg', | ||||
|         tagSlug: 'interracial', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/facial/poster.jpeg', | ||||
|         tagSlug: 'facial', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/bukkake/poster.jpeg', | ||||
|         tagSlug: 'bukkake', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/swallowing/poster.jpeg', | ||||
|         tagSlug: 'swallowing', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/creampie/poster.jpeg', | ||||
|         tagSlug: 'creampie', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/anal-creampie/poster.jpeg', | ||||
|         tagSlug: 'anal-creampie', | ||||
|         comment: '', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/oral-creampie/poster.jpeg', | ||||
|         tagSlug: 'oral-creampie', | ||||
|         comment: '', | ||||
|     }, | ||||
| ] | ||||
|     .map((file, index) => ({ | ||||
|         ...file, | ||||
|         thumbnail: file.thumbnail || file.path.replace('.jpeg', '_thumb.jpeg'), | ||||
|         mime: 'image/jpeg', | ||||
|         index, | ||||
|     })); | ||||
| 
 | ||||
| const tagPhotos = [ | ||||
|     { | ||||
|         path: 'tags/airtight/2.jpeg', | ||||
|         tagSlug: 'airtight', | ||||
|         comment: 'Dakota Skye in "Dakota Goes Nuts" for ArchAngel', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/airtight/1.jpeg', | ||||
|         tagSlug: 'airtight', | ||||
|         comment: 'Chloe Amour in "DP Masters 4" for Jules Jordan', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/airtight/0.jpeg', | ||||
|         domain: 'tags', | ||||
|         tagSlug: 'airtight', | ||||
|         comment: 'Sheena Shaw in "Ass Worship 14" for Jules Jordan', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/da-tp/0.jpeg', | ||||
|         tagSlug: 'da-tp', | ||||
|         comment: 'Natasha Teen in LegalPorno SZ2164', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/da-tp/3.jpeg', | ||||
|         tagSlug: 'da-tp', | ||||
|         comment: 'Evelina Darling in GIO294', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/da-tp/1.jpeg', | ||||
|         tagSlug: 'da-tp', | ||||
|         comment: 'Francys Belle in SZ1702 for LegalPorno', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/da-tp/2.jpeg', | ||||
|         tagSlug: 'da-tp', | ||||
|         comment: 'Angel Smalls in GIO408 for LegalPorno', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/da-tp/4.jpeg', | ||||
|         tagSlug: 'da-tp', | ||||
|         comment: 'Ninel Mojado aka Mira Cuckold in GIO063 for LegalPorno', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/dv-tp/poster.jpeg', | ||||
|         tagSlug: 'dv-tp', | ||||
|         comment: 'Juelz Ventura in "Gangbanged 5" for Elegant Angel', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/dv-tp/0.jpeg', | ||||
|         tagSlug: 'dv-tp', | ||||
|         comment: 'Luna Rival in LegalPorno SZ1490', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/triple-anal/1.jpeg', | ||||
|         tagSlug: 'triple-anal', | ||||
|         comment: 'Natasha Teen in SZ2098 for LegalPorno', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/triple-anal/2.jpeg', | ||||
|         tagSlug: 'triple-anal', | ||||
|         comment: 'Kira Thorn in GIO1018 for LegalPorno', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/gangbang/1.jpeg', | ||||
|         tagSlug: 'gangbang', | ||||
|         comment: 'Ginger Lynn in "Gangbang Mystique", a photoset shot by Suze Randall for Puritan No. 10, 1984. This photo pushed the boundaries of pornography at the time, as depicting a woman \'fully occupied\' was unheard of.', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/gangbang/2.jpeg', | ||||
|         tagSlug: 'gangbang', | ||||
|         comment: 'Riley Reid\'s double anal in "The Gangbang of Riley Reid" for Jules Jordan', | ||||
|     }, | ||||
|     { | ||||
|         path: 'tags/gangbang/3.jpeg', | ||||
|         tagSlug: 'gangbang', | ||||
|         comment: 'Kelsi Monroe in "Brazzers House 2, Day 2" for Brazzers', | ||||
|     }, | ||||
| ] | ||||
|     .map((file, index) => ({ | ||||
|         ...file, | ||||
|         thumbnail: file.thumbnail || file.path.replace('.jpeg', '_thumb.jpeg'), | ||||
|         mime: 'image/jpeg', | ||||
|         index, | ||||
|     })); | ||||
| 
 | ||||
| /* eslint-disable max-len */ | ||||
| exports.seed = knex => Promise.resolve() | ||||
|     .then(async () => { | ||||
|         const [duplicates, tags] = await Promise.all([ | ||||
|             knex('media').where('domain', 'tags'), | ||||
|             knex('tags').where('alias_for', null), | ||||
|         const tagMedia = tagPosters.concat(tagPhotos); | ||||
| 
 | ||||
|         const tags = await knex('tags').whereIn('slug', tagMedia.map(item => item.tagSlug)); | ||||
|         const { inserted, updated } = await upsert('media', tagMedia.map(({ | ||||
|             path, thumbnail, mime, index, comment, | ||||
|         }) => ({ | ||||
|             path, thumbnail, mime, index, comment, | ||||
|         })), 'path', knex); | ||||
| 
 | ||||
|         const tagIdsBySlug = tags.reduce((acc, tag) => ({ ...acc, [tag.slug]: tag.id }), {}); | ||||
|         const mediaIdsByPath = inserted.concat(updated).reduce((acc, item) => ({ ...acc, [item.path]: item.id }), {}); | ||||
| 
 | ||||
|         const tagPosterEntries = tagPosters.map(poster => ({ | ||||
|             tag_id: tagIdsBySlug[poster.tagSlug], | ||||
|             media_id: mediaIdsByPath[poster.path], | ||||
|         })); | ||||
| 
 | ||||
|         const tagPhotoEntries = tagPhotos.map(photo => ({ | ||||
|             tag_id: tagIdsBySlug[photo.tagSlug], | ||||
|             media_id: mediaIdsByPath[photo.path], | ||||
|         })); | ||||
| 
 | ||||
|         return Promise.all([ | ||||
|             upsert('tags_posters', tagPosterEntries, 'tag_id', knex), | ||||
|             upsert('tags_photos', tagPhotoEntries, 'tag_id', knex), | ||||
|         ]); | ||||
| 
 | ||||
|         const duplicatesByPath = duplicates.reduce((acc, file) => ({ ...acc, [file.path]: file }), {}); | ||||
|         const tagsMap = tags.reduce((acc, { id, slug }) => ({ ...acc, [slug]: id }), {}); | ||||
| 
 | ||||
|         const media = getMedia(tagsMap); | ||||
| 
 | ||||
|         return upsert('media', media, duplicatesByPath, 'path', knex); | ||||
|     }); | ||||
|  |  | |||
|  | @ -1755,9 +1755,4 @@ const countries = [ | |||
| ]; | ||||
| 
 | ||||
| exports.seed = knex => knex('countries') | ||||
|     .then(async () => { | ||||
|         const duplicates = await knex('countries').select('*'); | ||||
|         const duplicatesByAlpha2 = duplicates.reduce((acc, country) => ({ ...acc, [country.alpha2]: country }), {}); | ||||
| 
 | ||||
|         return upsert('countries', countries, duplicatesByAlpha2, 'alpha2', knex); | ||||
|     }); | ||||
|     .then(async () => upsert('countries', countries, 'alpha2', knex)); | ||||
|  |  | |||
|  | @ -1,29 +1,18 @@ | |||
| 'use strict'; | ||||
| 
 | ||||
| async function upsert(table, items, duplicatesById, identifier = 'id', knex) { | ||||
| async function upsert(table, items, identifier = 'id', knex) { | ||||
|     const duplicates = await knex(table).whereIn(identifier, items.map(item => item[identifier])); | ||||
|     const duplicatesByIdentifier = duplicates.reduce((acc, item) => ({ ...acc, [item[identifier]]: item }), {}); | ||||
| 
 | ||||
|     const { insert, update } = items.reduce((acc, item) => { | ||||
|         if (duplicatesById[item[identifier]]) { | ||||
|             return { | ||||
|                 ...acc, | ||||
|                 update: [ | ||||
|                     ...acc.update, | ||||
|                     { | ||||
|                         ...duplicatesById[item[identifier]], | ||||
|                         ...item, | ||||
|                     }, | ||||
|                 ], | ||||
|             }; | ||||
|         if (duplicatesByIdentifier[item[identifier]]) { | ||||
|             acc.update.push(item); | ||||
|             return acc; | ||||
|         } | ||||
| 
 | ||||
|         return { | ||||
|             ...acc, | ||||
|             insert: [ | ||||
|                 ...acc.insert, | ||||
|                 item, | ||||
|             ], | ||||
|         }; | ||||
|     }, | ||||
|     { | ||||
|         acc.insert.push(item); | ||||
|         return acc; | ||||
|     }, { | ||||
|         insert: [], | ||||
|         update: [], | ||||
|     }); | ||||
|  | @ -32,13 +21,19 @@ async function upsert(table, items, duplicatesById, identifier = 'id', knex) { | |||
|         console.log(`${table}: Inserting ${insert.length}`); | ||||
|         console.log(`${table}: Updating ${update.length}`); | ||||
| 
 | ||||
|         return Promise.all([ | ||||
|             knex(table).insert(insert), | ||||
|         const [inserted, updated] = await Promise.all([ | ||||
|             knex(table).returning('*').insert(insert), | ||||
|             knex.transaction(async trx => Promise.all(update.map(item => trx | ||||
|                 .where({ [identifier]: item[identifier] }) | ||||
|                 .update(item) | ||||
|                 .into(table)))), | ||||
|                 .into(table) | ||||
|                 .returning('*')))), | ||||
|         ]); | ||||
| 
 | ||||
|         return { | ||||
|             inserted: Array.isArray(inserted) ? inserted : [], | ||||
|             updated: updated.reduce((acc, updatedItems) => acc.concat(updatedItems), []), | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     return { insert, update }; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue