Skip to content

Commit 03cf8a6

Browse files
committed
Scripting: Converters can adapt return values
Add ability to explicitly coerce the return value from a script. Runtime fields want to avoid returning `Object` from the execute method in each context. Instead, they will return an array of primitive objects, such as `long[]`. However, it's convenient to allow a user to return a single primitive type rather than allocating a length-one array. To achieve this, an implementer can add explicit conversion functions to a context with signature: `public static <context-return-value> convertFrom<Suffix>(<any type>)` When a user returns a type other than the context return value, at compile-time, painless will insert a call to their `convertFrom` method. This commit is Phase 1 of this work. It handles explicit converters for all painless types EXCEPT def type. Refs: elastic#59647
1 parent 1c6ffb6 commit 03cf8a6

File tree

1 file changed

+54
-4
lines changed

1 file changed

+54
-4
lines changed

modules/lang-painless/src/test/java/org/elasticsearch/painless/FactoryTests.java

+54-4
Original file line numberDiff line numberDiff line change
@@ -301,22 +301,72 @@ public interface Factory {
301301
public static long[] convertFromInt(int i) {
302302
return new long[]{i};
303303
}
304+
305+
public static long[] convertFromString(String s) {
306+
return new long[]{Long.parseLong(s)};
307+
}
308+
309+
public static long[] convertFromList(List<?> l) {
310+
long[] converted = new long[l.size()];
311+
for (int i=0; i < l.size(); i++) {
312+
Object o = l.get(i);
313+
if (o instanceof Long) {
314+
converted[i] = (Long) o;
315+
} else if (o instanceof Integer) {
316+
converted[i] = (Integer) o;
317+
} else if (o instanceof String) {
318+
converted[i] = Long.parseLong((String) o);
319+
}
320+
}
321+
return converted;
322+
}
304323
}
305324

306325

307326
public void testConverterFactory() {
308327
FactoryTestConverterScript.Factory factory =
309-
scriptEngine.compile("factory_test", "return test;", FactoryTestConverterScript.CONTEXT, Collections.emptyMap());
328+
scriptEngine.compile("converter_test",
329+
"return test;",
330+
FactoryTestConverterScript.CONTEXT, Collections.emptyMap());
310331
FactoryTestConverterScript script = factory.newInstance(Collections.singletonMap("test", 2));
311332
assertArrayEquals(new long[]{2}, script.execute(2));
312333
script = factory.newInstance(Collections.singletonMap("test", 3));
313334
assertArrayEquals(new long[]{3}, script.execute(3));
314335

315-
factory = scriptEngine.compile("factory_test", "return test + 1;", FactoryTestConverterScript.CONTEXT, Collections.emptyMap());
336+
factory = scriptEngine.compile("converter_test",
337+
"return test + 1;",
338+
FactoryTestConverterScript.CONTEXT, Collections.emptyMap());
316339
script = factory.newInstance(Collections.singletonMap("test", 2));
317340
assertArrayEquals(new long[]{1001}, script.execute(1000));
318341

319-
// TODO(stu): different conversion
320-
// TODO(stu): return long array
342+
factory = scriptEngine.compile("converter_test",
343+
"return '100';",
344+
FactoryTestConverterScript.CONTEXT, Collections.emptyMap());
345+
script = factory.newInstance(Collections.singletonMap("test", 2));
346+
assertArrayEquals(new long[]{100}, script.execute(1000));
347+
348+
factory = scriptEngine.compile("converter_test",
349+
"long[] a = new long[]{test, 123}; return a;",
350+
FactoryTestConverterScript.CONTEXT, Collections.emptyMap());
351+
script = factory.newInstance(Collections.singletonMap("test", 2));
352+
assertArrayEquals(new long[]{1000, 123}, script.execute(1000));
353+
354+
factory = scriptEngine.compile("converter_test",
355+
"return [test, 123];",
356+
FactoryTestConverterScript.CONTEXT, Collections.emptyMap());
357+
script = factory.newInstance(Collections.singletonMap("test", 2));
358+
assertArrayEquals(new long[]{1000, 123}, script.execute(1000));
359+
360+
factory = scriptEngine.compile("converter_test",
361+
"ArrayList a = new ArrayList(); a.add(test); a.add(456); a.add('789'); return a;",
362+
FactoryTestConverterScript.CONTEXT, Collections.emptyMap());
363+
script = factory.newInstance(Collections.singletonMap("test", 2));
364+
assertArrayEquals(new long[]{123, 456, 789}, script.execute(123));
365+
366+
ClassCastException cce = expectScriptThrows(ClassCastException.class, () ->
367+
scriptEngine.compile("converter_test",
368+
"return true;",
369+
FactoryTestConverterScript.CONTEXT, Collections.emptyMap()));
370+
assertEquals(cce.getMessage(), "Cannot cast from [boolean] to [long[]].");
321371
}
322372
}

0 commit comments

Comments
 (0)