agrs-sequelize-sdk 1.2.68 → 1.2.70
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 +89 -89
- package/models/AdSet.js +289 -289
- package/models/AdSetHistory.js +30 -30
- package/models/AdsetPerformance.js +126 -126
- package/models/Article.js +170 -170
- package/models/Buyers.js +25 -25
- package/models/Campaign.js +145 -145
- package/models/CampaignCreationLog.js +280 -280
- package/models/CampaignHistory.js +33 -33
- package/models/Channel.js +55 -55
- package/models/Domain.js +25 -25
- package/models/DynamicFeed.js +89 -89
- package/models/ExplorAdsChannel.js +61 -61
- package/models/Feed.js +33 -33
- package/models/FrontStoryChannel.js +59 -59
- package/models/Pages.js +73 -73
- 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/Rule.js +175 -36
- package/models/RuleAction.js +97 -0
- package/models/RuleCondition.js +99 -0
- package/models/RuleExecution.js +115 -0
- package/models/RulesValues.js +56 -56
- package/models/SupportedLocale.js +23 -23
- package/models/SyncHistory.js +249 -249
- 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,111 +1,111 @@
|
|
|
1
|
-
module.exports = (sequelize, DataTypes) => {
|
|
2
|
-
const RsocKeywordPerformance = sequelize.define('RsocKeywordPerformance', {
|
|
3
|
-
id: {
|
|
4
|
-
type: DataTypes.INTEGER,
|
|
5
|
-
primaryKey: true,
|
|
6
|
-
autoIncrement: true,
|
|
7
|
-
allowNull: false
|
|
8
|
-
},
|
|
9
|
-
ts: {
|
|
10
|
-
type: DataTypes.DATE,
|
|
11
|
-
allowNull: false,
|
|
12
|
-
comment: 'Timestamp of the record'
|
|
13
|
-
},
|
|
14
|
-
channel_id: {
|
|
15
|
-
type: DataTypes.STRING,
|
|
16
|
-
allowNull: false,
|
|
17
|
-
comment: 'Channel identifier'
|
|
18
|
-
},
|
|
19
|
-
style_id: {
|
|
20
|
-
type: DataTypes.STRING,
|
|
21
|
-
allowNull: true,
|
|
22
|
-
comment: 'Style identifier'
|
|
23
|
-
},
|
|
24
|
-
country_code: {
|
|
25
|
-
type: DataTypes.STRING(2),
|
|
26
|
-
allowNull: true,
|
|
27
|
-
comment: 'Country code (ISO 2-letter)'
|
|
28
|
-
},
|
|
29
|
-
custom_query: {
|
|
30
|
-
type: DataTypes.TEXT,
|
|
31
|
-
allowNull: true,
|
|
32
|
-
comment: 'Custom search query'
|
|
33
|
-
},
|
|
34
|
-
query: {
|
|
35
|
-
type: DataTypes.TEXT,
|
|
36
|
-
allowNull: true,
|
|
37
|
-
comment: 'Standard search query'
|
|
38
|
-
},
|
|
39
|
-
funnel_page_views: {
|
|
40
|
-
type: DataTypes.INTEGER,
|
|
41
|
-
allowNull: true,
|
|
42
|
-
defaultValue: 0,
|
|
43
|
-
comment: 'Number of funnel page views'
|
|
44
|
-
},
|
|
45
|
-
funnel_impressions: {
|
|
46
|
-
type: DataTypes.INTEGER,
|
|
47
|
-
allowNull: true,
|
|
48
|
-
defaultValue: 0,
|
|
49
|
-
comment: 'Number of funnel impressions'
|
|
50
|
-
},
|
|
51
|
-
funnel_clicks: {
|
|
52
|
-
type: DataTypes.INTEGER,
|
|
53
|
-
allowNull: true,
|
|
54
|
-
defaultValue: 0,
|
|
55
|
-
comment: 'Number of funnel clicks'
|
|
56
|
-
},
|
|
57
|
-
page_views: {
|
|
58
|
-
type: DataTypes.INTEGER,
|
|
59
|
-
allowNull: true,
|
|
60
|
-
defaultValue: 0,
|
|
61
|
-
comment: 'Number of page views'
|
|
62
|
-
},
|
|
63
|
-
impressions: {
|
|
64
|
-
type: DataTypes.INTEGER,
|
|
65
|
-
allowNull: true,
|
|
66
|
-
defaultValue: 0,
|
|
67
|
-
comment: 'Number of impressions'
|
|
68
|
-
},
|
|
69
|
-
clicks: {
|
|
70
|
-
type: DataTypes.INTEGER,
|
|
71
|
-
allowNull: true,
|
|
72
|
-
defaultValue: 0,
|
|
73
|
-
comment: 'Number of clicks'
|
|
74
|
-
},
|
|
75
|
-
agrs_cid: {
|
|
76
|
-
type: DataTypes.STRING,
|
|
77
|
-
allowNull: true,
|
|
78
|
-
comment: 'AGRS campaign identifier linking to campaign data'
|
|
79
|
-
}
|
|
80
|
-
}, {
|
|
81
|
-
tableName: 'rsoc_keyword_performance',
|
|
82
|
-
timestamps: true, // Adds createdAt and updatedAt columns
|
|
83
|
-
indexes: [
|
|
84
|
-
{
|
|
85
|
-
fields: ['channel_id', 'ts'],
|
|
86
|
-
name: 'idx_rsoc_keyword_channel_time'
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
fields: ['style_id'],
|
|
90
|
-
name: 'idx_rsoc_keyword_style'
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
fields: ['country_code'],
|
|
94
|
-
name: 'idx_rsoc_keyword_country'
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
fields: ['agrs_cid'],
|
|
98
|
-
name: 'idx_rsoc_keyword_agrs_cid'
|
|
99
|
-
}
|
|
100
|
-
]
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// Define associations if needed
|
|
104
|
-
RsocKeywordPerformance.associate = (models) => {
|
|
105
|
-
// Add associations here if your table needs to reference other tables
|
|
106
|
-
// For example:
|
|
107
|
-
// RsocKeywordPerformance.belongsTo(models.Channel, { foreignKey: 'channel_id' });
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
return RsocKeywordPerformance;
|
|
1
|
+
module.exports = (sequelize, DataTypes) => {
|
|
2
|
+
const RsocKeywordPerformance = sequelize.define('RsocKeywordPerformance', {
|
|
3
|
+
id: {
|
|
4
|
+
type: DataTypes.INTEGER,
|
|
5
|
+
primaryKey: true,
|
|
6
|
+
autoIncrement: true,
|
|
7
|
+
allowNull: false
|
|
8
|
+
},
|
|
9
|
+
ts: {
|
|
10
|
+
type: DataTypes.DATE,
|
|
11
|
+
allowNull: false,
|
|
12
|
+
comment: 'Timestamp of the record'
|
|
13
|
+
},
|
|
14
|
+
channel_id: {
|
|
15
|
+
type: DataTypes.STRING,
|
|
16
|
+
allowNull: false,
|
|
17
|
+
comment: 'Channel identifier'
|
|
18
|
+
},
|
|
19
|
+
style_id: {
|
|
20
|
+
type: DataTypes.STRING,
|
|
21
|
+
allowNull: true,
|
|
22
|
+
comment: 'Style identifier'
|
|
23
|
+
},
|
|
24
|
+
country_code: {
|
|
25
|
+
type: DataTypes.STRING(2),
|
|
26
|
+
allowNull: true,
|
|
27
|
+
comment: 'Country code (ISO 2-letter)'
|
|
28
|
+
},
|
|
29
|
+
custom_query: {
|
|
30
|
+
type: DataTypes.TEXT,
|
|
31
|
+
allowNull: true,
|
|
32
|
+
comment: 'Custom search query'
|
|
33
|
+
},
|
|
34
|
+
query: {
|
|
35
|
+
type: DataTypes.TEXT,
|
|
36
|
+
allowNull: true,
|
|
37
|
+
comment: 'Standard search query'
|
|
38
|
+
},
|
|
39
|
+
funnel_page_views: {
|
|
40
|
+
type: DataTypes.INTEGER,
|
|
41
|
+
allowNull: true,
|
|
42
|
+
defaultValue: 0,
|
|
43
|
+
comment: 'Number of funnel page views'
|
|
44
|
+
},
|
|
45
|
+
funnel_impressions: {
|
|
46
|
+
type: DataTypes.INTEGER,
|
|
47
|
+
allowNull: true,
|
|
48
|
+
defaultValue: 0,
|
|
49
|
+
comment: 'Number of funnel impressions'
|
|
50
|
+
},
|
|
51
|
+
funnel_clicks: {
|
|
52
|
+
type: DataTypes.INTEGER,
|
|
53
|
+
allowNull: true,
|
|
54
|
+
defaultValue: 0,
|
|
55
|
+
comment: 'Number of funnel clicks'
|
|
56
|
+
},
|
|
57
|
+
page_views: {
|
|
58
|
+
type: DataTypes.INTEGER,
|
|
59
|
+
allowNull: true,
|
|
60
|
+
defaultValue: 0,
|
|
61
|
+
comment: 'Number of page views'
|
|
62
|
+
},
|
|
63
|
+
impressions: {
|
|
64
|
+
type: DataTypes.INTEGER,
|
|
65
|
+
allowNull: true,
|
|
66
|
+
defaultValue: 0,
|
|
67
|
+
comment: 'Number of impressions'
|
|
68
|
+
},
|
|
69
|
+
clicks: {
|
|
70
|
+
type: DataTypes.INTEGER,
|
|
71
|
+
allowNull: true,
|
|
72
|
+
defaultValue: 0,
|
|
73
|
+
comment: 'Number of clicks'
|
|
74
|
+
},
|
|
75
|
+
agrs_cid: {
|
|
76
|
+
type: DataTypes.STRING,
|
|
77
|
+
allowNull: true,
|
|
78
|
+
comment: 'AGRS campaign identifier linking to campaign data'
|
|
79
|
+
}
|
|
80
|
+
}, {
|
|
81
|
+
tableName: 'rsoc_keyword_performance',
|
|
82
|
+
timestamps: true, // Adds createdAt and updatedAt columns
|
|
83
|
+
indexes: [
|
|
84
|
+
{
|
|
85
|
+
fields: ['channel_id', 'ts'],
|
|
86
|
+
name: 'idx_rsoc_keyword_channel_time'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
fields: ['style_id'],
|
|
90
|
+
name: 'idx_rsoc_keyword_style'
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
fields: ['country_code'],
|
|
94
|
+
name: 'idx_rsoc_keyword_country'
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
fields: ['agrs_cid'],
|
|
98
|
+
name: 'idx_rsoc_keyword_agrs_cid'
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Define associations if needed
|
|
104
|
+
RsocKeywordPerformance.associate = (models) => {
|
|
105
|
+
// Add associations here if your table needs to reference other tables
|
|
106
|
+
// For example:
|
|
107
|
+
// RsocKeywordPerformance.belongsTo(models.Channel, { foreignKey: 'channel_id' });
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return RsocKeywordPerformance;
|
|
111
111
|
};
|
package/models/Rule.js
CHANGED
|
@@ -1,39 +1,178 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
const { DataTypes } = require("sequelize");
|
|
2
|
+
|
|
3
|
+
module.exports = (sequelize) => {
|
|
4
|
+
const Rule = sequelize.define(
|
|
5
|
+
"Rule",
|
|
6
|
+
{
|
|
7
|
+
id: {
|
|
8
|
+
type: DataTypes.UUID,
|
|
9
|
+
defaultValue: DataTypes.UUIDV4,
|
|
10
|
+
primaryKey: true,
|
|
11
|
+
},
|
|
12
|
+
name: {
|
|
13
|
+
type: DataTypes.STRING,
|
|
14
|
+
allowNull: false,
|
|
15
|
+
comment: "Rule name for identification",
|
|
16
|
+
},
|
|
17
|
+
code: {
|
|
18
|
+
type: DataTypes.STRING,
|
|
19
|
+
allowNull: false,
|
|
20
|
+
unique: true,
|
|
21
|
+
comment: "Unique code for the rule",
|
|
22
|
+
},
|
|
23
|
+
permissions: {
|
|
24
|
+
type: DataTypes.ARRAY(DataTypes.STRING),
|
|
25
|
+
allowNull: false,
|
|
26
|
+
defaultValue: [],
|
|
27
|
+
comment: "Permissions required for this rule",
|
|
28
|
+
},
|
|
29
|
+
feature: {
|
|
30
|
+
type: DataTypes.STRING,
|
|
31
|
+
allowNull: true,
|
|
32
|
+
comment: "Feature this rule belongs to",
|
|
33
|
+
},
|
|
34
|
+
parentId: {
|
|
35
|
+
type: DataTypes.UUID,
|
|
36
|
+
allowNull: true,
|
|
37
|
+
references: {
|
|
38
|
+
model: "Rules",
|
|
39
|
+
key: "id",
|
|
40
|
+
},
|
|
41
|
+
onDelete: "CASCADE",
|
|
42
|
+
comment: "Parent rule ID for hierarchical rules",
|
|
43
|
+
},
|
|
44
|
+
// Additional fields for the new rules system
|
|
45
|
+
description: {
|
|
46
|
+
type: DataTypes.TEXT,
|
|
47
|
+
allowNull: true,
|
|
48
|
+
comment: "Optional description of what this rule does",
|
|
49
|
+
},
|
|
50
|
+
isActive: {
|
|
51
|
+
type: DataTypes.BOOLEAN,
|
|
52
|
+
defaultValue: true,
|
|
53
|
+
allowNull: false,
|
|
54
|
+
comment: "Whether the rule is currently active",
|
|
55
|
+
},
|
|
56
|
+
ruleType: {
|
|
57
|
+
type: DataTypes.ENUM("PAUSE", "BUDGET", "BID", "STATUS", "CUSTOM"),
|
|
58
|
+
allowNull: true,
|
|
59
|
+
comment: "Type of rule - determines the action category",
|
|
60
|
+
},
|
|
61
|
+
targetLevel: {
|
|
62
|
+
type: DataTypes.ENUM("CAMPAIGN", "ADSET", "AD"),
|
|
63
|
+
allowNull: true,
|
|
64
|
+
comment: "Level at which the rule operates",
|
|
65
|
+
},
|
|
66
|
+
scheduleType: {
|
|
67
|
+
type: DataTypes.ENUM("INTERVAL", "CRON", "MANUAL"),
|
|
68
|
+
allowNull: true,
|
|
69
|
+
defaultValue: "MANUAL",
|
|
70
|
+
comment: "How the rule is triggered",
|
|
71
|
+
},
|
|
72
|
+
scheduleConfig: {
|
|
73
|
+
type: DataTypes.JSONB,
|
|
74
|
+
allowNull: true,
|
|
75
|
+
comment:
|
|
76
|
+
"Schedule configuration (interval minutes, cron expression, etc.)",
|
|
77
|
+
},
|
|
78
|
+
gcpJobName: {
|
|
79
|
+
type: DataTypes.STRING(255),
|
|
80
|
+
allowNull: true,
|
|
81
|
+
comment: "GCP Cloud Scheduler job name for this rule",
|
|
82
|
+
},
|
|
83
|
+
lastExecuted: {
|
|
84
|
+
type: DataTypes.DATE,
|
|
85
|
+
allowNull: true,
|
|
86
|
+
comment: "When the rule was last executed",
|
|
87
|
+
},
|
|
88
|
+
nextExecution: {
|
|
89
|
+
type: DataTypes.DATE,
|
|
90
|
+
allowNull: true,
|
|
91
|
+
comment: "When the rule is scheduled to run next",
|
|
92
|
+
},
|
|
93
|
+
executionCount: {
|
|
94
|
+
type: DataTypes.INTEGER,
|
|
95
|
+
defaultValue: 0,
|
|
96
|
+
allowNull: false,
|
|
97
|
+
comment: "Number of times this rule has been executed",
|
|
98
|
+
},
|
|
99
|
+
successCount: {
|
|
100
|
+
type: DataTypes.INTEGER,
|
|
101
|
+
defaultValue: 0,
|
|
102
|
+
allowNull: false,
|
|
103
|
+
comment: "Number of successful executions",
|
|
104
|
+
},
|
|
105
|
+
failureCount: {
|
|
106
|
+
type: DataTypes.INTEGER,
|
|
107
|
+
defaultValue: 0,
|
|
108
|
+
allowNull: false,
|
|
109
|
+
comment: "Number of failed executions",
|
|
110
|
+
},
|
|
111
|
+
createdBy: {
|
|
112
|
+
type: DataTypes.STRING(255),
|
|
113
|
+
allowNull: true,
|
|
114
|
+
comment: "User who created this rule",
|
|
115
|
+
},
|
|
116
|
+
updatedBy: {
|
|
117
|
+
type: DataTypes.STRING(255),
|
|
118
|
+
allowNull: true,
|
|
119
|
+
comment: "User who last updated this rule",
|
|
120
|
+
},
|
|
35
121
|
},
|
|
36
|
-
|
|
122
|
+
{
|
|
123
|
+
tableName: "RulesValues", // Use the existing table name
|
|
124
|
+
timestamps: true,
|
|
125
|
+
indexes: [
|
|
126
|
+
{
|
|
127
|
+
fields: ["code"],
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
fields: ["feature"],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
fields: ["parentId"],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
fields: ["isActive"],
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
fields: ["ruleType"],
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
fields: ["targetLevel"],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
fields: ["scheduleType"],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
fields: ["nextExecution"],
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
Rule.associate = (models) => {
|
|
155
|
+
// A rule has many conditions
|
|
156
|
+
Rule.hasMany(models.RuleCondition, {
|
|
157
|
+
foreignKey: "ruleId",
|
|
158
|
+
as: "conditions",
|
|
159
|
+
onDelete: "CASCADE",
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// A rule has many actions
|
|
163
|
+
Rule.hasMany(models.RuleAction, {
|
|
164
|
+
foreignKey: "ruleId",
|
|
165
|
+
as: "actions",
|
|
166
|
+
onDelete: "CASCADE",
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// A rule has many execution logs
|
|
170
|
+
Rule.hasMany(models.RuleExecution, {
|
|
171
|
+
foreignKey: "ruleId",
|
|
172
|
+
as: "executions",
|
|
173
|
+
onDelete: "CASCADE",
|
|
174
|
+
});
|
|
175
|
+
};
|
|
37
176
|
|
|
38
177
|
return Rule;
|
|
39
|
-
};
|
|
178
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const { DataTypes } = require("sequelize");
|
|
2
|
+
|
|
3
|
+
module.exports = (sequelize) => {
|
|
4
|
+
const RuleAction = sequelize.define(
|
|
5
|
+
"RuleAction",
|
|
6
|
+
{
|
|
7
|
+
id: {
|
|
8
|
+
type: DataTypes.UUID,
|
|
9
|
+
defaultValue: DataTypes.UUIDV4,
|
|
10
|
+
primaryKey: true,
|
|
11
|
+
},
|
|
12
|
+
ruleId: {
|
|
13
|
+
type: DataTypes.UUID,
|
|
14
|
+
allowNull: false,
|
|
15
|
+
references: {
|
|
16
|
+
model: "RulesValues",
|
|
17
|
+
key: "id",
|
|
18
|
+
},
|
|
19
|
+
comment: "Reference to the parent rule",
|
|
20
|
+
},
|
|
21
|
+
actionType: {
|
|
22
|
+
type: DataTypes.ENUM(
|
|
23
|
+
// Campaign level actions
|
|
24
|
+
"PAUSE_CAMPAIGN",
|
|
25
|
+
"ACTIVATE_CAMPAIGN",
|
|
26
|
+
"CHANGE_CAMPAIGN_BUDGET",
|
|
27
|
+
"CHANGE_CAMPAIGN_BID_STRATEGY",
|
|
28
|
+
|
|
29
|
+
// AdSet level actions
|
|
30
|
+
"PAUSE_ADSET",
|
|
31
|
+
"ACTIVATE_ADSET",
|
|
32
|
+
"CHANGE_ADSET_BUDGET",
|
|
33
|
+
"CHANGE_ADSET_BID",
|
|
34
|
+
"CHANGE_ADSET_BID_STRATEGY",
|
|
35
|
+
|
|
36
|
+
// Ad level actions
|
|
37
|
+
"PAUSE_AD",
|
|
38
|
+
"ACTIVATE_AD",
|
|
39
|
+
|
|
40
|
+
// Custom actions
|
|
41
|
+
"CUSTOM_ACTION"
|
|
42
|
+
),
|
|
43
|
+
allowNull: false,
|
|
44
|
+
comment: "Type of action to perform",
|
|
45
|
+
},
|
|
46
|
+
actionConfig: {
|
|
47
|
+
type: DataTypes.JSONB,
|
|
48
|
+
allowNull: true,
|
|
49
|
+
comment:
|
|
50
|
+
"Configuration for the action (budget amount, bid strategy, etc.)",
|
|
51
|
+
},
|
|
52
|
+
order: {
|
|
53
|
+
type: DataTypes.INTEGER,
|
|
54
|
+
allowNull: false,
|
|
55
|
+
defaultValue: 0,
|
|
56
|
+
comment: "Order of this action within the rule",
|
|
57
|
+
},
|
|
58
|
+
isActive: {
|
|
59
|
+
type: DataTypes.BOOLEAN,
|
|
60
|
+
defaultValue: true,
|
|
61
|
+
allowNull: false,
|
|
62
|
+
comment: "Whether this action is active",
|
|
63
|
+
},
|
|
64
|
+
delayMinutes: {
|
|
65
|
+
type: DataTypes.INTEGER,
|
|
66
|
+
allowNull: true,
|
|
67
|
+
defaultValue: 0,
|
|
68
|
+
comment: "Delay in minutes before executing this action",
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
tableName: "RuleActions",
|
|
73
|
+
timestamps: true,
|
|
74
|
+
indexes: [
|
|
75
|
+
{
|
|
76
|
+
fields: ["ruleId"],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
fields: ["actionType"],
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
fields: ["order"],
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
RuleAction.associate = (models) => {
|
|
89
|
+
// An action belongs to a rule
|
|
90
|
+
RuleAction.belongsTo(models.Rule, {
|
|
91
|
+
foreignKey: "ruleId",
|
|
92
|
+
as: "rule",
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return RuleAction;
|
|
97
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const { DataTypes } = require("sequelize");
|
|
2
|
+
|
|
3
|
+
module.exports = (sequelize) => {
|
|
4
|
+
const RuleCondition = sequelize.define(
|
|
5
|
+
"RuleCondition",
|
|
6
|
+
{
|
|
7
|
+
id: {
|
|
8
|
+
type: DataTypes.UUID,
|
|
9
|
+
defaultValue: DataTypes.UUIDV4,
|
|
10
|
+
primaryKey: true,
|
|
11
|
+
},
|
|
12
|
+
ruleId: {
|
|
13
|
+
type: DataTypes.UUID,
|
|
14
|
+
allowNull: false,
|
|
15
|
+
references: {
|
|
16
|
+
model: "RulesValues",
|
|
17
|
+
key: "id",
|
|
18
|
+
},
|
|
19
|
+
comment: "Reference to the parent rule",
|
|
20
|
+
},
|
|
21
|
+
field: {
|
|
22
|
+
type: DataTypes.STRING(100),
|
|
23
|
+
allowNull: false,
|
|
24
|
+
comment: "Field to evaluate (e.g., roi, ctr, campaign_name)",
|
|
25
|
+
},
|
|
26
|
+
operator: {
|
|
27
|
+
type: DataTypes.ENUM(
|
|
28
|
+
"EQUALS",
|
|
29
|
+
"NOT_EQUALS",
|
|
30
|
+
"GREATER_THAN",
|
|
31
|
+
"LESS_THAN",
|
|
32
|
+
"GREATER_THAN_OR_EQUAL",
|
|
33
|
+
"LESS_THAN_OR_EQUAL",
|
|
34
|
+
"BETWEEN",
|
|
35
|
+
"IN",
|
|
36
|
+
"NOT_IN",
|
|
37
|
+
"CONTAINS",
|
|
38
|
+
"NOT_CONTAINS",
|
|
39
|
+
"IS_NULL",
|
|
40
|
+
"IS_NOT_NULL"
|
|
41
|
+
),
|
|
42
|
+
allowNull: false,
|
|
43
|
+
comment: "Comparison operator",
|
|
44
|
+
},
|
|
45
|
+
value: {
|
|
46
|
+
type: DataTypes.JSONB,
|
|
47
|
+
allowNull: true,
|
|
48
|
+
comment:
|
|
49
|
+
"Value(s) to compare against (can be array for BETWEEN, IN, etc.)",
|
|
50
|
+
},
|
|
51
|
+
logicalOperator: {
|
|
52
|
+
type: DataTypes.ENUM("AND", "OR"),
|
|
53
|
+
allowNull: false,
|
|
54
|
+
defaultValue: "AND",
|
|
55
|
+
comment: "How this condition connects to the next one",
|
|
56
|
+
},
|
|
57
|
+
order: {
|
|
58
|
+
type: DataTypes.INTEGER,
|
|
59
|
+
allowNull: false,
|
|
60
|
+
defaultValue: 0,
|
|
61
|
+
comment: "Order of this condition within the rule",
|
|
62
|
+
},
|
|
63
|
+
isActive: {
|
|
64
|
+
type: DataTypes.BOOLEAN,
|
|
65
|
+
defaultValue: true,
|
|
66
|
+
allowNull: false,
|
|
67
|
+
comment: "Whether this condition is active",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
tableName: "RuleConditions",
|
|
72
|
+
timestamps: true,
|
|
73
|
+
indexes: [
|
|
74
|
+
{
|
|
75
|
+
fields: ["ruleId"],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
fields: ["field"],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
fields: ["operator"],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
fields: ["order"],
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
RuleCondition.associate = (models) => {
|
|
91
|
+
// A condition belongs to a rule
|
|
92
|
+
RuleCondition.belongsTo(models.Rule, {
|
|
93
|
+
foreignKey: "ruleId",
|
|
94
|
+
as: "rule",
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return RuleCondition;
|
|
99
|
+
};
|