Skip to content

Commit

Permalink
feat(names): domainValueObject to domainLiteral, for intuition++ (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
uladkasach authored May 26, 2024
1 parent 602c406 commit c1b0eef
Show file tree
Hide file tree
Showing 17 changed files with 58 additions and 58 deletions.
6 changes: 3 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Consequently, by utilizing the schema generator:
- you can comfortably modify any generated schema to support edge cases or differences in opinion not already supported by the library, as you fully manage the sql that was generated

### Inspiration
- [Domain Driven Design](https://dddcommunity.org/learning-ddd/what_is_ddd/): domain driven design provides tools to define the Domain Model in a ubiquitous language (Entities, Value Objects, etc), which increase increases the maintainability and utility of the infrastructure you spend time building.
- [Domain Driven Design](https://dddcommunity.org/learning-ddd/what_is_ddd/): domain driven design provides tools to define the Domain Model in a ubiquitous language (Entities, Literals, etc), which increase increases the maintainability and utility of the infrastructure you spend time building.
- [Temporal Database Design](https://dba.stackexchange.com/a/114738/75296): temporal database design provides a way to optimally implement the "insert only" data lifecycle pattern, retaining the changes an entity goes through over time while also maintaining foreign keys, uniqueness constraints, and normalization.

# Usage
Expand All @@ -72,9 +72,9 @@ Consequently, by utilizing the schema generator:
```ts
// for example: in <root>/schema/entities.ts

import { Entity, prop, ValueObject } from '../module';
import { Entity, prop, Literal } from '../module';

const photo = new ValueObject({
const photo = new Literal({
name: 'photo',
properties: {
url: prop.VARCHAR(),
Expand Down
4 changes: 2 additions & 2 deletions src/contract/__test_assets__/domain.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Event } from '../../domain';
import { Entity, prop, ValueObject } from '../module';
import { Entity, prop, Literal } from '../module';

const photo = new ValueObject({
const photo = new Literal({
name: 'photo',
properties: {
url: prop.VARCHAR(255),
Expand Down
2 changes: 1 addition & 1 deletion src/contract/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export {
Entity,
Event,
Property,
ValueObject,
Literal,
} from '../domain';
export { prop } from '../logic/define';
2 changes: 1 addition & 1 deletion src/domain/objects/Event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Property } from './Property';
interface EventConstructorProps {
name: string;
properties: {
[index: string]: Omit<Property, 'updatable'>; // by definition, value objects are not updatable
[index: string]: Omit<Property, 'updatable'>; // by definition, literals are not updatable
};
unique: string[];
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { DataTypeName } from '../constants';
import { DataType } from './DataType';
import { Literal } from './Literal';
import { Property } from './Property';
import { ValueObject } from './ValueObject';

describe('ValueObject', () => {
describe('Literal', () => {
const type = new DataType({
name: DataTypeName.VARCHAR,
precision: 255,
});
it('should be possible to initialize with valid data', () => {
const address = new ValueObject({
const address = new Literal({
name: 'address',
properties: {
name: new Property({
Expand All @@ -19,12 +19,12 @@ describe('ValueObject', () => {
}),
},
});
expect(address).toBeInstanceOf(ValueObject);
expect(address).toBeInstanceOf(Literal);
});
it('should throw an error if the property is "updatable"', () => {
try {
// tslint:disable-next-line: no-unused-expression
new ValueObject({
new Literal({
name: 'address',
properties: {
name: new Property({
Expand All @@ -37,7 +37,7 @@ describe('ValueObject', () => {
throw new Error('should not reach here');
} catch (error) {
expect(error.message).toEqual(
'value objects can not have updateable properties, by definition',
'literals can not have updateable properties, by definition',
);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { Entity } from './Entity';
import { Property } from './Property';

/*
turns out: Domain Value Objects, from a persistance perspective, are just like Domain Entities - except with more constraints:
turns out: Domain Literals, from a persistance perspective, are just like Domain Entities - except with more constraints:
- i.e., no updatable values
- i.e., it is unique on all properties
*/
interface ValueObjectConstructorProps {
interface LiteralConstructorProps {
name: string;
properties: {
[index: string]: Omit<Property, 'updatable'>; // by definition, value objects are not updatable
[index: string]: Omit<Property, 'updatable'>; // by definition, literals are not updatable
};
}
export class ValueObject extends Entity {
constructor(props: ValueObjectConstructorProps) {
export class Literal extends Entity {
constructor(props: LiteralConstructorProps) {
// 1. check that all the properties are immutable; this shouldn't be allowed w/ type checking but lets run time validate it too
const updateableProperties = Object.keys(props.properties).filter(
(propertyName) => {
Expand All @@ -24,7 +24,7 @@ export class ValueObject extends Entity {
);
if (updateableProperties.length)
throw new Error(
'value objects can not have updateable properties, by definition',
'literals can not have updateable properties, by definition',
);

// 2. define the unique condition automatically, as all properties
Expand Down
2 changes: 1 addition & 1 deletion src/domain/objects/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { DataType } from './DataType';
export { Property } from './Property';
export { Entity, Properties } from './Entity';
export { ValueObject } from './ValueObject';
export { Literal } from './Literal';
export { Event } from './Event';
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Entity, ValueObject } from '../../../../domain';
import { Entity, Literal } from '../../../../domain';
import * as prop from '../../../define/defineProperty';
import { generateAndRecordEntitySchema } from './generateAndRecordEntitySchema';
import { readFile } from './utils/fileIO';

describe('generateAndRecordEntitySchema', () => {
const targetDirPath = `${__dirname}/__test_assets__/generated`;
it('should record all resources for a value object (i.e., non updatable entity)', async () => {
const address = new ValueObject({
it('should record all resources for a literal (i.e., non updatable entity)', async () => {
const address = new Literal({
name: 'address',
properties: {
street: prop.VARCHAR(255),
Expand Down Expand Up @@ -105,13 +105,13 @@ describe('generateAndRecordEntitySchema', () => {
expect(viewCurrentSql).toContain('CREATE OR REPLACE VIEW');
});
it('should record all resources for an updatable entity with array properties', async () => {
const language = new ValueObject({
const language = new Literal({
name: 'language',
properties: {
name: prop.VARCHAR(255),
},
});
const producer = new ValueObject({
const producer = new Literal({
name: 'producer',
properties: {
name: prop.VARCHAR(255),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Entity, ValueObject } from '../../../../domain';
import { Entity, Literal } from '../../../../domain';
import { prop } from '../../../define';
import { normalizeDeclarationContents } from './normalizeDeclarationContents';
import { throwErrorIfAnyReservedPropertyNamesAreUsed } from './throwErrorIfAnyReservedPropertyNamesAreUsed';
Expand Down Expand Up @@ -34,7 +34,7 @@ describe('normalizeDeclarationContents', () => {
);
}
});
it('throw an error if entities are not all of class Entity or ValueObject', () => {
it('throw an error if entities are not all of class Entity or Literal', () => {
const contents = { entities: ['not an Entity'] };
try {
normalizeDeclarationContents({ contents });
Expand Down Expand Up @@ -101,12 +101,12 @@ describe('normalizeDeclarationContents', () => {
entity: exampleEntity,
});
});
it('should return the entities and value objects found in the contents', () => {
const plant = new ValueObject({
it('should return the entities and literals found in the contents', () => {
const plant = new Literal({
name: 'plant',
properties: { genus: prop.VARCHAR(255) },
});
const vase = new ValueObject({
const vase = new Literal({
name: 'vase',
properties: { plants: prop.ARRAY_OF(prop.REFERENCES(plant)) },
});
Expand All @@ -131,12 +131,12 @@ describe('normalizeDeclarationContents', () => {
// check that we return everything as expected
expect(entities).toEqual([plant, vase, customer, order]);
});
it('should return the entities and value objects found in the contents - when specified with the generateSqlSchemasFor syntax', () => {
const plant = new ValueObject({
it('should return the entities and literals found in the contents - when specified with the generateSqlSchemasFor syntax', () => {
const plant = new Literal({
name: 'plant',
properties: { genus: prop.VARCHAR(255) },
});
const vase = new ValueObject({
const vase = new Literal({
name: 'vase',
properties: { plants: prop.ARRAY_OF(prop.REFERENCES(plant)) },
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Entity, ValueObject } from '../../../../../domain';
import { Entity, Literal } from '../../../../../domain';
import { prop } from '../../../../define';
import { throwErrorIfAnyReferencePropertyDoesNotHaveExplicitSuffix } from './throwErrorIfAnyReferencePropertyDoesNotHaveExplicitSuffix';

describe('throwErrorIfAnyReferencePropertyDoesNotHaveExplicitSuffix', () => {
it('should throw an error if property references another but does not have correct name', () => {
const photo = new ValueObject({
const photo = new Literal({
name: 'photo',
properties: { url: prop.VARCHAR(255) },
});
Expand All @@ -25,7 +25,7 @@ describe('throwErrorIfAnyReferencePropertyDoesNotHaveExplicitSuffix', () => {
}
});
it('should throw an error if an array property references another but does not have correct name', () => {
const photo = new ValueObject({
const photo = new Literal({
name: 'photo',
properties: { url: prop.VARCHAR(255) },
});
Expand All @@ -49,7 +49,7 @@ describe('throwErrorIfAnyReferencePropertyDoesNotHaveExplicitSuffix', () => {
}
});
it('should not throw an error for an entity with correctly named reference properties', () => {
const photo = new ValueObject({
const photo = new Literal({
name: 'photo',
properties: { url: prop.VARCHAR(255) },
});
Expand Down
4 changes: 2 additions & 2 deletions src/logic/define/defineProperty.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DataTypeName, Entity, Property, ValueObject } from '../../domain';
import { DataTypeName, Entity, Property, Literal } from '../../domain';
import * as prop from './defineProperty';

describe('generateProperty', () => {
Expand Down Expand Up @@ -28,7 +28,7 @@ describe('generateProperty', () => {
});
});
it('should throw an error if entity REFERENCES_VERSION of a non-updatable entity', () => {
const apple = new ValueObject({
const apple = new Literal({
name: 'apple',
properties: {
name: prop.VARCHAR(255), // e.g., Granny Smith
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { pg as prepare } from 'yesql';
import { normalizeCreateFunctionDdl } from '../../../../__nonpublished_modules__/postgres-show-create-ddl/showCreateFunction/normalizeCreateFunctionDdl';
import { getShowCreateFunction } from '../../../../__test_utils__/getShowCreateFunction';
import { uuid as uuidV4 } from '../../../../deps';
import { Entity, ValueObject } from '../../../../domain';
import { Entity, Literal } from '../../../../domain';
import * as prop from '../../../define/defineProperty';
import {
createTablesForEntity,
Expand Down Expand Up @@ -444,13 +444,13 @@ describe('generateEntityUpsert', () => {
});

describe('entity with array properties', () => {
const language = new ValueObject({
const language = new Literal({
name: 'language',
properties: {
name: prop.VARCHAR(),
},
});
const producer = new ValueObject({
const producer = new Literal({
name: 'producer',
properties: {
name: prop.VARCHAR(),
Expand Down Expand Up @@ -1138,10 +1138,10 @@ describe('generateEntityUpsert', () => {
},
unique: ['make', 'model', 'year'],
});
const crashReport = new ValueObject({
const crashReport = new Literal({
name: 'crash_report',
properties: {
location_id: prop.BIGINT(), // this should reference a real "location" value object, but for this example lets just leave it as a bigint
location_id: prop.BIGINT(), // this should reference a real "location" literal, but for this example lets just leave it as a bigint
vehicle_version_id: prop.REFERENCES_VERSION(vehicle), // reference the specific vehicle version, as maybe a software glitch is causing the crashes
},
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ValueObject } from '../../../../../domain';
import { Literal } from '../../../../../domain';
import { prop } from '../../../../define';
import { castPropertyToFunctionInputDefinition } from './castPropertyToFunctionInputDefinition';

Expand All @@ -11,7 +11,7 @@ describe('castPropertyToFunctionInputDefinition', () => {
expect(definition).toMatchSnapshot();
});
it('should define the definition accurately for an array property', () => {
const tag = new ValueObject({
const tag = new Literal({
name: 'tag',
properties: { name: prop.VARCHAR(255) },
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Entity, ValueObject } from '../../../../../domain';
import { Entity, Literal } from '../../../../../domain';
import { prop } from '../../../../define';
import { castPropertyToWhereClauseConditional } from './castPropertyToWhereClauseConditional';

describe('castPropertyToWhereClauseConditional', () => {
const user = new ValueObject({
const user = new Literal({
name: 'user',
properties: { name: prop.VARCHAR(255) },
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
getDatabaseConnection,
} from '../../../__test_utils__/databaseConnection';
import { getShowCreateTable } from '../../../__test_utils__/getShowCreateTable';
import { Entity, ValueObject } from '../../../domain';
import { Entity, Literal } from '../../../domain';
import * as prop from '../../define/defineProperty';
import { createTablesForEntity, dropTablesForEntity } from '../__test_utils__';
import { generateEntityTables } from './generateEntityTables';
Expand Down Expand Up @@ -170,13 +170,13 @@ describe('generateEntityTables', () => {
expect(createVersionTable).toEqual(tables.version!.sql); // should be the exact string
});
it('generates tables for an entity with array properties (both updatable and static) and unique on one array, w/ the same syntax as show create', async () => {
const photo = new ValueObject({
const photo = new Literal({
name: 'photo',
properties: {
url: prop.VARCHAR(255),
},
});
const host = new ValueObject({
const host = new Literal({
name: 'host',
properties: {
name: prop.VARCHAR(255),
Expand Down
6 changes: 3 additions & 3 deletions src/logic/generate/entityTables/generateEntityTables.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Entity, ValueObject } from '../../../domain';
import { Entity, Literal } from '../../../domain';
import * as prop from '../../define/defineProperty';
import { generateEntityTables } from './generateEntityTables';
import { generateMappingTablesForArrayProperties } from './generateMappingTablesForArrayProperties';
Expand Down Expand Up @@ -88,13 +88,13 @@ describe('generateEntityTables', () => {
);
});
it('should generateMappingTablesForArrayProperties for the array properties only', () => {
const language = new ValueObject({
const language = new Literal({
name: 'language',
properties: {
name: prop.VARCHAR(255),
},
});
const producer = new ValueObject({
const producer = new Literal({
name: 'producer',
properties: {
name: prop.VARCHAR(255),
Expand Down
Loading

0 comments on commit c1b0eef

Please sign in to comment.