public static Result<Boolean> isRecordsEquals(TableRecords beforeImage, TableRecords afterImage) {
        if (beforeImage == null) {
            return Result.build(afterImage == null, null);
        } else {
            if (afterImage == null) {
                return Result.build(false, null);
            }
            if (beforeImage.getTableName().equalsIgnoreCase(afterImage.getTableName())
                    && CollectionUtils.isSizeEquals(beforeImage.getRows(), afterImage.getRows())) {
                //when image is EmptyTableRecords, getTableMeta will throw an exception
                if (CollectionUtils.isEmpty(beforeImage.getRows())) {
                    return Result.ok();
                }
                return compareRows(beforeImage.getTableMeta(), beforeImage.getRows(), afterImage.getRows());
            } else {
                return Result.build(false, null);
            }
        }
    }
@Test
    public void isRecordsEquals() {
        TableMeta tableMeta = Mockito.mock(TableMeta.class);
        Mockito.when(tableMeta.getPrimaryKeyOnlyName()).thenReturn(Arrays.asList(new String[]{"pk"}));
        Mockito.when(tableMeta.getTableName()).thenReturn("table_name");

        TableRecords beforeImage = new TableRecords();
        beforeImage.setTableName("table_name");
        beforeImage.setTableMeta(tableMeta);

        List<Row> rows = new ArrayList<>();
        Row row = new Row();
        Field field01 = addField(row,"pk", 1, "12345");
        Field field02 = addField(row,"age", 1, "18");
        rows.add(row);
        beforeImage.setRows(rows);

        Assertions.assertFalse(DataCompareUtils.isRecordsEquals(beforeImage, null).getResult());
        Assertions.assertFalse(DataCompareUtils.isRecordsEquals(null, beforeImage).getResult());

        TableRecords afterImage = new TableRecords();
        afterImage.setTableName("table_name1"); // wrong table name
        afterImage.setTableMeta(tableMeta);

        Assertions.assertFalse(DataCompareUtils.isRecordsEquals(beforeImage, afterImage).getResult());
        afterImage.setTableName("table_name");

        Assertions.assertFalse(DataCompareUtils.isRecordsEquals(beforeImage, afterImage).getResult());

        List<Row> rows2 = new ArrayList<>();
        Row row2 = new Row();
        Field field11 = addField(row2,"pk", 1, "12345");
        Field field12 = addField(row2,"age", 1, "18");
        rows2.add(row2);
        afterImage.setRows(rows2);
        Assertions.assertTrue(DataCompareUtils.isRecordsEquals(beforeImage, afterImage).getResult());

        field11.setValue("23456");
        Assertions.assertFalse(DataCompareUtils.isRecordsEquals(beforeImage, afterImage).getResult());
        field11.setValue("12345");

        field12.setName("sex");
        Assertions.assertFalse(DataCompareUtils.isRecordsEquals(beforeImage, afterImage).getResult());
        field12.setName("age");

        field12.setValue("19");
        Assertions.assertFalse(DataCompareUtils.isRecordsEquals(beforeImage, afterImage).getResult());
        field12.setName("18");

        Field field3 = new Field("pk", 1, "12346");
        Row row3 = new Row();
        row3.add(field3);
        rows2.add(row3);
        Assertions.assertFalse(DataCompareUtils.isRecordsEquals(beforeImage, afterImage).getResult());
        

        beforeImage.setRows(new ArrayList<>());
        afterImage.setRows(new ArrayList<>());
        Assertions.assertTrue(DataCompareUtils.isRecordsEquals(beforeImage, afterImage).getResult());
    }