Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[yVM4sJbH] Dev fix round trip for csv loading #666

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions common/src/main/java/apoc/load/Mapping.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@ private Object convertType(String value) {
return DateValue.parse(value).asObjectCopy();
case DURATION:
return DurationValue.parse(value);
case LONG:
case INTEGER:
return Util.toLong(value);
case DOUBLE:
case FLOAT:
return Util.toDouble(value);
case BOOLEAN:
Expand Down
2 changes: 2 additions & 0 deletions common/src/main/java/apoc/meta/Types.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import org.neo4j.values.storable.DurationValue;

public enum Types {
LONG,
DOUBLE,
INTEGER,
FLOAT,
STRING,
Expand Down
122 changes: 120 additions & 2 deletions core/src/test/java/apoc/export/csv/ImportCsvTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,14 @@ public class ImportCsvTest {
"""
:START_ID(node_code),:END_ID(node_code),:TYPE
806^04^150\\\\^123456,2,FRIENDS_WITH
"""))
"""),
new AbstractMap.SimpleEntry<>(
"withDifferentTypes",
"""
id:ID|name:STRING|age:double|chipID:long|:LABEL
1|Maja|0.5|1236|Cat
2|Pelle|0.5|1345|Cat
"""))
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)));

@Before
Expand All @@ -312,7 +319,7 @@ public void setUp() throws IOException {
CsvTestUtil.saveCsvFile(entry.getKey(), entry.getValue());
}

TestUtil.registerProcedure(db, ImportCsv.class);
TestUtil.registerProcedure(db, ImportCsv.class, ExportCSV.class);

apocConfig().setProperty(APOC_IMPORT_FILE_ENABLED, true);
apocConfig().setProperty(APOC_EXPORT_FILE_ENABLED, true);
Expand Down Expand Up @@ -994,4 +1001,115 @@ public void testLoadDuplicateNodes() {
long id = TestUtil.<Long>singleResultFirstColumn(db, "MATCH (n:Person) RETURN n.id AS id ORDER BY id");
Assert.assertEquals(1L, id);
}

@Test
public void testDifferentDataTypes() {
TestUtil.testCall(
db,
"CALL apoc.import.csv([{fileName: $file, labels: ['Person']}], [], $config)",
map(
"file",
"file:/withDifferentTypes.csv",
"config",
map("delimiter", '|', "ignoreDuplicateNodes", true)),
(r) -> {
assertEquals(2L, r.get("nodes"));
assertEquals(0L, r.get("relationships"));
});

TestUtil.testResult(
db, "MATCH (n:Cat) RETURN n.name AS name, n.age AS age, n.chipID AS chipID ORDER BY name", (res) -> {
Map<String, Object> r = res.next();
assertEquals("Maja", r.get("name"));
assertEquals(0.5, r.get("age"));
assertEquals(1236L, r.get("chipID"));
r = res.next();
assertEquals("Pelle", r.get("name"));
assertEquals(0.5, r.get("age"));
assertEquals(1345L, r.get("chipID"));
});

db.executeTransactionally("MATCH (n:Cat) DETACH DELETE n");
}

@Test
public void testRoundTripWithTypes() {
db.executeTransactionally("MATCH (n) DETACH DELETE n");

db.executeTransactionally(
"""
CREATE (:Cat {
name: 'Maja',
age: 0.5,
chipID: 1236,
location: point({latitude: 13.1, longitude: 33.46789}),
isFluffy: true,
born: date('2024-05-10')
})
CREATE (:Cat {
name: 'Pelle',
age: 0.5,
chipID: 1345,
location: point({latitude: 13.1, longitude: 33.46789}),
isFluffy: false,
born: date('2024-05-10')
})
""");

// In separate files
String fileNameStart = "exportedData";
String fileName = fileNameStart + ".csv";
TestUtil.testCall(
db,
"CALL apoc.export.csv.all($file,{bulkImport: true})",
map("file", fileName),
(r) -> assertEquals(fileName, r.get("file")));

// REMOVE DATA
db.executeTransactionally("MATCH (n) DETACH DELETE n");

TestUtil.testCall(
db,
"CALL apoc.import.csv([{fileName: $file, labels: ['Cat']}], [], $config)",
map("file", fileNameStart + ".nodes.Cat.csv", "config", map("ignoreDuplicateNodes", true)),
(r) -> {
assertEquals(2L, r.get("nodes"));
assertEquals(0L, r.get("relationships"));
});

TestUtil.testResult(
db,
"""
MATCH (n:Cat)
RETURN n.name AS name,
n.age AS age,
n.chipID AS chipID,
n.isFluffy AS isFluffy,
n.friends AS friends,
n.location AS location,
n.born AS born
ORDER BY name
""",
(res) -> {
Map<String, Object> r = res.next();
assertEquals("Maja", r.get("name"));
assertEquals(0.5, r.get("age"));
assertEquals(1236L, r.get("chipID"));
assertEquals(true, r.get("isFluffy"));
assertEquals(
Values.pointValue(CoordinateReferenceSystem.WGS_84, 33.46789D, 13.1D), r.get("location"));
assertEquals(LocalDate.of(2024, 5, 10), r.get("born"));

r = res.next();
assertEquals("Pelle", r.get("name"));
assertEquals(0.5, r.get("age"));
assertEquals(1345L, r.get("chipID"));
assertEquals(false, r.get("isFluffy"));
assertEquals(
Values.pointValue(CoordinateReferenceSystem.WGS_84, 33.46789D, 13.1D), r.get("location"));
assertEquals(LocalDate.of(2024, 5, 10), r.get("born"));
});

db.executeTransactionally("MATCH (n:Cat) DETACH DELETE n");
}
}
Loading