Skip to content

Commit

Permalink
apply inverseTransform + typeHidden after repo sync
Browse files Browse the repository at this point in the history
  • Loading branch information
brahimmouhamou committed Jun 22, 2022
1 parent a86b7a8 commit 611b08e
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 18 deletions.
6 changes: 5 additions & 1 deletion src/__tests__/entities/test-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export = {
test_string_set_type_coerce: { type: 'set', setType: 'string', coerce: true },
test_number_set_type_coerce: { type: 'set', setType: 'number', coerce: true },
test_binary: { type: 'binary' },
simple_string: 'string'
simple_string: 'string',
inverse_transformed_simple_string: {
type: "string",
inverseTransform: (input: string) => input.toUpperCase(),
},
}
}
43 changes: 43 additions & 0 deletions src/__tests__/entity-creation.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,49 @@ describe('Entity creation', ()=> {
expect(result).toThrow(`Please provide a valid entity definition`)
})

it("creates an attribute with a inverseTransformation function", async () => {
// Create basic table
const TestTable = new Table({
name: "test-table",
partitionKey: "pk",
sortKey: "sk",
DocumentClient,
});

// Create basic entity
const TestEntity = new Entity({
name: "TestEnt",
attributes: {
pk: {
partitionKey: true,
inverseTransform: (val) => val.toUpperCase(),
default: "pkDef",
},
test: {
inverseTransform: (val, data) => {
return val.toUpperCase();
},
default: () => "defaultVal",
},
sk: { type: "string", sortKey: true },
testx: ["sk", 0],
testy: [
"sk",
1,
{
default: () => "testDefaultX",
inverseTransform: (val) => {
return "__" + val.toUpperCase();
},
},
],
},
table: TestTable,
timestamps: false,
})
})



// it('creates entity w/ table', async () => {

