Skip to content

Commit

Permalink
pass annotations for reference fields to the EntityRef kotlin class. … (
Browse files Browse the repository at this point in the history
PolymerLabs#6063)

* pass annotations for reference fields to the EntityRef kotlin class. Also adds a canonical @Hardref annotation.

* fix for strict deps

* update kotlin goldens

* address review comments

* sync
  • Loading branch information
galganif authored Sep 3, 2020
1 parent e3094ed commit ba10107
Show file tree
Hide file tree
Showing 15 changed files with 140 additions and 61 deletions.
16 changes: 15 additions & 1 deletion java/arcs/core/data/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ SCHEMA_FIELDS_SRCS = [
"SchemaFields.kt",
]

ANNOTATIONS_SRCS = [
"Annotation.kt",
"AnnotationParam.kt",
]

REFERENCE_SRCS = [
"Reference.kt",
]
Expand All @@ -24,13 +29,15 @@ arcs_kt_library(
name = "data",
srcs = glob(
["*.kt"],
exclude = ENTITY_SRCS + SCHEMA_FIELDS_SRCS + REFERENCE_SRCS,
exclude = ENTITY_SRCS + SCHEMA_FIELDS_SRCS + REFERENCE_SRCS + ANNOTATIONS_SRCS,
),
exports = [
":annotations",
":rawentity",
":reference",
],
deps = [
":annotations",
":rawentity",
":reference",
":schema_fields",
Expand Down Expand Up @@ -66,7 +73,14 @@ arcs_kt_library(
name = "schema_fields",
srcs = SCHEMA_FIELDS_SRCS,
deps = [
":annotations",
":rawentity",
"//java/arcs/core/type",
],
)

arcs_kt_library(
name = "annotations",
srcs = ANNOTATIONS_SRCS,
deps = [],
)
8 changes: 6 additions & 2 deletions java/arcs/core/data/SchemaFields.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ import arcs.core.type.Type

/** The possible types for a field in a [Schema]. */
sealed class FieldType(
val tag: Tag
val tag: Tag,
open val annotations: List<Annotation> = emptyList()
) {
/** An Arcs primitive type. */
data class Primitive(val primitiveType: PrimitiveType) : FieldType(Tag.Primitive) {
override fun toString() = primitiveType.name
}

/** A reference to an entity. */
data class EntityRef(val schemaHash: String) : FieldType(Tag.EntityRef) {
data class EntityRef(
val schemaHash: String,
override val annotations: List<Annotation> = emptyList()
) : FieldType(Tag.EntityRef, annotations) {
override fun toString() = "&$schemaHash"
}

Expand Down
5 changes: 5 additions & 0 deletions src/runtime/canonical-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,10 @@ annotation policy(name: Text)
retention: Source
doc: 'Indicates that the target recipe should comply with the policy of the given name.'
annotation hardRef
targets: [SchemaField]
retention: Source
doc: 'It can be used on reference fields: a hard reference indicates that the entity with that field should be deleted when the referenced entity is deleted.'
${canonicalPolicyAnnotations}
`;
14 changes: 14 additions & 0 deletions src/runtime/tests/manifest-parser-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ describe('manifest parser', () => {
h1: create 'my-id' @tiedToRuntime
h2: create #mytag @tiedToArc`);
});
it('parses schema annotations', () => {
parse(`
schema Abcd
foo: &MyFoo @aFoo
`);
});
it('parses particle schema annotations', () => {
parse(`
particle Foo
a: reads B {
foo: &MyFoo @aFoo
}
`);
});
it('parses recipes with particles', () => {
parse(`
recipe Recipe
Expand Down
22 changes: 0 additions & 22 deletions src/tools/annotation2proto.ts

This file was deleted.

51 changes: 51 additions & 0 deletions src/tools/annotations-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* @license
* Copyright (c) 2020 Google Inc. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt
* Code distributed by Google as part of this project is also
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/

import {AnnotationRef} from '../runtime/arcs-types/annotation.js';
import {quote, KotlinGenerationUtils} from './kotlin-generation-utils.js';

export function annotationToProtoPayload(annotation: AnnotationRef) {
return {
name: annotation.name,
params: Object.entries(annotation.params).map(([name, value]) => {
const valueField = typeof value === 'string' ? 'strValue'
: typeof value === 'number' ? 'numValue' : 'boolValue';
return {name, [valueField]: value};
})
};
}

// Encode the annotations in a kotlin list of kotlin Annotation.
export function annotationsToKotlin(annotations: AnnotationRef[]): string {
const ktUtils = new KotlinGenerationUtils();
const annotationStrs: string[] = [];
for (const ref of annotations) {
const paramMappings = Object.entries(ref.annotation.params).map(([name, type]) => {
const paramToMapping = () => {
switch (type) {
case 'Text':
return `AnnotationParam.Str(${quote(ref.params[name].toString())})`;
case 'Number':
return `AnnotationParam.Num(${ref.params[name]})`;
case 'Boolean':
return `AnnotationParam.Bool(${ref.params[name]})`;
default: throw new Error(`Unsupported param type ${type}`);
}
};
return `"${name}" to ${paramToMapping()}`;
});

annotationStrs.push(ktUtils.applyFun('Annotation', [
quote(ref.name),
ktUtils.mapOf(paramMappings, 12)
]));
}
return ktUtils.listOf(annotationStrs);
}
7 changes: 5 additions & 2 deletions src/tools/kotlin-schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {KotlinGenerationUtils, leftPad, quote} from './kotlin-generation-utils.j
import {Schema} from '../types/lib-types.js';
import {KTExtracter} from './kotlin-refinement-generator.js';
import {assert} from '../platform/assert-web.js';
import {annotationsToKotlin} from './annotations-utils.js';

const ktUtils = new KotlinGenerationUtils();

Expand Down Expand Up @@ -72,7 +73,8 @@ async function visitSchemaFields(schema: Schema, visitor: (field: SchemaField) =
}
}

async function getSchemaType(field: string, {kind, schema, type, innerType}): Promise<string> {
async function getSchemaType(field: string, {kind, schema, type, innerType, annotations}): Promise<string> {
// Annotations are only passed on for references, we can add support for other field types as needed.
const fieldType = 'arcs.core.data.FieldType';
if (kind === 'schema-primitive') {
switch (type) {
Expand All @@ -95,7 +97,8 @@ async function getSchemaType(field: string, {kind, schema, type, innerType}): Pr
default: break;
}
} else if (kind === 'schema-reference') {
return `${fieldType}.EntityRef(${quote(await schema.model.getEntitySchema().hash())})`;
const kannotations = (annotations && annotations.length) ? ', ' + annotationsToKotlin(annotations) : '';
return `${fieldType}.EntityRef(${quote(await schema.model.getEntitySchema().hash())}${kannotations})`;
} else if (kind === 'schema-nested') {
return `${fieldType}.InlineEntity(${quote(await schema.model.getEntitySchema().hash())})`;
} else if (kind === 'schema-ordered-list') {
Expand Down
2 changes: 1 addition & 1 deletion src/tools/manifest2proto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {CheckCondition, CheckExpression} from '../runtime/arcs-types/check.js';
import {flatMap} from '../runtime/util.js';
import {Policy} from '../runtime/policy/policy.js';
import {policyToProtoPayload} from './policy2proto.js';
import {annotationToProtoPayload} from './annotation2proto.js';
import {annotationToProtoPayload} from './annotations-utils.js';

export async function encodeManifestToProto(path: string): Promise<Uint8Array> {
const manifest = await Runtime.parseFile(path, {throwImportErrors: true});
Expand Down
34 changes: 4 additions & 30 deletions src/tools/plan-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {Type} from '../types/lib-types.js';
import {KotlinGenerationUtils, quote, tryImport} from './kotlin-generation-utils.js';
import {generateConnectionType, generateHandleType} from './kotlin-type-generator.js';
import {Direction} from '../runtime/arcs-types/enums.js';
import {AnnotationRef} from '../runtime/arcs-types/annotation.js';
import {annotationsToKotlin} from './annotations-utils.js';

const ktUtils = new KotlinGenerationUtils();

Expand Down Expand Up @@ -49,7 +49,7 @@ export class PlanGenerator {
return ktUtils.applyFun(`Plan`, [
ktUtils.listOf(await Promise.all(recipe.particles.map(p => this.createParticle(p)))),
ktUtils.listOf(recipe.handles.map(h => this.handleVariableName(h))),
PlanGenerator.createAnnotations(recipe.annotations)
annotationsToKotlin(recipe.annotations)
], {startIndent});
}, {delegate: 'lazy'});

Expand Down Expand Up @@ -81,7 +81,7 @@ export class PlanGenerator {
return ktUtils.applyFun(`Handle`, [
await this.createStorageKey(handle),
await generateHandleType(handle.type.resolvedType()),
PlanGenerator.createAnnotations(handle.annotations)
annotationsToKotlin(handle.annotations)
], {startIndent});
}, {delegate: 'lazy'});
}
Expand All @@ -108,7 +108,7 @@ export class PlanGenerator {
const handle = this.handleVariableName(connection.handle);
const mode = this.createHandleMode(connection.direction, connection.type);
const type = await generateConnectionType(connection, {namespace: this.namespace});
const annotations = PlanGenerator.createAnnotations(connection.handle.annotations);
const annotations = annotationsToKotlin(connection.handle.annotations);
const args = [handle, mode, type, annotations];
if (connection.spec.expression) {
// This is a temporary stop gap, until we develop Expression AST in TypeScript.
Expand Down Expand Up @@ -145,32 +145,6 @@ export class PlanGenerator {
throw new PlanGeneratorError(`Problematic handle '${handle.id}': Only 'create' Handles can have null 'StorageKey's.`);
}

static createAnnotations(annotations: AnnotationRef[]): string {
const annotationStrs: string[] = [];
for (const ref of annotations) {
const paramMappings = Object.entries(ref.annotation.params).map(([name, type]) => {
const paramToMapping = () => {
switch (type) {
case 'Text':
return `AnnotationParam.Str(${quote(ref.params[name].toString())})`;
case 'Number':
return `AnnotationParam.Num(${ref.params[name]})`;
case 'Boolean':
return `AnnotationParam.Bool(${ref.params[name]})`;
default: throw new Error(`Unsupported param type ${type}`);
}
};
return `"${name}" to ${paramToMapping()}`;
});

annotationStrs.push(ktUtils.applyFun('Annotation', [
quote(ref.name),
ktUtils.mapOf(paramMappings, 12)
]));
}
return ktUtils.listOf(annotationStrs);
}

fileHeader(): string {
return `\
/* ktlint-disable */
Expand Down
2 changes: 1 addition & 1 deletion src/tools/policy2proto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import {mapToDictionary} from '../runtime/util.js';
import {PolicyConfig, PolicyField, PolicyTarget, Policy} from '../runtime/policy/policy.js';
import {PolicyRetentionMediumEnum, PolicyFieldUsageEnum} from './manifest-proto.js';
import {annotationToProtoPayload} from './annotation2proto.js';
import {annotationToProtoPayload} from './annotations-utils.js';

export function policyToProtoPayload(policy: Policy) {
return {
Expand Down
1 change: 1 addition & 0 deletions src/tools/schema2kotlin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export class Schema2Kotlin extends Schema2Base {
} else {
// Imports for jvm.
imports.push(
'import arcs.core.data.Annotation',
'import arcs.core.data.expression.*',
'import arcs.core.data.expression.Expression.*',
'import arcs.core.data.expression.Expression.BinaryOp.*',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
*/

import {assert} from '../../platform/chai-web.js';
import {AnnotationRef} from '../../runtime/arcs-types/annotation.js';
import {annotationToProtoPayload} from '../annotation2proto.js';
import {annotationToProtoPayload} from '../annotations-utils.js';
import {Manifest} from '../../runtime/manifest.js';

const customAnnotation = `
Expand Down
1 change: 1 addition & 0 deletions src/tools/tests/goldens/generated-schemas.jvm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package arcs.golden
// GENERATED CODE -- DO NOT EDIT
//

import arcs.core.data.Annotation
import arcs.core.data.expression.*
import arcs.core.data.expression.Expression.*
import arcs.core.data.expression.Expression.BinaryOp.*
Expand Down
34 changes: 34 additions & 0 deletions src/tools/tests/goldens/kotlin-schema-generation.cgtest
Original file line number Diff line number Diff line change
Expand Up @@ -368,3 +368,37 @@ arcs.core.data.Schema(
queryExpression = true.asExpr()
)
-----[end]-----

-----[name]-----
Hard reference annotation.
-----[input]-----
schema Package
schema Thing
apppackage: &Package @hardRef
particle T
h1: reads Thing
-----[results]-----
arcs.core.data.Schema(
setOf(arcs.core.data.SchemaName("Thing")),
arcs.core.data.SchemaFields(
singletons = mapOf(
"apppackage" to arcs.core.data.FieldType.EntityRef("e66546dddeeeeb244d5cefb50aec907475ebf424", listOf(Annotation("hardRef", emptyMap())))
),
collections = emptyMap()
),
"ab9592e35fddd0c0833b05289b88ddf4fe41958c",
refinementExpression = true.asExpr(),
queryExpression = true.asExpr()
)
-----[next]-----
arcs.core.data.Schema(
setOf(arcs.core.data.SchemaName("Package")),
arcs.core.data.SchemaFields(
singletons = emptyMap(),
collections = emptyMap()
),
"e66546dddeeeeb244d5cefb50aec907475ebf424",
refinementExpression = true.asExpr(),
queryExpression = true.asExpr()
)
-----[end]-----
1 change: 1 addition & 0 deletions src/tools/tests/goldens/kt_generated-schemas.jvm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package arcs.golden
// GENERATED CODE -- DO NOT EDIT
//

import arcs.core.data.Annotation
import arcs.core.data.expression.*
import arcs.core.data.expression.Expression.*
import arcs.core.data.expression.Expression.BinaryOp.*
Expand Down

0 comments on commit ba10107

Please sign in to comment.