agrs-sequelize-sdk 1.2.99 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/migrations/add-requested-from-dashboard-to-articles.js +17 -17
- package/models/AdAccountValues.js +25 -25
- package/models/AdHistory.js +30 -30
- package/models/AdPerformance.js +94 -94
- package/models/AdSet.js +289 -289
- package/models/AdSetHistory.js +30 -30
- package/models/AdsetPerformance.js +126 -126
- package/models/Article.js +190 -190
- package/models/AutomationRule.js +161 -127
- package/models/Buyers.js +25 -25
- package/models/Campaign.js +157 -157
- package/models/CampaignActionHistory.js +86 -86
- package/models/CampaignCreationLog.js +309 -309
- package/models/CampaignHistory.js +33 -33
- package/models/Channel.js +55 -55
- package/models/Domain.js +25 -25
- package/models/DynamicFeed.js +212 -212
- package/models/ExplorAdsChannel.js +61 -61
- package/models/Feed.js +33 -33
- package/models/FrontStoryChannel.js +59 -59
- package/models/MineChannel.js +42 -42
- package/models/Pages.js +81 -81
- package/models/PipelineExecution.js +59 -59
- package/models/Presets.js +34 -34
- package/models/RSOCFeedCampaign.js +357 -357
- package/models/RsocKeywordPerformance.js +110 -110
- package/models/RuleAction.js +90 -90
- package/models/RuleCondition.js +98 -98
- package/models/RuleExecution.js +107 -107
- package/models/RulesValues.js +56 -56
- package/models/SupportedLocale.js +23 -23
- package/models/SyncHistory.js +249 -249
- package/models/Tier2_AdAccounts.js +110 -110
- package/models/Tier2_Assets.js +70 -70
- package/models/Tier2_BusinessManagers.js +105 -105
- package/models/Tier2_CreditLines.js +99 -99
- package/models/Tier2_Pages.js +91 -91
- package/models/Tier2_Pixels.js +82 -82
- package/models/Tier2_Tokens.js +64 -64
- package/models/Tier2_UserAdAccounts.js +83 -83
- package/models/TokenRotationState.js +121 -121
- package/models/TonicRSOCKeywordPerformance.js +122 -122
- package/models/Vertical.js +25 -25
- package/models/newFiles.js +110 -110
- package/package.json +19 -21
- package/run.sh +214 -214
- package/services/sequelizeService.js +63 -63
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
module.exports = (sequelize, DataTypes) => {
|
|
2
|
-
const Tier2_UserAdAccounts = sequelize.define(
|
|
3
|
-
"Tier2_UserAdAccounts",
|
|
4
|
-
{
|
|
5
|
-
id: {
|
|
6
|
-
type: DataTypes.UUID,
|
|
7
|
-
defaultValue: DataTypes.UUIDV4,
|
|
8
|
-
primaryKey: true,
|
|
9
|
-
},
|
|
10
|
-
userId: {
|
|
11
|
-
type: DataTypes.STRING,
|
|
12
|
-
allowNull: false,
|
|
13
|
-
comment: "User ID (can be internal system ID or external ID)",
|
|
14
|
-
},
|
|
15
|
-
adAccountId: {
|
|
16
|
-
type: DataTypes.UUID,
|
|
17
|
-
allowNull: false,
|
|
18
|
-
references: {
|
|
19
|
-
model: "Tier2_AdAccounts",
|
|
20
|
-
key: "id",
|
|
21
|
-
},
|
|
22
|
-
onUpdate: "CASCADE",
|
|
23
|
-
onDelete: "CASCADE",
|
|
24
|
-
},
|
|
25
|
-
facebookAdAccountId: {
|
|
26
|
-
type: DataTypes.STRING,
|
|
27
|
-
allowNull: false,
|
|
28
|
-
comment: "Facebook Ad Account ID (for quick reference)",
|
|
29
|
-
},
|
|
30
|
-
permissions: {
|
|
31
|
-
type: DataTypes.ARRAY(DataTypes.STRING),
|
|
32
|
-
allowNull: false,
|
|
33
|
-
defaultValue: ["view", "create_campaigns", "view_performance"],
|
|
34
|
-
comment:
|
|
35
|
-
"Permissions: view, create_campaigns, edit_campaigns, view_performance, manage_assets",
|
|
36
|
-
},
|
|
37
|
-
assignedAt: {
|
|
38
|
-
type: DataTypes.DATE,
|
|
39
|
-
allowNull: false,
|
|
40
|
-
defaultValue: DataTypes.NOW,
|
|
41
|
-
},
|
|
42
|
-
assignedBy: {
|
|
43
|
-
type: DataTypes.STRING,
|
|
44
|
-
allowNull: true,
|
|
45
|
-
comment: "User ID who assigned this ad account",
|
|
46
|
-
},
|
|
47
|
-
status: {
|
|
48
|
-
type: DataTypes.ENUM("active", "suspended", "revoked"),
|
|
49
|
-
allowNull: false,
|
|
50
|
-
defaultValue: "active",
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
tableName: "Tier2_UserAdAccounts",
|
|
55
|
-
indexes: [
|
|
56
|
-
{
|
|
57
|
-
fields: ["userId"],
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
fields: ["adAccountId"],
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
fields: ["facebookAdAccountId"],
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
unique: true,
|
|
67
|
-
fields: ["userId", "adAccountId"],
|
|
68
|
-
name: "unique_user_ad_account",
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
}
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
Tier2_UserAdAccounts.associate = (models) => {
|
|
75
|
-
// Association with Tier2_AdAccounts
|
|
76
|
-
Tier2_UserAdAccounts.belongsTo(models.Tier2_AdAccounts, {
|
|
77
|
-
foreignKey: "adAccountId",
|
|
78
|
-
as: "adAccount",
|
|
79
|
-
});
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
return Tier2_UserAdAccounts;
|
|
83
|
-
};
|
|
1
|
+
module.exports = (sequelize, DataTypes) => {
|
|
2
|
+
const Tier2_UserAdAccounts = sequelize.define(
|
|
3
|
+
"Tier2_UserAdAccounts",
|
|
4
|
+
{
|
|
5
|
+
id: {
|
|
6
|
+
type: DataTypes.UUID,
|
|
7
|
+
defaultValue: DataTypes.UUIDV4,
|
|
8
|
+
primaryKey: true,
|
|
9
|
+
},
|
|
10
|
+
userId: {
|
|
11
|
+
type: DataTypes.STRING,
|
|
12
|
+
allowNull: false,
|
|
13
|
+
comment: "User ID (can be internal system ID or external ID)",
|
|
14
|
+
},
|
|
15
|
+
adAccountId: {
|
|
16
|
+
type: DataTypes.UUID,
|
|
17
|
+
allowNull: false,
|
|
18
|
+
references: {
|
|
19
|
+
model: "Tier2_AdAccounts",
|
|
20
|
+
key: "id",
|
|
21
|
+
},
|
|
22
|
+
onUpdate: "CASCADE",
|
|
23
|
+
onDelete: "CASCADE",
|
|
24
|
+
},
|
|
25
|
+
facebookAdAccountId: {
|
|
26
|
+
type: DataTypes.STRING,
|
|
27
|
+
allowNull: false,
|
|
28
|
+
comment: "Facebook Ad Account ID (for quick reference)",
|
|
29
|
+
},
|
|
30
|
+
permissions: {
|
|
31
|
+
type: DataTypes.ARRAY(DataTypes.STRING),
|
|
32
|
+
allowNull: false,
|
|
33
|
+
defaultValue: ["view", "create_campaigns", "view_performance"],
|
|
34
|
+
comment:
|
|
35
|
+
"Permissions: view, create_campaigns, edit_campaigns, view_performance, manage_assets",
|
|
36
|
+
},
|
|
37
|
+
assignedAt: {
|
|
38
|
+
type: DataTypes.DATE,
|
|
39
|
+
allowNull: false,
|
|
40
|
+
defaultValue: DataTypes.NOW,
|
|
41
|
+
},
|
|
42
|
+
assignedBy: {
|
|
43
|
+
type: DataTypes.STRING,
|
|
44
|
+
allowNull: true,
|
|
45
|
+
comment: "User ID who assigned this ad account",
|
|
46
|
+
},
|
|
47
|
+
status: {
|
|
48
|
+
type: DataTypes.ENUM("active", "suspended", "revoked"),
|
|
49
|
+
allowNull: false,
|
|
50
|
+
defaultValue: "active",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
tableName: "Tier2_UserAdAccounts",
|
|
55
|
+
indexes: [
|
|
56
|
+
{
|
|
57
|
+
fields: ["userId"],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
fields: ["adAccountId"],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
fields: ["facebookAdAccountId"],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
unique: true,
|
|
67
|
+
fields: ["userId", "adAccountId"],
|
|
68
|
+
name: "unique_user_ad_account",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
Tier2_UserAdAccounts.associate = (models) => {
|
|
75
|
+
// Association with Tier2_AdAccounts
|
|
76
|
+
Tier2_UserAdAccounts.belongsTo(models.Tier2_AdAccounts, {
|
|
77
|
+
foreignKey: "adAccountId",
|
|
78
|
+
as: "adAccount",
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return Tier2_UserAdAccounts;
|
|
83
|
+
};
|
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
// models/TokenRotationState.js
|
|
2
|
-
module.exports = (sequelize, DataTypes) => {
|
|
3
|
-
const TokenRotationState = sequelize.define(
|
|
4
|
-
"TokenRotationState",
|
|
5
|
-
{
|
|
6
|
-
id: {
|
|
7
|
-
type: DataTypes.INTEGER,
|
|
8
|
-
primaryKey: true,
|
|
9
|
-
autoIncrement: true,
|
|
10
|
-
},
|
|
11
|
-
tokenType: {
|
|
12
|
-
type: DataTypes.STRING,
|
|
13
|
-
allowNull: false,
|
|
14
|
-
unique: true,
|
|
15
|
-
defaultValue: "FACEBOOK_ACCESS_TOKEN",
|
|
16
|
-
comment: "Type of token being rotated (e.g., FACEBOOK_ACCESS_TOKEN)",
|
|
17
|
-
},
|
|
18
|
-
currentIndex: {
|
|
19
|
-
type: DataTypes.INTEGER,
|
|
20
|
-
allowNull: false,
|
|
21
|
-
defaultValue: 0,
|
|
22
|
-
comment: "Current index in the token rotation (0-based)",
|
|
23
|
-
},
|
|
24
|
-
totalTokens: {
|
|
25
|
-
type: DataTypes.INTEGER,
|
|
26
|
-
allowNull: false,
|
|
27
|
-
defaultValue: 10,
|
|
28
|
-
comment: "Total number of tokens in rotation",
|
|
29
|
-
},
|
|
30
|
-
lastUsedAt: {
|
|
31
|
-
type: DataTypes.DATE,
|
|
32
|
-
allowNull: true,
|
|
33
|
-
comment: "Timestamp of last token usage",
|
|
34
|
-
},
|
|
35
|
-
totalUsageCount: {
|
|
36
|
-
type: DataTypes.BIGINT,
|
|
37
|
-
allowNull: false,
|
|
38
|
-
defaultValue: 0,
|
|
39
|
-
comment: "Total number of times tokens have been used",
|
|
40
|
-
},
|
|
41
|
-
rotationStrategy: {
|
|
42
|
-
type: DataTypes.ENUM("round_robin", "least_used", "random"),
|
|
43
|
-
allowNull: false,
|
|
44
|
-
defaultValue: "round_robin",
|
|
45
|
-
comment: "Strategy for token rotation",
|
|
46
|
-
},
|
|
47
|
-
metadata: {
|
|
48
|
-
type: DataTypes.JSONB,
|
|
49
|
-
allowNull: true,
|
|
50
|
-
comment: "Additional metadata (per-token usage stats, health, etc.)",
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
tableName: "TokenRotationState",
|
|
55
|
-
timestamps: true, // Adds createdAt and updatedAt
|
|
56
|
-
indexes: [
|
|
57
|
-
{
|
|
58
|
-
fields: ["tokenType"],
|
|
59
|
-
unique: true,
|
|
60
|
-
name: "idx_token_rotation_type",
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
fields: ["lastUsedAt"],
|
|
64
|
-
name: "idx_token_rotation_last_used",
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
}
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
// Instance methods
|
|
71
|
-
TokenRotationState.prototype.incrementUsage = async function () {
|
|
72
|
-
this.totalUsageCount = (
|
|
73
|
-
BigInt(this.totalUsageCount) + BigInt(1)
|
|
74
|
-
).toString();
|
|
75
|
-
this.lastUsedAt = new Date();
|
|
76
|
-
await this.save();
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
TokenRotationState.prototype.rotateToNext = async function () {
|
|
80
|
-
this.currentIndex = (this.currentIndex + 1) % this.totalTokens;
|
|
81
|
-
await this.save();
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
TokenRotationState.prototype.getCurrentTokenNumber = function () {
|
|
85
|
-
return this.currentIndex + 1; // Return 1-based index
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// Static methods
|
|
89
|
-
TokenRotationState.getOrCreate = async function (
|
|
90
|
-
tokenType = "FACEBOOK_ACCESS_TOKEN"
|
|
91
|
-
) {
|
|
92
|
-
const [state, created] = await this.findOrCreate({
|
|
93
|
-
where: { tokenType },
|
|
94
|
-
defaults: {
|
|
95
|
-
tokenType,
|
|
96
|
-
currentIndex: 0,
|
|
97
|
-
totalTokens: 10,
|
|
98
|
-
rotationStrategy: "round_robin",
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
return state;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
TokenRotationState.getStats = async function (
|
|
105
|
-
tokenType = "FACEBOOK_ACCESS_TOKEN"
|
|
106
|
-
) {
|
|
107
|
-
const state = await this.findOne({ where: { tokenType } });
|
|
108
|
-
if (!state) return null;
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
currentTokenNumber: state.getCurrentTokenNumber(),
|
|
112
|
-
totalTokens: state.totalTokens,
|
|
113
|
-
totalUsageCount: state.totalUsageCount.toString(),
|
|
114
|
-
lastUsedAt: state.lastUsedAt,
|
|
115
|
-
rotationStrategy: state.rotationStrategy,
|
|
116
|
-
metadata: state.metadata,
|
|
117
|
-
};
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
return TokenRotationState;
|
|
121
|
-
};
|
|
1
|
+
// models/TokenRotationState.js
|
|
2
|
+
module.exports = (sequelize, DataTypes) => {
|
|
3
|
+
const TokenRotationState = sequelize.define(
|
|
4
|
+
"TokenRotationState",
|
|
5
|
+
{
|
|
6
|
+
id: {
|
|
7
|
+
type: DataTypes.INTEGER,
|
|
8
|
+
primaryKey: true,
|
|
9
|
+
autoIncrement: true,
|
|
10
|
+
},
|
|
11
|
+
tokenType: {
|
|
12
|
+
type: DataTypes.STRING,
|
|
13
|
+
allowNull: false,
|
|
14
|
+
unique: true,
|
|
15
|
+
defaultValue: "FACEBOOK_ACCESS_TOKEN",
|
|
16
|
+
comment: "Type of token being rotated (e.g., FACEBOOK_ACCESS_TOKEN)",
|
|
17
|
+
},
|
|
18
|
+
currentIndex: {
|
|
19
|
+
type: DataTypes.INTEGER,
|
|
20
|
+
allowNull: false,
|
|
21
|
+
defaultValue: 0,
|
|
22
|
+
comment: "Current index in the token rotation (0-based)",
|
|
23
|
+
},
|
|
24
|
+
totalTokens: {
|
|
25
|
+
type: DataTypes.INTEGER,
|
|
26
|
+
allowNull: false,
|
|
27
|
+
defaultValue: 10,
|
|
28
|
+
comment: "Total number of tokens in rotation",
|
|
29
|
+
},
|
|
30
|
+
lastUsedAt: {
|
|
31
|
+
type: DataTypes.DATE,
|
|
32
|
+
allowNull: true,
|
|
33
|
+
comment: "Timestamp of last token usage",
|
|
34
|
+
},
|
|
35
|
+
totalUsageCount: {
|
|
36
|
+
type: DataTypes.BIGINT,
|
|
37
|
+
allowNull: false,
|
|
38
|
+
defaultValue: 0,
|
|
39
|
+
comment: "Total number of times tokens have been used",
|
|
40
|
+
},
|
|
41
|
+
rotationStrategy: {
|
|
42
|
+
type: DataTypes.ENUM("round_robin", "least_used", "random"),
|
|
43
|
+
allowNull: false,
|
|
44
|
+
defaultValue: "round_robin",
|
|
45
|
+
comment: "Strategy for token rotation",
|
|
46
|
+
},
|
|
47
|
+
metadata: {
|
|
48
|
+
type: DataTypes.JSONB,
|
|
49
|
+
allowNull: true,
|
|
50
|
+
comment: "Additional metadata (per-token usage stats, health, etc.)",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
tableName: "TokenRotationState",
|
|
55
|
+
timestamps: true, // Adds createdAt and updatedAt
|
|
56
|
+
indexes: [
|
|
57
|
+
{
|
|
58
|
+
fields: ["tokenType"],
|
|
59
|
+
unique: true,
|
|
60
|
+
name: "idx_token_rotation_type",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
fields: ["lastUsedAt"],
|
|
64
|
+
name: "idx_token_rotation_last_used",
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Instance methods
|
|
71
|
+
TokenRotationState.prototype.incrementUsage = async function () {
|
|
72
|
+
this.totalUsageCount = (
|
|
73
|
+
BigInt(this.totalUsageCount) + BigInt(1)
|
|
74
|
+
).toString();
|
|
75
|
+
this.lastUsedAt = new Date();
|
|
76
|
+
await this.save();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
TokenRotationState.prototype.rotateToNext = async function () {
|
|
80
|
+
this.currentIndex = (this.currentIndex + 1) % this.totalTokens;
|
|
81
|
+
await this.save();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
TokenRotationState.prototype.getCurrentTokenNumber = function () {
|
|
85
|
+
return this.currentIndex + 1; // Return 1-based index
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Static methods
|
|
89
|
+
TokenRotationState.getOrCreate = async function (
|
|
90
|
+
tokenType = "FACEBOOK_ACCESS_TOKEN"
|
|
91
|
+
) {
|
|
92
|
+
const [state, created] = await this.findOrCreate({
|
|
93
|
+
where: { tokenType },
|
|
94
|
+
defaults: {
|
|
95
|
+
tokenType,
|
|
96
|
+
currentIndex: 0,
|
|
97
|
+
totalTokens: 10,
|
|
98
|
+
rotationStrategy: "round_robin",
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
return state;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
TokenRotationState.getStats = async function (
|
|
105
|
+
tokenType = "FACEBOOK_ACCESS_TOKEN"
|
|
106
|
+
) {
|
|
107
|
+
const state = await this.findOne({ where: { tokenType } });
|
|
108
|
+
if (!state) return null;
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
currentTokenNumber: state.getCurrentTokenNumber(),
|
|
112
|
+
totalTokens: state.totalTokens,
|
|
113
|
+
totalUsageCount: state.totalUsageCount.toString(),
|
|
114
|
+
lastUsedAt: state.lastUsedAt,
|
|
115
|
+
rotationStrategy: state.rotationStrategy,
|
|
116
|
+
metadata: state.metadata,
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return TokenRotationState;
|
|
121
|
+
};
|
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
module.exports = (sequelize, DataTypes) => {
|
|
2
|
-
const TonicRSOCKeywordPerformance = sequelize.define(
|
|
3
|
-
"TonicRSOCKeywordPerformance",
|
|
4
|
-
{
|
|
5
|
-
Date: {
|
|
6
|
-
type: DataTypes.DATEONLY,
|
|
7
|
-
primaryKey: true,
|
|
8
|
-
},
|
|
9
|
-
adID: {
|
|
10
|
-
type: DataTypes.STRING,
|
|
11
|
-
references: {
|
|
12
|
-
model: "Ad",
|
|
13
|
-
key: "AdID",
|
|
14
|
-
},
|
|
15
|
-
foreignKey: true,
|
|
16
|
-
primaryKey: true,
|
|
17
|
-
},
|
|
18
|
-
Keyword: {
|
|
19
|
-
type: DataTypes.STRING,
|
|
20
|
-
allowNull: false,
|
|
21
|
-
primaryKey: true,
|
|
22
|
-
},
|
|
23
|
-
Country: {
|
|
24
|
-
type: DataTypes.STRING,
|
|
25
|
-
allowNull: false,
|
|
26
|
-
primaryKey: true, // ✅ Country is now part of primary key
|
|
27
|
-
},
|
|
28
|
-
Revenue: {
|
|
29
|
-
type: DataTypes.FLOAT,
|
|
30
|
-
allowNull: false,
|
|
31
|
-
},
|
|
32
|
-
Clicks: {
|
|
33
|
-
type: DataTypes.INTEGER,
|
|
34
|
-
allowNull: false,
|
|
35
|
-
},
|
|
36
|
-
TemplatedKeyword: {
|
|
37
|
-
type: DataTypes.STRING,
|
|
38
|
-
allowNull: true,
|
|
39
|
-
},
|
|
40
|
-
FirstAppearanceDate: {
|
|
41
|
-
type: DataTypes.DATEONLY,
|
|
42
|
-
allowNull: true,
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
tableName: "TonicRSOCKeywordPerformance",
|
|
47
|
-
indexes: [
|
|
48
|
-
{
|
|
49
|
-
unique: true,
|
|
50
|
-
fields: ["Date", "adID", "Keyword", "Country"],
|
|
51
|
-
name: "tonic_primary_idx" // ✅ Custom short name
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
fields: ["Date"],
|
|
55
|
-
name: "tonic_date_idx"
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
fields: ["adID"],
|
|
59
|
-
name: "tonic_adid_idx"
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
fields: ["Keyword"],
|
|
63
|
-
name: "tonic_keyword_idx"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
fields: ["Country"],
|
|
67
|
-
name: "tonic_country_idx"
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
fields: ["Revenue"],
|
|
71
|
-
name: "tonic_revenue_idx"
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
fields: ["Clicks"],
|
|
75
|
-
name: "tonic_clicks_idx"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
fields: ["Country", "Date"],
|
|
79
|
-
name: "tonic_country_date_idx"
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
fields: ["Keyword", "Country"],
|
|
83
|
-
name: "tonic_keyword_country_idx"
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
fields: ["Date", "Revenue"],
|
|
87
|
-
name: "tonic_date_revenue_idx"
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
hooks: {
|
|
91
|
-
beforeCreate: async (record, options) => {
|
|
92
|
-
try {
|
|
93
|
-
const existingKeyword = await sequelize.models.TonicRSOCKeywordPerformance.findOne({
|
|
94
|
-
where: {
|
|
95
|
-
Keyword: sequelize.where(
|
|
96
|
-
sequelize.fn("LOWER", sequelize.col("Keyword")),
|
|
97
|
-
sequelize.fn("LOWER", record.Keyword)
|
|
98
|
-
),
|
|
99
|
-
Country: record.Country,
|
|
100
|
-
},
|
|
101
|
-
attributes: ["FirstAppearanceDate"],
|
|
102
|
-
transaction: options.transaction,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
record.FirstAppearanceDate =
|
|
106
|
-
existingKeyword?.FirstAppearanceDate || record.Date;
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error("Error in TonicRSOCKeywordPerformance FirstAppearanceDate hook:", error);
|
|
109
|
-
throw error;
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
}
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
TonicRSOCKeywordPerformance.associate = (models) => {
|
|
117
|
-
TonicRSOCKeywordPerformance.belongsTo(models.Ad, {
|
|
118
|
-
foreignKey: "adID",
|
|
119
|
-
});
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
return TonicRSOCKeywordPerformance;
|
|
1
|
+
module.exports = (sequelize, DataTypes) => {
|
|
2
|
+
const TonicRSOCKeywordPerformance = sequelize.define(
|
|
3
|
+
"TonicRSOCKeywordPerformance",
|
|
4
|
+
{
|
|
5
|
+
Date: {
|
|
6
|
+
type: DataTypes.DATEONLY,
|
|
7
|
+
primaryKey: true,
|
|
8
|
+
},
|
|
9
|
+
adID: {
|
|
10
|
+
type: DataTypes.STRING,
|
|
11
|
+
references: {
|
|
12
|
+
model: "Ad",
|
|
13
|
+
key: "AdID",
|
|
14
|
+
},
|
|
15
|
+
foreignKey: true,
|
|
16
|
+
primaryKey: true,
|
|
17
|
+
},
|
|
18
|
+
Keyword: {
|
|
19
|
+
type: DataTypes.STRING,
|
|
20
|
+
allowNull: false,
|
|
21
|
+
primaryKey: true,
|
|
22
|
+
},
|
|
23
|
+
Country: {
|
|
24
|
+
type: DataTypes.STRING,
|
|
25
|
+
allowNull: false,
|
|
26
|
+
primaryKey: true, // ✅ Country is now part of primary key
|
|
27
|
+
},
|
|
28
|
+
Revenue: {
|
|
29
|
+
type: DataTypes.FLOAT,
|
|
30
|
+
allowNull: false,
|
|
31
|
+
},
|
|
32
|
+
Clicks: {
|
|
33
|
+
type: DataTypes.INTEGER,
|
|
34
|
+
allowNull: false,
|
|
35
|
+
},
|
|
36
|
+
TemplatedKeyword: {
|
|
37
|
+
type: DataTypes.STRING,
|
|
38
|
+
allowNull: true,
|
|
39
|
+
},
|
|
40
|
+
FirstAppearanceDate: {
|
|
41
|
+
type: DataTypes.DATEONLY,
|
|
42
|
+
allowNull: true,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
tableName: "TonicRSOCKeywordPerformance",
|
|
47
|
+
indexes: [
|
|
48
|
+
{
|
|
49
|
+
unique: true,
|
|
50
|
+
fields: ["Date", "adID", "Keyword", "Country"],
|
|
51
|
+
name: "tonic_primary_idx" // ✅ Custom short name
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
fields: ["Date"],
|
|
55
|
+
name: "tonic_date_idx"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
fields: ["adID"],
|
|
59
|
+
name: "tonic_adid_idx"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
fields: ["Keyword"],
|
|
63
|
+
name: "tonic_keyword_idx"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
fields: ["Country"],
|
|
67
|
+
name: "tonic_country_idx"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
fields: ["Revenue"],
|
|
71
|
+
name: "tonic_revenue_idx"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
fields: ["Clicks"],
|
|
75
|
+
name: "tonic_clicks_idx"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
fields: ["Country", "Date"],
|
|
79
|
+
name: "tonic_country_date_idx"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
fields: ["Keyword", "Country"],
|
|
83
|
+
name: "tonic_keyword_country_idx"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
fields: ["Date", "Revenue"],
|
|
87
|
+
name: "tonic_date_revenue_idx"
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
hooks: {
|
|
91
|
+
beforeCreate: async (record, options) => {
|
|
92
|
+
try {
|
|
93
|
+
const existingKeyword = await sequelize.models.TonicRSOCKeywordPerformance.findOne({
|
|
94
|
+
where: {
|
|
95
|
+
Keyword: sequelize.where(
|
|
96
|
+
sequelize.fn("LOWER", sequelize.col("Keyword")),
|
|
97
|
+
sequelize.fn("LOWER", record.Keyword)
|
|
98
|
+
),
|
|
99
|
+
Country: record.Country,
|
|
100
|
+
},
|
|
101
|
+
attributes: ["FirstAppearanceDate"],
|
|
102
|
+
transaction: options.transaction,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
record.FirstAppearanceDate =
|
|
106
|
+
existingKeyword?.FirstAppearanceDate || record.Date;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("Error in TonicRSOCKeywordPerformance FirstAppearanceDate hook:", error);
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
TonicRSOCKeywordPerformance.associate = (models) => {
|
|
117
|
+
TonicRSOCKeywordPerformance.belongsTo(models.Ad, {
|
|
118
|
+
foreignKey: "adID",
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
return TonicRSOCKeywordPerformance;
|
|
123
123
|
};
|