Expand Down
17 changes: 10 additions & 7 deletions src/__tests__/entity.parse.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ const TestTable = new Table({
describe('parse',()=>{

it('parses single item', ()=>{
let item = TestEntity.parse({ pk: '[email protected]', sk: 'email', test_string: 'test', _et: 'TestEntity' })
let item = TestEntity.parse({ pk: '[email protected]', sk: 'email', test_string: 'test', inverse_transformed_simple_string: "transformed", _et: 'TestEntity' })
expect(item).toEqual({
email: '[email protected]',
test_type: 'email',
test_string: 'test',
inverse_transformed_simple_string: "TRANSFORMED",
entity: 'TestEntity'
})
})
Expand All @@ -41,19 +42,21 @@ describe('parse',()=>{

it('parses multiple items', ()=>{
let items = TestEntity.parse([
{ pk: '[email protected]', sk: 'email', test_string: 'test' },
{ pk: '[email protected]', sk: 'email2', test_string: 'test2' }
{ pk: '[email protected]', sk: 'email', test_string: 'test', inverse_transformed_simple_string: "transformed", },
{ pk: '[email protected]', sk: 'email2', test_string: 'test2', inverse_transformed_simple_string: "transformed", }
])
expect(items).toEqual([
{
email: '[email protected]',
test_type: 'email',
test_string: 'test'
test_string: 'test',
inverse_transformed_simple_string: "TRANSFORMED",
},
{
email: '[email protected]',
test_type: 'email2',
test_string: 'test2'
test_string: 'test2',
inverse_transformed_simple_string: "TRANSFORMED",
}
])
})
Expand All @@ -76,11 +79,11 @@ describe('parse',()=>{
})

it('parses composite field', ()=>{
let item = SimpleEntity.parse({ pk: '[email protected]', sk: 'active#email', test_composite: 'test' })
let item = SimpleEntity.parse({ pk: '[email protected]', sk: 'active#email', test_composite: 'test' })
expect(item).toEqual({
pk: '[email protected]',
test_composite: 'test',
test_composite2: 'email'
test_composite2: 'email',
})
})

Expand Down
2 changes: 2 additions & 0 deletions src/__tests__/parseEntity.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const entity: EntityConstructor = {
modified: '_modified',
modifiedAlias: 'modifiedAlias',
typeAlias: 'typeAlias',
typeHidden: true,
attributes: {
pk: { partitionKey: true },
sk: { sortKey: true },
Expand All @@ -38,6 +39,7 @@ describe('parseEntity', () => {
expect(ent.autoExecute).toBe(true)
expect(ent.autoParse).toBe(true)
expect(ent._etAlias).toBe('typeAlias')
expect(ent.typeHidden).toBe(true)
})

it('fails on extra config option', async () => {
Expand Down
5 changes: 4 additions & 1 deletion src/classes/Entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ export interface EntityConstructor {
autoExecute?: boolean
autoParse?: boolean
table?: Table
typeHidden?: boolean;
}

export interface EntityAttributeConfig {
type?: DynamoDBTypes
default?: any | ((data: object) => any)
dependsOn?: string | string[]
transform?: (value: any, data: {}) => any
inverseTransform?: (value: any, data: {}) => any
coerce?: boolean
save?: boolean
onUpdate?: boolean
Expand Down Expand Up @@ -139,6 +141,7 @@ class Entity<
public defaults: any
public linked: any
public required: any
public typeHidden!: boolean

// Declare constructor (entity config)
constructor(entity: EntityConstructor) {
Expand Down Expand Up @@ -172,7 +175,7 @@ class Entity<

// If an entity tracking field is enabled, add the attributes, alias and the default
if (table.Table.entityField) {
this.schema.attributes[table.Table.entityField] = { type: 'string', alias: this._etAlias, default: this.name } as EntityAttributeConfig
this.schema.attributes[table.Table.entityField] = { type: 'string', hidden: this.typeHidden, alias: this._etAlias, default: this.name } as EntityAttributeConfig
this.defaults[table.Table.entityField] = this.name
this.schema.attributes[this._etAlias] = { type: 'string', map: table.Table.entityField, default: this.name } as EntityAttributeConfig
this.defaults[this._etAlias] = this.name
Expand Down
2 changes: 1 addition & 1 deletion src/classes/Table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class Table {
// Validate and sets the document client (extend with options.convertEmptyValues because it's not typed)
set DocumentClient(docClient: (DocumentClient & { options?: { convertEmptyValues: boolean}}) | undefined) {
// If a valid document client
if (docClient && docClient.get && docClient.put && docClient.delete && docClient.update) {
if (docClient) {
// Automatically set convertEmptyValues to true, unless false
if (docClient.options!.convertEmptyValues !== false)
docClient.options!.convertEmptyValues = true
Expand Down
33 changes: 25 additions & 8 deletions src/lib/formatItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,32 @@ export default (DocumentClient: DocumentClient) => (attributes: { [key:string] :

if ((attributes[field] && attributes[field].hidden) || (include.length > 0 && !include.includes(field))) return acc
// Extract values from sets
if (attributes[field] && attributes[field].type === 'set' && Array.isArray(item[field].values)) { item[field] = item[field].values }
return Object.assign(acc,{
[(attributes[field] && attributes[field].alias) || field]: (
attributes[field] && (attributes[field].prefix || attributes[field].suffix)
if (attributes[field] && attributes[field].type === 'set' && Array.isArray(item[field].values)) { item[field] = item[field].values }

const fieldValue =
attributes[field] &&
(attributes[field].prefix || attributes[field].suffix)
? item[field]
.replace(new RegExp(`^${escapeRegExp(attributes[field].prefix!)}`),'')
.replace(new RegExp(`${escapeRegExp(attributes[field].suffix!)}$`),'')
: item[field]
)
.replace(
new RegExp(`^${escapeRegExp(attributes[field].prefix!)}`),
""
)
.replace(
new RegExp(`${escapeRegExp(attributes[field].suffix!)}$`),
""
)
: item[field];

const transformedValue =
attributes[field] && attributes[field].inverseTransform
? (
attributes[field] as Required<EntityAttributeConfig>
).inverseTransform(fieldValue, item)
: fieldValue

return Object.assign(acc, {
[(attributes[field] && attributes[field].alias) || field]:
transformedValue,
})
},{})
}
Expand Down
5 changes: 5 additions & 0 deletions src/lib/parseEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export function parseEntity(entity: EntityConstructor) {
modified,
modifiedAlias,
typeAlias,
typeHidden,
attributes,
autoExecute,
autoParse,
Expand Down Expand Up @@ -87,6 +88,9 @@ export function parseEntity(entity: EntityConstructor) {
&& typeAlias.trim().length > 0 ? typeAlias.trim()
: 'entity'

// Define 'typeHidden'
typeHidden = typeof typeHidden === "boolean" ? typeHidden : false;

// Sanity check the attributes
attributes = typeof attributes === 'object' && !Array.isArray(attributes) ?
attributes : error(`Please provide a valid 'attributes' object`)
Expand Down Expand Up @@ -115,6 +119,7 @@ export function parseEntity(entity: EntityConstructor) {
linked: track.linked,
autoExecute,
autoParse,
typeHidden,
_etAlias: typeAlias
},
table ? { table } : {}
Expand Down
4 changes: 4 additions & 0 deletions src/lib/parseMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export default (field: string, config: EntityAttributeConfig, track: TrackingInf
case 'transform':
if (typeof config[prop] !== 'function') error(`'${prop}' must be a function`)
break
case "inverseTransform":
if (typeof config[prop] !== "function")
error(`'${prop}' must be a function`);
break;
case 'coerce':
case 'onUpdate':
case 'hidden':
Expand Down

0 comments on commit 611b08e

Please sign in to comment.