benhutchins / dyngoose

Elegant DynamoDB object modeling for Typescript.
https://www.npmjs.com/package/dyngoose
ISC License
89 stars 14 forks source link

StringSet looks like not implemented. #633

Closed air2 closed 1 year ago

air2 commented 1 year ago

Does the stringset attribute misses the following in it's implementation? toDynamo(values: Value): DynamoDB.AttributeValue fromDynamo(value: DynamoDB.AttributeValue): Value | null

I see this is done in the NumberSet but not in the StringSet and stringset does not seem to work correctly. Also I would suggest not to use string[] but Set but I guess that is a different ticket.

benhutchins commented 1 year ago

StringSet is fully implemented, is there something you're seeing that isn't working when creating a StringSet attribute?

air2 commented 1 year ago

Yes,

I have a class:

@Dyngoose.$Table({ name: 'jobs', connection: AwsService.dynamoDb })
export class JobTable extends Dyngoose.Table  {
  @Dyngoose.Attribute.String()
  public id: string = ''

  @Dyngoose.Attribute.StringSet()
  public dismissed:string[] = []

  @Dyngoose.$PrimaryKey('id')
  static readonly primaryKey: Dyngoose.Query.PrimaryKey<JobTable, number, string>

}

when when I retrieve a record const job = await JobTable.primaryKey.get({ id })

the seen field is null however the _attributes field contains the data, so when I do: const value = job.get('dismissed') value is filled.

The same with storing data. When I set a new value to the dismissed field and call the save function it is not stored, however if I do:

jobTable.set('dismissed', ['some', 'values']) and then call save it works.

I do not have to do this for the other properties only for the stringset property.

benhutchins commented 1 year ago

@air2 I think the issue here is the default value? You are setting the value to [] (an empty array), however, that default value will be ignored as the getter/setter properties set by the decorator will override it.

Dyngoose ensures all empty attribute values report as null and are removed from the record in DynamoDB. It never sets a value to a NULL type.

In this case, reading a value where dismissed is not set will return null. If you'd like to default to an empty array, you can do this with the manipulateRead method like:

  @Dyngoose.Attribute.StringSet({ manipulateRead: (val) => val ?? [] })
  public dismissed:string[] = []

I agree that the next version of Dyngoose should use a Set type instead of a native array. There is a utility updateSet on the table just because of this poor implementation.