Defining enumerations is directly supported in information modeling languages (such as in UML Class Diagrams), in data schema languages (such as in XML Schema, but not in SQL), and in many programming languages (such as in C++ and Java, but not in JavaScript).
Unfortunately, standard SQL does not support enumerations. Some DBMS, such as MySQL and Postgres, provide their own extensions of SQL column definitions in the CREATE TABLE statement allowing to define enumeration-valued columns.
A MySQL
enumeration is specified as a list of enumeration labels with the keyword
ENUM
within a column definition, like
so:
CREATE TABLE people ( name VARCHAR(40), gender ENUM('MALE', 'FEMALE', 'UNDETERMINED') );
A Postgres enumeration is specified as a special user-defined type that can be used in columns definitions:
CREATE TYPE GenderEL AS ENUM ('MALE', 'FEMALE', 'UNDETERMINED'); CREATE TABLE people ( name text, gender GenderEL )
In XML Schema, an enumeration datatype can be defined as a simple type restricting the
primitive type xs:string
in the following way:
<xs:simpleType name="BookCategoryEL"> <xs:restriction base="xs:string"> <xs:enumeration value="NOVEL"/> <xs:enumeration value="BIOGRAPHY"/> <xs:enumeration value="TEXTBOOK"/> <xs:enumeration value="OTHER"/> </xs:restriction> </xs:simpleType>
We can implement an enumeration in the form of a special JavaScript object definition using
the Object.defineProperties
method:
var BookCategoryEL = null; Object.defineProperties( BookCategoryEL, { NOVEL: {value: 1, writable: false}, BIOGRAPHY: {value: 2, writable: false}, TEXTBOOK: {value: 3, writable: false}, OTHER: {value: 4, writable: false}, MAX: {value: 4, writable: false}, labels: {value:["novel","biography","textbook","other"], writable: false} });
This definition allows using the enumeration literals BookCategoryEL.NOVEL
,
BookCategoryEL.BIOGRAPHY
etc., standing for the enumeration indexes 1, 2 , 3 and
4, in program statements. Notice how this definition takes care of the requirement that
enumeration literals like BookCategoryEL.NOVEL
are constants, the value of which
cannot be changed during program execution. This is achieved with the help of the property
descriptor writable: false
in the Object.defineProperties
statement.
We can also use a generic approach and define a meta-class Enumeration
for
creating enumerations in the form of special JS objects:
function Enumeration( enumLabels) { var i=0, LBL=""; this.MAX = enumLabels.length; this.labels = enumLabels; // generate the enum literals as capitalized keys/properties for (i=1; i <= enumLabels.length; i++) { LBL = enumLabels[i-1].toUpperCase(); this[LBL] = i; } // prevent any runtime change to the enumeration Object.freeze( this); };
Using
this Enumeration
class allows to define a new enumeration in the following way:
var BookCategoryEL = new Enumeration(["novel","biography","textbook","other"])
Having an enumeration like BookCategoryEL
, we can then check if an enumeration
attribute like category
has an admissible value by testing if its value is not
smaller than 1 and not greater than BookCategoryEL.MAX
. Also, the label can be
retrieved in the following way:
formEl.category.value = BookCategoryEL.labels[this.category - 1];
As an example, we consider the following model class Book
with the enumeration
attribute category
:
function Book( slots) { this.isbn = ""; // string this.title = ""; // string this.category = 0; // number (BookCategoryEL) if (arguments.length > 0) { this.setIsbn( slots.isbn); this.setTitle( slots.title); this.setCategory( slots.category); } };
For validating input values for the enumeration attribute category
, we can use
the following check function:
Book.checkCategory = function (c) { if (!c) { return new MandatoryValueConstraintViolation( "A category must be provided!"); } else if (!Number.isInteger(c) || c < 1 || c > BookCategoryEL.MAX) { return new RangeConstraintViolation( "The category must be a positive integer " + "not greater than "+ BookCategoryEL.MAX +" !"); } else { return new NoConstraintViolation(); } };
Notice how the range constraint defined by the enumeration BookCategoryEL
is
checked: it is tested if the input value c
is a positive integer and if it is not
greater than BookCategoryEL.MAX
.