import java.util.List;
+import static com.google.common.base.Preconditions.checkState;
+
@Phase(name = Phase.Name.PRE)
public class ManualMeasureDecorator implements Decorator {
private Measure copy(ManualMeasure manualMeasure) {
Metric metric = metricFinder.findById(manualMeasure.getMetricId());
- if (metric == null) {
- throw new IllegalStateException("Unable to find manual metric with id: " + manualMeasure.getMetricId());
- }
+ checkState(metric != null, "Unable to find manual metric with id: " + manualMeasure.getMetricId());
+
Measure measure = new Measure(metric);
measure.setValue(manualMeasure.getValue(), 5);
measure.setData(manualMeasure.getTextValue());
FeedSnapshotsLongDates.class,
FeedIssuesLongDates.class,
FeedFileSourcesBinaryData.class,
- FeedSemaphoresLongDates.class
+ FeedSemaphoresLongDates.class,
+ FeedProjectMeasuresLongDates.class,
+ FeedManualMeasuresLongDates.class
);
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.db.migrations.v51;
+
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.Database;
+import org.sonar.server.db.migrations.BaseDataChange;
+import org.sonar.server.db.migrations.MassUpdate;
+import org.sonar.server.db.migrations.Select;
+import org.sonar.server.db.migrations.SqlStatement;
+
+import java.sql.SQLException;
+import java.util.Date;
+
+public class FeedManualMeasuresLongDates extends BaseDataChange {
+
+ private final System2 system2;
+
+ public FeedManualMeasuresLongDates(Database db, System2 system2) {
+ super(db);
+ this.system2 = system2;
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ final long now = system2.now();
+ MassUpdate massUpdate = context.prepareMassUpdate();
+ massUpdate
+ .select("SELECT m.created_at, m.updated_at, m.id FROM manual_measures m WHERE created_at_ms IS NULL");
+ massUpdate
+ .update("UPDATE manual_measures SET created_at_ms=?, updated_at_ms=? WHERE id=?");
+ massUpdate.rowPluralName("manualMeasures");
+ massUpdate.execute(new MassUpdate.Handler() {
+ @Override
+ public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+ for (int i = 1; i <= 2; i++) {
+ Date date = row.getDate(i);
+ update.setLong(i, date == null ? null : Math.min(now, date.getTime()));
+ }
+
+ Long id = row.getLong(3);
+ update.setLong(3, id);
+
+ return true;
+ }
+ });
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.db.migrations.v51;
+
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.Database;
+import org.sonar.server.db.migrations.BaseDataChange;
+import org.sonar.server.db.migrations.MassUpdate;
+import org.sonar.server.db.migrations.Select;
+import org.sonar.server.db.migrations.SqlStatement;
+
+import java.sql.SQLException;
+import java.util.Date;
+
+public class FeedProjectMeasuresLongDates extends BaseDataChange {
+
+ private final System2 system2;
+
+ public FeedProjectMeasuresLongDates(Database db, System2 system2) {
+ super(db);
+ this.system2 = system2;
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ final long now = system2.now();
+ MassUpdate massUpdate = context.prepareMassUpdate();
+ massUpdate
+ .select("SELECT m.measure_date, m.id FROM project_measures m WHERE measure_date_ms IS NULL");
+ massUpdate
+ .update("UPDATE project_measures SET measure_date_ms=? WHERE id=?");
+ massUpdate.rowPluralName("projectMeasures");
+ massUpdate.execute(new MassUpdate.Handler() {
+ @Override
+ public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+ Date date = row.getDate(1);
+ update.setLong(1, date == null ? null : Math.min(now, date.getTime()));
+
+ Long id = row.getLong(2);
+ update.setLong(2, id);
+
+ return true;
+ }
+ });
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.db.migrations.v51;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.db.migrations.DatabaseMigration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.utils.DateUtils.parseDate;
+
+public class FeedManualMeasuresLongDatesTest {
+ @ClassRule
+ public static DbTester db = new DbTester().schema(FeedManualMeasuresLongDatesTest.class, "schema.sql");
+
+ @Before
+ public void before() throws Exception {
+ db.prepareDbUnit(getClass(), "before.xml");
+ }
+
+ @Test
+ public void execute() throws Exception {
+ DatabaseMigration migration = newMigration(System2.INSTANCE);
+
+ migration.execute();
+
+ int count = db
+ .countSql("select count(*) from manual_measures where " +
+ "created_at_ms is not null " +
+ "and updated_at_ms is not null");
+ assertThat(count).isEqualTo(2);
+ }
+
+ @Test
+ public void take_now_if_date_in_the_future() throws Exception {
+ System2 system = mock(System2.class);
+ when(system.now()).thenReturn(1234L);
+
+ DatabaseMigration migration = newMigration(system);
+
+ migration.execute();
+
+ int count = db
+ .countSql("select count(*) from manual_measures where " +
+ "created_at_ms = 1234");
+ assertThat(count).isEqualTo(1);
+ }
+
+ @Test
+ public void take_snapshot_date_if_in_the_past() throws Exception {
+ DatabaseMigration migration = newMigration(System2.INSTANCE);
+
+ migration.execute();
+
+ long snapshotTime = parseDate("2014-09-25").getTime();
+ int count = db
+ .countSql("select count(*) from manual_measures where " +
+ "created_at_ms=" + snapshotTime);
+ assertThat(count).isEqualTo(1);
+ }
+
+ private DatabaseMigration newMigration(System2 system) {
+ return new FeedManualMeasuresLongDates(db.database(), system);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.db.migrations.v51;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.db.migrations.DatabaseMigration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.utils.DateUtils.parseDate;
+
+public class FeedProjectMeasuresLongDatesTest {
+ @ClassRule
+ public static DbTester db = new DbTester().schema(FeedProjectMeasuresLongDatesTest.class, "schema.sql");
+
+ @Before
+ public void before() throws Exception {
+ db.prepareDbUnit(getClass(), "before.xml");
+ }
+
+ @Test
+ public void execute() throws Exception {
+ DatabaseMigration migration = newMigration(System2.INSTANCE);
+
+ migration.execute();
+
+ int count = db
+ .countSql("select count(*) from project_measures where " +
+ "measure_date_ms is not null");
+ assertThat(count).isEqualTo(2);
+ }
+
+ @Test
+ public void take_now_if_date_in_the_future() throws Exception {
+ System2 system = mock(System2.class);
+ when(system.now()).thenReturn(1234L);
+
+ DatabaseMigration migration = newMigration(system);
+
+ migration.execute();
+
+ int count = db
+ .countSql("select count(*) from project_measures where " +
+ "measure_date_ms = 1234");
+ assertThat(count).isEqualTo(1);
+ }
+
+ @Test
+ public void take_snapshot_date_if_in_the_past() throws Exception {
+ DatabaseMigration migration = newMigration(System2.INSTANCE);
+
+ migration.execute();
+
+ long snapshotTime = parseDate("2014-09-25").getTime();
+ int count = db
+ .countSql("select count(*) from project_measures where " +
+ "measure_date_ms=" + snapshotTime);
+ assertThat(count).isEqualTo(1);
+ }
+
+ private FeedProjectMeasuresLongDates newMigration(System2 system) {
+ return new FeedProjectMeasuresLongDates(db.database(), system);
+ }
+}
--- /dev/null
+<dataset>
+ <!-- new migration -->
+ <manual_measures
+ id="1"
+ created_at="2014-09-25"
+ created_at_ms="[null]"
+ updated_at="2014-09-25"
+ updated_at_ms="[null]"
+ />
+
+ <!-- re-entrant migration - ignore the ones that are already fed with new dates -->
+ <manual_measures
+ id="2"
+ created_at="2014-09-25"
+ created_at_ms="1500000000"
+ updated_at="2014-09-25"
+ updated_at_ms="1500000000"
+ />
+
+ <!-- NULL dates -->
+ <manual_measures
+ id="3"
+ created_at="[null]"
+ created_at_ms="[null]"
+ updated_at="[null]"
+ updated_at_ms="[null]"
+ />
+</dataset>
--- /dev/null
+CREATE TABLE "MANUAL_MEASURES" (
+ "ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "CREATED_AT" TIMESTAMP,
+ "CREATED_AT_MS" BIGINT,
+ "UPDATED_AT" TIMESTAMP,
+ "UPDATED_AT_MS" BIGINT
+);
--- /dev/null
+<dataset>
+ <!-- new migration -->
+ <project_measures
+ id="1"
+ measure_date="2014-09-25"
+ measure_date_ms="[null]"
+ />
+
+ <!-- re-entrant migration - ignore the ones that are already fed with new dates -->
+ <project_measures
+ id="2"
+ measure_date="2014-09-25"
+ measure_date_ms="1500000000"
+ />
+
+ <!-- NULL dates -->
+ <project_measures
+ id="3"
+ measure_date="[null]"
+ measure_date_ms="[null]"
+ />
+</dataset>
--- /dev/null
+CREATE TABLE "PROJECT_MEASURES" (
+ "ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "MEASURE_DATE" TIMESTAMP,
+ "MEASURE_DATE_MS" BIGINT
+);
if snapshot.nil?
snapshot=resource.last_snapshot
end
- snapshot && updated_at && snapshot.created_at<updated_at
+ snapshot && updated_at && snapshot.created_at<Time.at(updated_at/1000)
end
def formatted_value
--- /dev/null
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+#
+# SonarQube 5.1
+#
+class AddMeasuresLongDates < ActiveRecord::Migration
+ def self.up
+ add_column 'project_measures', :measure_date_ms, :big_integer, :null => true
+ add_column 'manual_measures', :created_at_ms, :big_integer, :null => true
+ add_column 'manual_measures', :updated_at_ms, :big_integer, :null => true
+ end
+end
--- /dev/null
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+#
+# SonarQube 5.1
+#
+class FeedMeasuresLongDates < ActiveRecord::Migration
+ def self.up
+ execute_java_migration('org.sonar.server.db.migrations.v51.FeedProjectMeasuresLongDates')
+ execute_java_migration('org.sonar.server.db.migrations.v51.FeedManualMeasuresLongDates')
+ end
+end
+
--- /dev/null
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+#
+# SonarQube 5.1
+#
+class RenameMeasuresLongDates < ActiveRecord::Migration
+ def self.up
+ remove_column 'project_measures', 'measure_date'
+ remove_column 'manual_measures', 'created_at'
+ remove_column 'manual_measures', 'updated_at'
+ rename_column 'manual_measures', 'created_at_ms', 'created_at'
+ rename_column 'manual_measures', 'updated_at_ms', 'updated_at'
+ rename_column 'project_measures', 'measure_date_ms', 'measure_date'
+ end
+end
+
*/
public class DatabaseVersion implements BatchComponent, ServerComponent {
- public static final int LAST_VERSION = 786;
+ public static final int LAST_VERSION = 789;
/**
* List of all the tables.n
import org.apache.commons.lang.builder.ToStringStyle;
import javax.persistence.*;
-import java.util.Date;
@Entity
@Table(name = "manual_measures")
private String description;
@Column(name = "created_at", updatable = true, nullable = true)
- private Date createdAt;
+ private Long createdAt;
@Column(name = "updated_at", updatable = true, nullable = true)
- private Date updatedAt;
+ private Long updatedAt;
@Column(name = "user_login", updatable = true, nullable = true, length = 40)
private String userLogin;
return resourceId;
}
- public Date getCreatedAt() {
+ public Long getCreatedAt() {
return createdAt;
}
- public Date getUpdatedAt() {
+ public Long getUpdatedAt() {
return updatedAt;
}
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('784');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('785');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('786');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('787');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('788');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('789');
INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null);
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
"RULES_CATEGORY_ID" INTEGER,
"TEXT_VALUE" VARCHAR(4000),
"TENDENCY" INTEGER,
- "MEASURE_DATE" TIMESTAMP,
+ "MEASURE_DATE" BIGINT,
"PROJECT_ID" INTEGER,
"ALERT_STATUS" VARCHAR(5),
"ALERT_TEXT" VARCHAR(4000),
"TEXT_VALUE" VARCHAR(4000),
"USER_LOGIN" VARCHAR(255),
"DESCRIPTION" VARCHAR(4000),
- "CREATED_AT" TIMESTAMP,
- "UPDATED_AT" TIMESTAMP
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT
);
CREATE TABLE "ACTIVE_RULES" (
import org.sonar.api.measures.Metric;
import org.sonar.api.rules.RulePriority;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.Table;
-import javax.persistence.Temporal;
-import javax.persistence.TemporalType;
+import javax.persistence.*;
import java.io.UnsupportedEncodingException;
import java.util.Date;
+import static org.sonar.api.utils.DateUtils.dateToLong;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
/**
* This class is the Hibernate model to store a measure in the DB
*/
@Column(name = "description", updatable = true, nullable = true, length = 4000)
private String description;
- @Temporal(TemporalType.TIMESTAMP)
@Column(name = "measure_date", updatable = true, nullable = true)
- private Date measureDate;
+ private Long measureDate;
@Column(name = "rule_id", updatable = true, nullable = true)
private Integer ruleId;
@Column(name = "measure_data", updatable = true, nullable = true, length = 167772150)
private byte[] data;
- public Long getId() {
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
-
/**
* Creates a measure based on a metric and a double value
*/
public MeasureModel() {
}
- /**
- * @return the measure double value
- */
- public Double getValue() {
- return value;
+ public Long getId() {
+ return id;
}
- /**
- * @return the measure description
- */
- public String getDescription() {
- return description;
+ public void setId(Long id) {
+ this.id = id;
}
/**
- * Sets the measure description
+ * @return the measure double value
*/
- public void setDescription(String description) {
- this.description = description;
+ public Double getValue() {
+ return value;
}
/**
return this;
}
+ /**
+ * @return the measure description
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Sets the measure description
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
/**
* @return the measure alert level
*/
return tendency;
}
- /**
- * @return whether the measure is about rule
- */
- public boolean isRuleMeasure() {
- return ruleId != null || rulePriority != null;
- }
-
/**
* Sets the measure tendency
*
return this;
}
+ /**
+ * @return whether the measure is about rule
+ */
+ public boolean isRuleMeasure() {
+ return ruleId != null || rulePriority != null;
+ }
+
public Integer getMetricId() {
return metricId;
}
* @return the date of the measure
*/
public Date getMeasureDate() {
- return measureDate;
+ return longToDate(measureDate);
}
/**
* @return the current object
*/
public MeasureModel setMeasureDate(Date measureDate) {
+ this.measureDate = dateToLong(measureDate);
+ return this;
+ }
+
+ /**
+ * @return the date of the measure
+ */
+ public Long getMeasureDateMs() {
+ return measureDate;
+ }
+
+ /**
+ * Sets the date for the measure
+ *
+ * @return the current object
+ */
+ public MeasureModel setMeasureDateMs(Long measureDate) {
this.measureDate = measureDate;
return this;
}
variation_value_2, variation_value_3, variation_value_4, variation_value_5, person_id, measure_data)
VALUES (
#{value, jdbcType=DOUBLE}, #{metricId, jdbcType=INTEGER}, #{snapshotId, jdbcType=INTEGER}, #{ruleId, jdbcType=INTEGER}, #{textValue, jdbcType=VARCHAR}, #{tendency, jdbcType=INTEGER},
- #{measureDate, jdbcType=TIMESTAMP}, #{projectId, jdbcType=INTEGER}, #{alertStatus, jdbcType=VARCHAR}, #{alertText, jdbcType=VARCHAR},
+ #{measureDateMs, jdbcType=BIGINT}, #{projectId, jdbcType=INTEGER}, #{alertStatus, jdbcType=VARCHAR}, #{alertText, jdbcType=VARCHAR},
#{url, jdbcType=VARCHAR}, #{description, jdbcType=VARCHAR}, #{rulePriority.ordinal, jdbcType=INTEGER}, #{characteristicId, jdbcType=INTEGER}, #{variationValue1, jdbcType=DOUBLE},
#{variationValue2, jdbcType=DOUBLE}, #{variationValue3, jdbcType=DOUBLE}, #{variationValue4, jdbcType=DOUBLE}, #{variationValue5, jdbcType=DOUBLE}, #{personId, jdbcType=INTEGER}, #{data}
)