Simplified link tracking related tables naming (#15480)

- Removes superfluous "link" from table names
- Fixes type definititon of dropTables util
- Updates & renames models
- Noop existing migrations to avoid unnecessary work
This commit is contained in:
Fabien 'egg' O'Carroll 2022-09-29 22:08:45 +01:00 committed by GitHub
parent 579ca615f9
commit 45d65663f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 96 additions and 50 deletions

View File

@ -39,8 +39,8 @@ const BACKUP_TABLES = [
'comment_likes',
'comment_reports',
'jobs',
'link_redirects',
'members_link_click_events'
'redirects',
'members_click_events'
];
// NOTE: exposing only tables which are going to be included in a "default" export file

View File

@ -38,7 +38,7 @@ function addTable(name, tableSpec) {
/**
* Creates migration which will drop a table
*
* @param {[string]} names - names of the tables to drop
* @param {string[]} names - names of the tables to drop
*/
function dropTables(names) {
return createIrreversibleMigration(

View File

@ -1,10 +1,9 @@
const {addTable} = require('../../utils');
module.exports = addTable('link_redirects', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
from: {type: 'string', maxlength: 2000, nullable: false},
to: {type: 'string', maxlength: 2000, nullable: false},
post_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'posts.id', setNullDelete: true},
created_at: {type: 'dateTime', nullable: false},
updated_at: {type: 'dateTime', nullable: true}
});
const logging = require('@tryghost/logging');
module.exports = {
async up() {
logging.warn('Skipping migration - noop');
},
async down() {
logging.warn('Skipping migration - noop');
}
};

View File

@ -1,8 +1,9 @@
const {addTable} = require('../../utils');
module.exports = addTable('members_link_click_events', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
link_id: {type: 'string', maxlength: 24, nullable: false, references: 'link_redirects.id', cascadeDelete: true},
created_at: {type: 'dateTime', nullable: false}
});
const logging = require('@tryghost/logging');
module.exports = {
async up() {
logging.warn('Skipping migration - noop');
},
async down() {
logging.warn('Skipping migration - noop');
}
};

View File

@ -0,0 +1,28 @@
const {addTable, combineNonTransactionalMigrations} = require('../../utils');
function reverseMigration({up, down, config}) {
return {
config,
up: down,
down: up
};
}
module.exports = reverseMigration(
combineNonTransactionalMigrations(
addTable('link_redirects', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
from: {type: 'string', maxlength: 2000, nullable: false},
to: {type: 'string', maxlength: 2000, nullable: false},
post_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'posts.id', setNullDelete: true},
created_at: {type: 'dateTime', nullable: false},
updated_at: {type: 'dateTime', nullable: true}
}),
addTable('members_link_click_events', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
link_id: {type: 'string', maxlength: 24, nullable: false, references: 'link_redirects.id', cascadeDelete: true},
created_at: {type: 'dateTime', nullable: false}
})
)
);

View File

@ -0,0 +1,10 @@
const {addTable} = require('../../utils');
module.exports = addTable('redirects', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
from: {type: 'string', maxlength: 2000, nullable: false},
to: {type: 'string', maxlength: 2000, nullable: false},
post_id: {type: 'string', maxlength: 24, nullable: true, unique: false, references: 'posts.id', setNullDelete: true},
created_at: {type: 'dateTime', nullable: false},
updated_at: {type: 'dateTime', nullable: true}
});

View File

@ -0,0 +1,8 @@
const {addTable} = require('../../utils');
module.exports = addTable('members_click_events', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
redirect_id: {type: 'string', maxlength: 24, nullable: false, references: 'redirects.id', cascadeDelete: true},
created_at: {type: 'dateTime', nullable: false}
});

View File

