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

[utils] add util for converting between es and kibana types #11967

Merged
merged 12 commits into from
May 24, 2017

Conversation

spalger
Copy link
Contributor

@spalger spalger commented May 23, 2017

In order to share the same es<->kibana type conversion rules on the server and client this:

  • moves the _cast_mapping_type module from the ui/index_patterns into src/utils
  • exposes functions for things like getEsTypes(), rather than port IndexedArray to the server
  • merges logic from src/ui/public/index_patterns/_field_types.js

this.sortable = !!sortable;
this.filterable = !!filterable;
this.esTypes = Object.freeze(esTypes || []);
Object.freeze(this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling Object.freeze in a constructor probably isn't a great pattern to get into the habit of using. If another class wanted to extend this one the freeze would prevent it from doing so. I suppose it's not particularly important in this instance though, it's unlikely anyone will want to extend this class.

Copy link
Contributor Author

@spalger spalger May 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Freezing the field type instances is basically the whole reason this constructor exists, and it's only exported so it can be used in the tests. If subclassing was something we wanted to do then extensions would have to comply with the limitation (attach getters/setters/methods to the prototype) or update the KbnFieldType class. I'm fine with that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just playing around with Object.freeze() in another context and, unfortunately, I don't think it's a good idea to use it since it prevents angular from rendering it in an ng-repeat, which requires adding a unique $$hashKey to the object... I'll do something else.

});

it('returns undefined for invalid name', () => {
expect(getKbnFieldType(Math.random())).to.be(undefined);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding randomness to a test like this doesn't seem like a good idea to me. What if it behaves differently if you pass in 0 vs 42? Also what makes the name invalid? Is it the fact that you're passing a non-string? If that's the case I would say 'returns undefined for non-string arguments'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generally hesitate to use static strings for "invalid" values, so I wanted to use a little randomness and got lazy.

});

