agrs-sequelize-sdk 1.1.56 → 1.1.58

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/models/Channel.js CHANGED
@@ -1,230 +1,55 @@
1
1
  module.exports = (sequelize, DataTypes) => {
2
- const RSOCFeedCampaign = sequelize.define(
3
- "RSOCFeedCampaign",
2
+ const Channel = sequelize.define(
3
+ "Channel",
4
4
  {
5
- AGRS_CID: {
6
- type: DataTypes.STRING,
7
- allowNull: false,
8
- unique: true,
9
- primaryKey: true,
10
- },
11
- AGRSAID: {
12
- type: DataTypes.STRING,
13
- allowNull: false,
14
- comment: "Foreign key referencing Article.AGRSAID",
15
- },
16
- articleName: {
17
- type: DataTypes.STRING,
18
- allowNull: false,
19
- comment: "Name of the associated article",
20
- },
21
5
  channelId: {
22
6
  type: DataTypes.STRING,
23
7
  allowNull: false,
24
- comment: "Foreign key referencing Channel.channelId",
8
+ // Not setting as primary key or unique since duplicates are allowed
25
9
  },
26
10
  styleId: {
27
- type: DataTypes.STRING,
28
- allowNull: true,
29
- comment: "Style ID (stid) inherited from Channel",
30
- },
31
- assignee: {
32
11
  type: DataTypes.STRING,
33
12
  allowNull: false,
34
13
  },
35
14
  status: {
36
15
  type: DataTypes.STRING,
37
16
  allowNull: false,
38
- defaultValue: "active",
17
+ defaultValue: "free",
39
18
  validate: {
40
- isIn: [["active", "inactive", "archived"]],
19
+ isIn: [["free", "used", "archived"]],
41
20
  },
42
21
  },
43
- country: {
44
- type: DataTypes.STRING,
45
- allowNull: false,
46
- },
47
- vertical: {
48
- type: DataTypes.STRING,
49
- allowNull: false,
50
- comment: "Maps to Article.category for dynamic selection",
51
- },
52
- freeText: {
53
- type: DataTypes.TEXT,
54
- allowNull: true,
55
- },
56
- campaignName: {
57
- type: DataTypes.STRING,
58
- allowNull: false,
59
- },
60
- campaignId: {
61
- type: DataTypes.STRING,
62
- allowNull: true,
63
- },
64
- keywords: {
65
- type: DataTypes.ARRAY(DataTypes.STRING),
66
- allowNull: true,
67
- },
68
- link: {
69
- type: DataTypes.STRING(1024),
70
- allowNull: true,
71
- comment: "Campaign-specific URL based on article URL with parameters",
72
- },
73
- redirectLink: {
74
- type: DataTypes.STRING(1024),
75
- allowNull: true,
76
- },
77
- pixelId: {
78
- type: DataTypes.STRING(1024),
79
- allowNull: true,
80
- },
81
- token: {
82
- type: DataTypes.STRING(1024),
83
- allowNull: true,
84
- },
85
- accountId: {
86
- type: DataTypes.STRING,
87
- allowNull: false,
88
- },
89
- feedName: {
90
- type: DataTypes.STRING,
91
- allowNull: true,
92
- defaultValue: "RSOC",
93
- },
94
- adTitle: {
95
- type: DataTypes.STRING,
96
- allowNull: true,
97
- },
98
- domain: {
99
- type: DataTypes.STRING,
100
- allowNull: true,
101
- },
102
- feedProvider: {
103
- type: DataTypes.STRING,
104
- allowNull: false,
105
- defaultValue: "RSOC",
106
- },
107
- createdCampaignAt: {
108
- type: DataTypes.DATE,
109
- allowNull: true,
110
- defaultValue: DataTypes.NOW,
111
- },
112
- draft: {
113
- type: DataTypes.BOOLEAN,
114
- allowNull: true,
115
- defaultValue: false,
116
- },
117
- createdAt: {
118
- type: DataTypes.DATE,
119
- defaultValue: DataTypes.NOW,
120
- },
121
- updatedAt: {
122
- type: DataTypes.DATE,
123
- defaultValue: DataTypes.NOW,
124
- },
125
- platform: {
126
- type: DataTypes.STRING,
22
+ connectedCampaigns: {
23
+ type: DataTypes.JSONB, // Use JSONB for better querying capabilities
127
24
  allowNull: false,
128
- },
129
- mediaBuyer: {
130
- type: DataTypes.STRING,
131
- allowNull: true,
25
+ defaultValue: [],
132
26
  },
133
27
  },
134
28
  {
135
- tableName: "rsoc_feed_campaigns",
29
+ tableName: "channels",
136
30
  timestamps: true,
31
+ indexes: [
32
+ // Add a composite unique index on channelId and styleId if needed
33
+ {
34
+ unique: true,
35
+ fields: ["channelId", "styleId"],
36
+ name: "unique_channel_style",
37
+ },
38
+ ],
137
39
  }
138
40
  );
139
41
 
140
- RSOCFeedCampaign.associate = (models) => {
141
- RSOCFeedCampaign.belongsTo(models.Article, {
142
- foreignKey: "AGRSAID",
143
- targetKey: "AGRSAID",
144
- as: "Article",
145
- constraints: false, // Disable foreign key constraint
146
- });
147
-
148
- RSOCFeedCampaign.belongsTo(models.Channel, {
149
- foreignKey: "channelId",
150
- targetKey: "channelId",
151
- as: "Channel",
152
- constraints: false, // Disable foreign key constraint
153
- });
154
- };
155
-
156
- RSOCFeedCampaign.beforeCreate(async (campaign) => {
157
- // Set redirectLink to null as requested
158
- campaign.setDataValue("redirectLink", null);
159
-
160
- const channel = await sequelize.models.Channel.findOne({
161
- where: { channelId: campaign.channelId, styleId: campaign.styleId },
162
- });
163
-
164
- if (channel) {
165
- const connectedCampaigns = channel.connectedCampaigns || [];
166
- if (!connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)) {
167
- connectedCampaigns.push({
168
- campaignId: campaign.AGRS_CID,
169
- assignedAt: new Date(),
170
- releasedAt: null,
171
- });
172
- await channel.update({ status: "used", connectedCampaigns });
173
- }
174
- }
175
- });
176
-
177
- RSOCFeedCampaign.beforeUpdate(async (campaign) => {
178
- // Ensure redirectLink remains null
179
- campaign.setDataValue("redirectLink", null);
180
-
181
- if (campaign.changed("channelId") || campaign.changed("styleId")) {
182
- const oldChannelId = campaign.previous("channelId");
183
- const oldStyleId = campaign.previous("styleId");
184
- const newChannelId = campaign.channelId;
185
- const newStyleId = campaign.styleId;
186
-
187
- if (oldChannelId) {
188
- const oldChannel = await sequelize.models.Channel.findOne({
189
- where: { channelId: oldChannelId, styleId: oldStyleId },
190
- });
191
-
192
- if (oldChannel) {
193
- const connectedCampaigns = oldChannel.connectedCampaigns || [];
194
- const updatedCampaigns = connectedCampaigns
195
- .map((c) =>
196
- c.campaignId === campaign.AGRS_CID
197
- ? { ...c, releasedAt: new Date() }
198
- : c
199
- )
200
- .filter((c) => c.releasedAt === null);
201
-
202
- await oldChannel.update({
203
- connectedCampaigns: updatedCampaigns,
204
- status: updatedCampaigns.length > 0 ? "used" : "free",
205
- });
206
- }
207
- }
208
-
209
- const newChannel = await sequelize.models.Channel.findOne({
210
- where: { channelId: newChannelId, styleId: newStyleId },
42
+ // Define associations without enforcing constraints
43
+ Channel.associate = (models) => {
44
+ if (models.RSOCFeedCampaign) {
45
+ Channel.hasMany(models.RSOCFeedCampaign, {
46
+ foreignKey: "channelId",
47
+ sourceKey: "channelId",
48
+ as: "RSOCFeedCampaigns",
49
+ constraints: false, // Disable FK constraint
211
50
  });
212
-
213
- if (newChannel) {
214
- const connectedCampaigns = newChannel.connectedCampaigns || [];
215
- if (
216
- !connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)
217
- ) {
218
- connectedCampaigns.push({
219
- campaignId: campaign.AGRS_CID,
220
- assignedAt: new Date(),
221
- releasedAt: null,
222
- });
223
- await newChannel.update({ status: "used", connectedCampaigns });
224
- }
225
- }
226
51
  }
227
- });
52
+ };
228
53
 
229
- return RSOCFeedCampaign;
54
+ return Channel;
230
55
  };
@@ -116,10 +116,12 @@ module.exports = (sequelize, DataTypes) => {
116
116
  },
117
117
  createdAt: {
118
118
  type: DataTypes.DATE,
119
+ allowNull: false,
119
120
  defaultValue: DataTypes.NOW,
120
121
  },
121
122
  updatedAt: {
122
123
  type: DataTypes.DATE,
124
+ allowNull: false,
123
125
  defaultValue: DataTypes.NOW,
124
126
  },
125
127
  platform: {
@@ -134,158 +136,156 @@ module.exports = (sequelize, DataTypes) => {
134
136
  {
135
137
  tableName: "rsoc_feed_campaigns",
136
138
  timestamps: true,
137
- // Entirely disable automatic foreign key creation
138
- references: false,
139
139
  }
140
140
  );
141
141
 
142
- // Override the standard associate method to use non-constraint associations
143
- RSOCFeedCampaign.associate = function (models) {
144
- // Define associations without foreign key constraints
145
- const queryOptions = { constraints: false };
146
-
147
- // Associate with Article model
142
+ // Define associations without enforcing foreign key constraints
143
+ RSOCFeedCampaign.associate = (models) => {
148
144
  if (models.Article) {
149
145
  RSOCFeedCampaign.belongsTo(models.Article, {
150
146
  foreignKey: "AGRSAID",
151
147
  targetKey: "AGRSAID",
152
148
  as: "Article",
153
- ...queryOptions,
149
+ constraints: false,
154
150
  });
155
151
  }
156
152
 
157
- // Associate with Channel model
158
153
  if (models.Channel) {
159
154
  RSOCFeedCampaign.belongsTo(models.Channel, {
160
155
  foreignKey: "channelId",
161
156
  targetKey: "channelId",
162
157
  as: "Channel",
163
- ...queryOptions,
158
+ constraints: false,
164
159
  });
165
160
  }
166
161
  };
167
162
 
163
+ // BeforeCreate hook: Update Channel status and connectedCampaigns
168
164
  RSOCFeedCampaign.beforeCreate(async (campaign, options) => {
169
- // Set redirectLink to null as requested
170
165
  campaign.setDataValue("redirectLink", null);
171
166
 
172
- // Only update the channel if not in the middle of a sync operation
173
- if (!options.silent) {
174
- try {
175
- const channel = await sequelize.models.Channel.findOne({
176
- where: {
177
- channelId: campaign.channelId,
178
- styleId: campaign.styleId,
179
- },
180
- });
167
+ // Skip channel update if in a silent operation (e.g., during sync)
168
+ if (options.silent) return;
169
+
170
+ try {
171
+ const channel = await sequelize.models.Channel.findOne({
172
+ where: {
173
+ channelId: campaign.channelId,
174
+ styleId: campaign.styleId || null,
175
+ },
176
+ });
181
177
 
182
- if (channel) {
183
- const connectedCampaigns = channel.connectedCampaigns || [];
184
- if (
185
- !connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)
186
- ) {
187
- connectedCampaigns.push({
188
- campaignId: campaign.AGRS_CID,
189
- assignedAt: new Date(),
190
- releasedAt: null,
191
- });
192
- await channel.update(
193
- {
194
- status: "used",
195
- connectedCampaigns,
196
- },
197
- { silent: true }
198
- );
199
- }
178
+ if (channel) {
179
+ const connectedCampaigns = channel.connectedCampaigns || [];
180
+ if (
181
+ !connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)
182
+ ) {
183
+ connectedCampaigns.push({
184
+ campaignId: campaign.AGRS_CID,
185
+ assignedAt: new Date(),
186
+ releasedAt: null,
187
+ });
188
+ await channel.update(
189
+ {
190
+ status: "used",
191
+ connectedCampaigns,
192
+ },
193
+ { silent: true }
194
+ );
200
195
  }
201
- } catch (error) {
202
- console.error(
203
- "Error updating channel in beforeCreate hook:",
204
- error.message
196
+ } else {
197
+ console.warn(
198
+ `Channel not found for channelId: ${campaign.channelId}, styleId: ${campaign.styleId}`
205
199
  );
206
- // Continue with campaign creation even if channel update fails
207
200
  }
201
+ } catch (error) {
202
+ console.error("Error in beforeCreate hook:", error.message);
208
203
  }
209
204
  });
210
205
 
206
+ // BeforeUpdate hook: Handle channel reassignment
211
207
  RSOCFeedCampaign.beforeUpdate(async (campaign, options) => {
212
- // Ensure redirectLink remains null
213
208
  campaign.setDataValue("redirectLink", null);
214
209
 
215
- // Only update the channels if not in the middle of a sync operation
210
+ // Skip channel update if in a silent operation or no relevant changes
216
211
  if (
217
- !options.silent &&
218
- (campaign.changed("channelId") || campaign.changed("styleId"))
212
+ options.silent ||
213
+ (!campaign.changed("channelId") && !campaign.changed("styleId"))
219
214
  ) {
220
- try {
221
- const oldChannelId = campaign.previous("channelId");
222
- const oldStyleId = campaign.previous("styleId");
223
- const newChannelId = campaign.channelId;
224
- const newStyleId = campaign.styleId;
225
-
226
- // Update old channel if exists
227
- if (oldChannelId) {
228
- const oldChannel = await sequelize.models.Channel.findOne({
229
- where: {
230
- channelId: oldChannelId,
231
- styleId: oldStyleId,
232
- },
233
- });
234
-
235
- if (oldChannel) {
236
- const connectedCampaigns = oldChannel.connectedCampaigns || [];
237
- const updatedCampaigns = connectedCampaigns
238
- .map((c) =>
239
- c.campaignId === campaign.AGRS_CID
240
- ? { ...c, releasedAt: new Date() }
241
- : c
242
- )
243
- .filter((c) => c.releasedAt === null);
215
+ return;
216
+ }
244
217
 
245
- await oldChannel.update(
246
- {
247
- connectedCampaigns: updatedCampaigns,
248
- status: updatedCampaigns.length > 0 ? "used" : "free",
249
- },
250
- { silent: true }
251
- );
252
- }
253
- }
218
+ try {
219
+ const oldChannelId = campaign.previous("channelId");
220
+ const oldStyleId = campaign.previous("styleId") || null;
221
+ const newChannelId = campaign.channelId;
222
+ const newStyleId = campaign.styleId || null;
254
223
 
255
- // Update new channel if exists
256
- const newChannel = await sequelize.models.Channel.findOne({
224
+ // Release old channel
225
+ if (
226
+ oldChannelId &&
227
+ (oldChannelId !== newChannelId || oldStyleId !== newStyleId)
228
+ ) {
229
+ const oldChannel = await sequelize.models.Channel.findOne({
257
230
  where: {
258
- channelId: newChannelId,
259
- styleId: newStyleId,
231
+ channelId: oldChannelId,
232
+ styleId: oldStyleId,
260
233
  },
261
234
  });
262
235
 
263
- if (newChannel) {
264
- const connectedCampaigns = newChannel.connectedCampaigns || [];
265
- if (
266
- !connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)
267
- ) {
268
- connectedCampaigns.push({
269
- campaignId: campaign.AGRS_CID,
270
- assignedAt: new Date(),
271
- releasedAt: null,
272
- });
273
- await newChannel.update(
274
- {
275
- status: "used",
276
- connectedCampaigns,
277
- },
278
- { silent: true }
279
- );
280
- }
236
+ if (oldChannel) {
237
+ const connectedCampaigns = oldChannel.connectedCampaigns || [];
238
+ const updatedCampaigns = connectedCampaigns
239
+ .map((c) =>
240
+ c.campaignId === campaign.AGRS_CID
241
+ ? { ...c, releasedAt: new Date() }
242
+ : c
243
+ )
244
+ .filter((c) => !c.releasedAt);
245
+
246
+ await oldChannel.update(
247
+ {
248
+ connectedCampaigns: updatedCampaigns,
249
+ status: updatedCampaigns.length > 0 ? "used" : "free",
250
+ },
251
+ { silent: true }
252
+ );
253
+ }
254
+ }
255
+
256
+ // Assign new channel
257
+ const newChannel = await sequelize.models.Channel.findOne({
258
+ where: {
259
+ channelId: newChannelId,
260
+ styleId: newStyleId,
261
+ },
262
+ });
263
+
264
+ if (newChannel) {
265
+ const connectedCampaigns = newChannel.connectedCampaigns || [];
266
+ if (
267
+ !connectedCampaigns.some((c) => c.campaignId === campaign.AGRS_CID)
268
+ ) {
269
+ connectedCampaigns.push({
270
+ campaignId: campaign.AGRS_CID,
271
+ assignedAt: new Date(),
272
+ releasedAt: null,
273
+ });
274
+ await newChannel.update(
275
+ {
276
+ status: "used",
277
+ connectedCampaigns,
278
+ },
279
+ { silent: true }
280
+ );
281
281
  }
282
- } catch (error) {
283
- console.error(
284
- "Error updating channels in beforeUpdate hook:",
285
- error.message
282
+ } else {
283
+ console.warn(
284
+ `New channel not found for channelId: ${newChannelId}, styleId: ${newStyleId}`
286
285
  );
287
- // Continue with campaign update even if channel updates fail
288
286
  }
287
+ } catch (error) {
288
+ console.error("Error in beforeUpdate hook:", error.message);
289
289
  }
290
290
  });
291
291
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agrs-sequelize-sdk",
3
- "version": "1.1.56",
3
+ "version": "1.1.58",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "start": "node index.js",