@ -837,7 +837,7 @@ module.exports = {
created_at: {type: 'dateTime', nullable: false},
updated_at: {type: 'dateTime', nullable: true}
},
link_redirects: {
redirects: {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
from: {type: 'string', maxlength: 2000, nullable: false},
to: {type: 'string', maxlength: 2000, nullable: false},
@ -845,10 +845,10 @@ module.exports = {
created_at: {type: 'dateTime', nullable: false},
updated_at: {type: 'dateTime', nullable: true}
},
members_link_click_events: {
members_click_events: {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
link_id: {type: 'string', maxlength: 24, nullable: false, references: 'link_redirects.id', cascadeDelete: true},
redirect_id: {type: 'string', maxlength: 24, nullable: false, references: 'redirects.id', cascadeDelete: true},
created_at: {type: 'dateTime', nullable: false}
}
};

View File

@ -1,11 +1,11 @@
const errors = require('@tryghost/errors');
const ghostBookshelf = require('./base');
const MemberLinkClickEvent = ghostBookshelf.Model.extend({
tableName: 'members_link_click_events',
const MemberClickEvent = ghostBookshelf.Model.extend({
tableName: 'members_click_events',
link() {
return this.belongsTo('LinkRedirect', 'link_id');
return this.belongsTo('Redirect', 'link_id');
},
member() {
@ -13,14 +13,14 @@ const MemberLinkClickEvent = ghostBookshelf.Model.extend({
}
}, {
async edit() {
throw new errors.IncorrectUsageError({message: 'Cannot edit MemberLinkClickEvent'});
throw new errors.IncorrectUsageError({message: 'Cannot edit MemberClickEvent'});
},
async destroy() {
throw new errors.IncorrectUsageError({message: 'Cannot destroy MemberLinkClickEvent'});
throw new errors.IncorrectUsageError({message: 'Cannot destroy MemberClickEvent'});
}
});
module.exports = {
MemberLinkClickEvent: ghostBookshelf.model('MemberLinkClickEvent', MemberLinkClickEvent)
MemberClickEvent: ghostBookshelf.model('MemberClickEvent', MemberClickEvent)
};

View File

@ -1348,10 +1348,10 @@ Post = ghostBookshelf.Model.extend({
},
clicks(modelOrCollection) {
modelOrCollection.query('columns', 'posts.*', (qb) => {
qb.countDistinct('members_link_click_events.member_id')
.from('members_link_click_events')
.join('link_redirects', 'members_link_click_events.link_id', 'link_redirects.id')
.whereRaw('posts.id = link_redirects.post_id')
qb.countDistinct('members_click_events.member_id')
.from('members_click_events')
.join('redirects', 'members_click_events.redirect_id', 'redirects.id')
.whereRaw('posts.id = redirects.post_id')
.as('count__clicks');
});
}

View File

@ -1,8 +1,8 @@
const ghostBookshelf = require('./base');
const urlUtils = require('../../shared/url-utils');
const LinkRedirect = ghostBookshelf.Model.extend({
tableName: 'link_redirects',
const Redirect = ghostBookshelf.Model.extend({
tableName: 'redirects',
post() {
return this.belongsTo('Post', 'post_id');
@ -49,10 +49,10 @@ const LinkRedirect = ghostBookshelf.Model.extend({
countRelations() {
return {
clicks(modelOrCollection) {
modelOrCollection.query('columns', 'link_redirects.*', (qb) => {
qb.countDistinct('members_link_click_events.member_id')
.from('members_link_click_events')
.whereRaw('link_redirects.id = members_link_click_events.link_id')
modelOrCollection.query('columns', 'redirects.*', (qb) => {
qb.countDistinct('members_click_events.member_id')
.from('members_click_events')
.whereRaw('redirects.id = members_click_events.redirect_id')
.as('count__clicks');
});
}
@ -61,5 +61,5 @@ const LinkRedirect = ghostBookshelf.Model.extend({
});
module.exports = {
LinkRedirect: ghostBookshelf.model('LinkRedirect', LinkRedirect)
Redirect: ghostBookshelf.model('Redirect', Redirect)
};

View File

@ -14,7 +14,7 @@ class LinkRedirectsServiceWrapper {
const {LinkRedirectsService} = require('@tryghost/link-redirects');
this.linkRedirectRepository = new LinkRedirectRepository({
LinkRedirect: models.LinkRedirect,
LinkRedirect: models.Redirect,
urlUtils
});

View File

@ -36,7 +36,7 @@ module.exports = class LinkClickRepository {
for (const model of collection.models) {
const member = await this.#Member.findOne({id: model.get('member_id')});
result.push(new LinkClick({
link_id: model.get('link_id'),
link_id: model.get('redirect_id'),
member_uuid: member.get('uuid')
}));
}
@ -57,7 +57,7 @@ module.exports = class LinkClickRepository {
const model = await this.#MemberLinkClickEventModel.add({
// Only store the parthname (no support for variable query strings)
link_id: linkClick.link_id.toHexString(),
redirect_id: linkClick.link_id.toHexString(),
member_id: member.id
}, {});

View File

@ -22,12 +22,12 @@ class LinkTrackingServiceWrapper {
const {LinkClickTrackingService} = require('@tryghost/link-tracking');
const postLinkRepository = new PostLinkRepository({
LinkRedirect: models.LinkRedirect,
LinkRedirect: models.Redirect,
linkRedirectRepository: linkRedirection.linkRedirectRepository
});
this.linkClickRepository = new LinkClickRepository({
MemberLinkClickEventModel: models.MemberLinkClickEvent,
MemberLinkClickEventModel: models.MemberClickEvent,
Member: models.Member,
MemberLinkClickEvent: MemberLinkClickEvent,
DomainEvents

View File

@ -187,7 +187,7 @@ function createApiInstance(config) {
MemberAnalyticEvent: models.MemberAnalyticEvent,
MemberCreatedEvent: models.MemberCreatedEvent,
SubscriptionCreatedEvent: models.SubscriptionCreatedEvent,
MemberLinkClickEvent: models.MemberLinkClickEvent,
MemberLinkClickEvent: models.MemberClickEvent,
OfferRedemption: models.OfferRedemption,
Offer: models.Offer,
StripeProduct: models.StripeProduct,

View File

@ -36,12 +36,12 @@ describe('Exporter', function () {
'invites',
'jobs',
'labels',
'link_redirects',
'redirects',
'members',
'members_cancel_events',
'members_email_change_events',
'members_labels',
'members_link_click_events',
'members_click_events',
'members_login_events',
'members_newsletters',
'members_paid_subscription_events',

View File

@ -35,7 +35,7 @@ const validateRouteSettings = require('../../../../../core/server/services/route
*/
describe('DB version integrity', function () {
// Only these variables should need updating
const currentSchemaHash = '2a59debcacc1e3dc0b15e2f729ca4bdb';
const currentSchemaHash = '67009be314428b02976e75281de37b14';
const currentFixturesHash = '8cf221f0ed930ac1fe8030a58e60d64b';
const currentSettingsHash = '2978a5684a2d5fcf089f61f5d368a0c0';
const currentRoutesHash = '3d180d52c663d173a6be791ef411ed01';