it('returns unknown for unknown es types', () => {
expect(castEsToKbnFieldTypeName(Math.random())).to.be('unknown');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make more sense to test a string parameter here?


describe('castEsToKbnFieldType()', () => {
it('returns the kbnFieldType instance that matches the esType', () => {
expect(castEsToKbnFieldType('keyword')).to.be.a(KbnFieldType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is testing that the returned value is a KbnFieldType but not whether it is the correct KbnFieldType.

});

it('returns the unknown field type for unknown es types', () => {
expect(castEsToKbnFieldType(Math.random())).to.be(getKbnFieldType('unknown'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question about using a string param as above

@@ -21,7 +21,7 @@ uiModules
const fieldTypesByLang = {
painless: ['number', 'string', 'date', 'boolean'],
expression: ['number'],
default: _.keys(Private(IndexPatternsCastMappingTypeProvider).types.byType)
default: getEsTypes()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a list of Kibana types, not ES types.

if (!_.has(field, 'sortable')) field.sortable = type.sortable;
if (!_.has(field, 'filterable')) field.filterable = type.filterable;
return field;
const kbnType = castEsToKbnFieldType(field.type);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is always returning the unknown field type because field.type already has the kibana type name.

@spalger
Copy link
Contributor Author

spalger commented May 23, 2017

Thanks for the review @Bargs, everything should be resolved.

Object.freeze() keeps properties of an object from being redefined or removed, which we want for the kbnFieldTypes, but it also prevents them from being iterated by angular since angular needs to add a unique `$hashKey` property to each object. To keep the properties read only but allow extension KbnFieldType uses Object.defineProperties() instead.
@spalger spalger force-pushed the share/es-kbn-type-conversion branch from a33c795 to 2b65f6c Compare May 24, 2017 01:10
@spalger spalger requested review from kimjoar and removed request for BigFunger May 24, 2017 16:57
spalger added a commit to spalger/kibana that referenced this pull request May 24, 2017
@spalger spalger added the review label May 24, 2017
Copy link
Contributor

@kimjoar kimjoar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor nitpicks, but just feel free to skip them. LGTM

esTypes = []
} = options;

Object.defineProperties(this, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit meh, but I understand why, so I'm good with it. If this is what we have to do to have immutable objects, this is what we do.

* @return {Array<string>}
*/
export function getKbnTypeNames() {
return KBN_FIELD_TYPES.map(type => type.name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost feels like we should make KBN_FIELD_TYPES an object keyed on the name. That would make this and getKbnFieldType simpler. Not a big deal, though.

Copy link
Contributor Author

@spalger spalger May 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a thing about storing lists of objects in anything other than an array 😷 . But I would be fine creating a secondary object like KBN_FIELD_TYPES_BY_NAME or something.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries. I'm fine with keeping this as-is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it's fine as-is, but just to be philosophical about things, this is a scenario where a Map would be useful no?

Copy link
Contributor Author

@spalger spalger May 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An extra map, for optimizing access by name, sure. But there are other types of access we might want to optimize for. And these optimizations are definitely on the nano-scale

@@ -51,6 +53,10 @@ function stubbedLogstashFields() {
scripted = !!script,
} = metadata;

const type = (esType === 'conflict' || esType === 'unknown')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

esType can never be unknown here.

Also, what is conflict and why is it special-cased here? (instead of being handled within castEsToKbnFieldTypeName)

(maybe just add a comment above this line that describes why we're special-casing these?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, unknown is not possible here. The conflict type isn't from es, but is a special kbnFieldType, but we don't have any other way of representing here.

.when('GET', '/api/kibana/scripts/languages')
.respond(['expression', 'painless']);
getScriptedLangsResponse = $httpBackend.when('GET', '/api/kibana/scripts/languages');
getScriptedLangsResponse.respond(['expression', 'painless']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference in beforeEach: if it gets overridden in any test, it should always be handled within each test (so I only beforeEach something if it concerns all the tests it covers, otherwise I find it just becomes more difficult to track the state of things)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to do something like this at first but it just spiraled out of control and changed way too much stuff.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, just skip it if it adds noise to this PR


describe('getKbnTypeNames()', () => {
it('returns a list of all kbnFieldType names', () => {
const esTypes = getKbnTypeNames();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just .sort() this and do an equals check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention was more about not duplicating the whole list of kbnType names, but I'm fine with it. The list will basically never change

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is perfect for snapshot testing 🎉 (you don't want to maintain the list yourself really, you just want to make sure you have something that fails if the list changes)

@kimjoar
Copy link
Contributor

kimjoar commented May 24, 2017

:shipit:

@Bargs
Copy link
Contributor

Bargs commented May 24, 2017

LGTM

@spalger spalger merged commit c9afc8b into elastic:master May 24, 2017
spalger added a commit to spalger/kibana that referenced this pull request May 24, 2017
…11967)

* [utils] add util for converting between es and kibana types

* [utils/kbnFieldTypes] use random strings instead of numbers

* [utils/kbnFieldTypes] ensure that castEsToKbnFieldType() returns correct instance

* [utils/kbnFieldTypes] change getEsTypes() -> getKbnTypeNames()

* [fieldEditor] update test to validate limited type support

* [fieldEditor] unexpected scripted field langs should list all kbn types

* [test/stubbedLogstashIndexPattern] fix kbnFieldType use

* [utils/kbnFieldTypes] remove unused castEsToKbnFieldType() fn

* [utils/kbnFieldTypes] don't use Object.freeze()

Object.freeze() keeps properties of an object from being redefined or removed, which we want for the kbnFieldTypes, but it also prevents them from being iterated by angular since angular needs to add a unique `$hashKey` property to each object. To keep the properties read only but allow extension KbnFieldType uses Object.defineProperties() instead.

* [fixtures/logstashFields] fix use of "unknown" and "conflict" types

* [stubs/logstashFields] mention why "conflict" is special

* [utils/kbnFieldTypes] check complete output of getKbnTypeNames()

(cherry picked from commit c9afc8b)
spalger added a commit that referenced this pull request May 25, 2017
…1967) (#11993)

* [utils] add util for converting between es and kibana types (#11967)

* [utils] add util for converting between es and kibana types

* [utils/kbnFieldTypes] use random strings instead of numbers

* [utils/kbnFieldTypes] ensure that castEsToKbnFieldType() returns correct instance

* [utils/kbnFieldTypes] change getEsTypes() -> getKbnTypeNames()

* [fieldEditor] update test to validate limited type support

* [fieldEditor] unexpected scripted field langs should list all kbn types

* [test/stubbedLogstashIndexPattern] fix kbnFieldType use

* [utils/kbnFieldTypes] remove unused castEsToKbnFieldType() fn

* [utils/kbnFieldTypes] don't use Object.freeze()

Object.freeze() keeps properties of an object from being redefined or removed, which we want for the kbnFieldTypes, but it also prevents them from being iterated by angular since angular needs to add a unique `$hashKey` property to each object. To keep the properties read only but allow extension KbnFieldType uses Object.defineProperties() instead.

* [fixtures/logstashFields] fix use of "unknown" and "conflict" types

* [stubs/logstashFields] mention why "conflict" is special

* [utils/kbnFieldTypes] check complete output of getKbnTypeNames()

(cherry picked from commit c9afc8b)

* [fieldEditor] remove test that only applies to 6.0+
snide pushed a commit to snide/kibana that referenced this pull request May 30, 2017
…11967)

* [utils] add util for converting between es and kibana types

* [utils/kbnFieldTypes] use random strings instead of numbers

* [utils/kbnFieldTypes] ensure that castEsToKbnFieldType() returns correct instance

* [utils/kbnFieldTypes] change getEsTypes() -> getKbnTypeNames()

* [fieldEditor] update test to validate limited type support

* [fieldEditor] unexpected scripted field langs should list all kbn types

* [test/stubbedLogstashIndexPattern] fix kbnFieldType use

* [utils/kbnFieldTypes] remove unused castEsToKbnFieldType() fn

* [utils/kbnFieldTypes] don't use Object.freeze()

Object.freeze() keeps properties of an object from being redefined or removed, which we want for the kbnFieldTypes, but it also prevents them from being iterated by angular since angular needs to add a unique `$hashKey` property to each object. To keep the properties read only but allow extension KbnFieldType uses Object.defineProperties() instead.

* [fixtures/logstashFields] fix use of "unknown" and "conflict" types

* [stubs/logstashFields] mention why "conflict" is special

* [utils/kbnFieldTypes] check complete output of getKbnTypeNames()
jsoref referenced this pull request in jsoref/kibana Jun 21, 2018
@spalger spalger deleted the share/es-kbn-type-conversion branch October 18, 2019 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants