Skip to content

Commit

Permalink
resolve allegro#1907 | handle record references when presenting avro …
Browse files Browse the repository at this point in the history
…schema
  • Loading branch information
MiloszKorman committed Oct 16, 2024
1 parent 4180225 commit 419d7b7
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 7 deletions.
2 changes: 1 addition & 1 deletion hermes-console/json-server/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
"topics": [
{
"id": "pl.allegro.public.group.DummyEvent",
"schema": "{\"type\":\"record\",\"name\":\"DummyEvent\",\"namespace\":\"pl.allegro.public.group.DummyEvent\",\"doc\":\"Event emitted when notification is sent to a user\",\"fields\":[{\"name\":\"__metadata\",\"type\":[\"null\",{\"type\":\"map\",\"values\":\"string\"}],\"doc\":\"Field internally used by Hermes to propagate metadata.\",\"default\":null},{\"name\":\"waybillId\",\"type\":[\"null\",{\"type\":\"record\",\"name\":\"WaybillId\",\"fields\":[{\"name\":\"waybill\",\"type\":\"string\",\"doc\":\"Waybill\"},{\"name\":\"carrierId\",\"type\":\"string\",\"doc\":\"CarrierId\"}]}],\"doc\":\"WaybillId\",\"default\":null},{\"name\":\"notificationId\",\"type\":\"string\",\"doc\":\"Notification Id\"},{\"name\":\"userId\",\"type\":\"string\",\"doc\":\"User Id\"}]}",
"schema": "{\"type\":\"record\",\"name\":\"DummyEvent\",\"namespace\":\"pl.allegro.public.group.DummyEvent\",\"doc\":\"Event emitted when notification is sent to a user\",\"fields\":[{\"name\":\"__metadata\",\"type\":[\"null\",{\"type\":\"map\",\"values\":\"string\"}],\"doc\":\"Field internally used by Hermes to propagate metadata.\",\"default\":null},{\"name\":\"waybillId\",\"type\":[\"null\",{\"type\":\"record\",\"name\":\"WaybillId\",\"fields\":[{\"name\":\"waybill\",\"type\":\"string\",\"doc\":\"Waybill\"},{\"name\":\"carrierId\",\"type\":\"string\",\"doc\":\"CarrierId\"}]}],\"doc\":\"WaybillId\",\"default\":null},{\"name\":\"otherWaybillId\",\"type\":[\"null\",\"WaybillId\"],\"doc\":\"other WaybillId\",\"default\":null},{\"name\":\"notificationId\",\"type\":\"string\",\"doc\":\"Notification Id\"},{\"name\":\"userId\",\"type\":\"string\",\"doc\":\"User Id\"}]}",
"name": "pl.allegro.public.group.DummyEvent",
"description": "Events emitted when notification is sent to a user.",
"owner": {
Expand Down
2 changes: 1 addition & 1 deletion hermes-console/json-server/topics.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[
{
"id": "pl.allegro.public.group.DummyEvent",
"schema": "{\"type\":\"record\",\"name\":\"DummyEvent\",\"namespace\":\"pl.allegro.public.group.DummyEvent\",\"doc\":\"Event emitted when notification is sent to a user\",\"fields\":[{\"name\":\"__metadata\",\"type\":[\"null\",{\"type\":\"map\",\"values\":\"string\"}],\"doc\":\"Field internally used by Hermes to propagate metadata.\",\"default\":null},{\"name\":\"waybillId\",\"type\":[\"null\",{\"type\":\"record\",\"name\":\"WaybillId\",\"fields\":[{\"name\":\"waybill\",\"type\":\"string\",\"doc\":\"Waybill\"},{\"name\":\"carrierId\",\"type\":\"string\",\"doc\":\"CarrierId\"}]}],\"doc\":\"WaybillId\",\"default\":null},{\"name\":\"notificationId\",\"type\":\"string\",\"doc\":\"Notification Id\"},{\"name\":\"userId\",\"type\":\"string\",\"doc\":\"User Id\"}]}",
"schema": "{\"type\":\"record\",\"name\":\"DummyEvent\",\"namespace\":\"pl.allegro.public.group.DummyEvent\",\"doc\":\"Event emitted when notification is sent to a user\",\"fields\":[{\"name\":\"__metadata\",\"type\":[\"null\",{\"type\":\"map\",\"values\":\"string\"}],\"doc\":\"Field internally used by Hermes to propagate metadata.\",\"default\":null},{\"name\":\"waybillId\",\"type\":[\"null\",{\"type\":\"record\",\"name\":\"WaybillId\",\"fields\":[{\"name\":\"waybill\",\"type\":\"string\",\"doc\":\"Waybill\"},{\"name\":\"carrierId\",\"type\":\"string\",\"doc\":\"CarrierId\"}]}],\"doc\":\"WaybillId\",\"default\":null},{\"name\":\"otherWaybillId\",\"type\":[\"null\",\"WaybillId\"],\"doc\":\"other WaybillId\",\"default\":null},{\"name\":\"notificationId\",\"type\":\"string\",\"doc\":\"Notification Id\"},{\"name\":\"userId\",\"type\":\"string\",\"doc\":\"User Id\"}]}",
"name": "pl.allegro.public.group.DummyEvent",
"description": "Events emitted when notification is sent to a user.",
"owner": {
Expand Down
2 changes: 1 addition & 1 deletion hermes-console/src/dummy/topic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { Owner } from '@/api/owner';

export const dummyTopic: TopicWithSchema = {
schema:
'{"type":"record","name":"DummyEvent","namespace":"pl.allegro.public.group.DummyEvent","doc":"Event emitted when notification is sent to a user","fields":[{"name":"__metadata","type":["null",{"type":"map","values":"string"}],"doc":"Field internally used by Hermes to propagate metadata.","default":null},{"name":"waybillId","type":["null",{"type":"record","name":"WaybillId","fields":[{"name":"waybill","type":"string","doc":"Waybill"},{"name":"carrierId","type":"string","doc":"CarrierId"}]}],"doc":"WaybillId","default":null},{"name":"notificationId","type":"string","doc":"Notification Id"},{"name":"userId","type":"string","doc":"User Id"}]}',
'{"type":"record","name":"DummyEvent","namespace":"pl.allegro.public.group.DummyEvent","doc":"Event emitted when notification is sent to a user","fields":[{"name":"__metadata","type":["null",{"type":"map","values":"string"}],"doc":"Field internally used by Hermes to propagate metadata.","default":null},{"name":"waybillId","type":["null",{"type":"record","name":"WaybillId","fields":[{"name":"waybill","type":"string","doc":"Waybill"},{"name":"carrierId","type":"string","doc":"CarrierId"}]}],"doc":"WaybillId","default":null},{"name":"otherWaybillId","type":["null","WaybillId"],"doc":"other WaybillId","default":null},{"name":"notificationId","type":"string","doc":"Notification Id"},{"name":"userId","type":"string","doc":"User Id"}]}',
name: 'pl.allegro.public.group.DummyEvent',
description: 'Events emitted when notification is sent to a user.',
owner: {
Expand Down
1 change: 1 addition & 0 deletions hermes-console/src/views/topic/schema-panel/AvroTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export interface AvroSchema {
type: Type;
name: string;
namespace: string;
doc: string;
fields?: Field[];
default?: DefaultTypes;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<script lang="ts" setup>
import { defineProps, ref } from 'vue';
import type { AvroSchema, Type } from '@/views/topic/schema-panel/AvroTypes';
import type {
AvroSchema,
RecordType,
Type,
} from '@/views/topic/schema-panel/AvroTypes';
const props = defineProps<{
field: AvroSchema;
recordReferenceTypes: Map<string, RecordType>;
root: boolean;
}>();
const expanded = ref(true);
Expand Down Expand Up @@ -61,11 +66,22 @@
if (type.type === 'map') return type.values.symbols;
};
const findRecordReference = (type: Type) => {
const types = Array.isArray(type) ? type : [type];
return types
.filter((type) => typeof type === 'string')
.map((typeName) => props.recordReferenceTypes.get(typeName))
.find((recordType) => !!recordType);
};
const types = getTypes(props.field.type);
const isRecord = types.some((type: Type) => type.includes('record'));
const recordReference = findRecordReference(props.field.type);
const isRecord =
!!recordReference || types.some((type: Type) => type.includes('record'));
const isEnum = types.some((type: Type) => type.includes('enum'));
const expandable = isRecord || isEnum;
const nestedType = isRecord && findNestedType(props.field.type);
const nestedType =
isRecord && (recordReference || findNestedType(props.field.type));
const enumSymbols = isEnum && findEnumSymbols(props.field.type);
const toggle = (event: Event) => {
Expand Down Expand Up @@ -100,6 +116,7 @@
v-for="nestedField in nestedType.fields"
:key="nestedField.name"
:field="nestedField"
:record-reference-types="props.recordReferenceTypes"
:root="false"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts" setup>
import { createRecordsRegistry } from '@/views/topic/schema-panel/avro-viewer/avro-records-registry';
import AvroNode from '@/views/topic/schema-panel/avro-viewer/AvroNode.vue';
import type { AvroSchema } from '@/views/topic/schema-panel/AvroTypes';
const props = defineProps<{
Expand All @@ -9,6 +10,7 @@
const jsonSchema: AvroSchema = JSON.parse(props.schema);
return {
name: jsonSchema.name,
namespace: jsonSchema.namespace,
doc: jsonSchema.doc,
type: {
type: 'record',
Expand All @@ -22,7 +24,12 @@

<template>
<div class="avro-schema">
<AvroNode v-if="rootField()" :field="rootField()" :root="true" />
<AvroNode
v-if="rootField()"
:field="rootField()"
:record-reference-types="createRecordsRegistry(rootField())"
:root="true"
/>
</div>
</template>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type {
AvroSchema,
RecordType,
} from '@/views/topic/schema-panel/AvroTypes';

interface WorkingRecord {
record: RecordType;
namespace?: string;
justName: string;
}

const namespace = (
schema: AvroSchema,
parentNamespace?: string,
): string | undefined => {
if (schema.name.includes('.')) {
const lastDotIndex = schema.name.lastIndexOf('.');
return schema.name.substring(0, lastDotIndex);
}
if (schema.namespace) {
return schema.namespace;
}
return parentNamespace;
};

const justRecordName = (schema: AvroSchema): string => {
if (schema.name.includes('.')) {
const lastDotIndex = schema.name.lastIndexOf('.');
return schema.name.substring(lastDotIndex + 1);
}
return schema.name;
};

const recordWithNamespace = (
record: RecordType,
parentNamespace?: string,
): WorkingRecord => {
return {
record,
namespace: namespace(record, parentNamespace),
justName: justRecordName(record),
};
};

const getDirectSubRecords = (parent: WorkingRecord): WorkingRecord[] => {
return parent.record.fields
.flatMap((field) => (Array.isArray(field.type) ? field.type : [field.type]))
.filter((field) => field.type === 'record')
.map((record) => recordWithNamespace(record, parent.namespace));
};

const getAllSubRecords = (
unprocessedRecords: WorkingRecord[],
processedRecords: WorkingRecord[],
): WorkingRecord[] => {
if (unprocessedRecords.length === 0) {
return processedRecords;
}
const currentLevelSubRecords =
unprocessedRecords.flatMap(getDirectSubRecords);
return getAllSubRecords(currentLevelSubRecords, [
...processedRecords,
...currentLevelSubRecords,
]);
};

const validQualifiers = (
record: WorkingRecord,
rootNamespace?: string,
): string[] => {
if (!record.namespace) {
return [record.justName];
}
if (record.namespace === rootNamespace) {
return [record.justName, `${record.namespace}.${record.justName}`];
}
return [`${record.namespace}.${record.justName}`];
};

const associateByValidQualifiers = (
records: WorkingRecord[],
rootNamespace?: string,
): Map<string, RecordType> => {
return new Map(
records.flatMap((record) => {
return validQualifiers(record, rootNamespace).map((qualifier) => [
qualifier,
record.record,
]);
}),
);
};

export const createRecordsRegistry = (
schema: AvroSchema,
): Map<string, RecordType> => {
const workingRootRecord = recordWithNamespace({
...schema.type,
name: schema.name,
namespace: schema.namespace,
});
const allRecords = getAllSubRecords([workingRootRecord], []);
return associateByValidQualifiers(allRecords, workingRootRecord.namespace);
};

0 comments on commit 419d7b7

Please sign in to comment.