Skip to content

Commit

Permalink
Improvements for existing table support (tywalch#79)
Browse files Browse the repository at this point in the history
* Improvements for keys with field names that match attribute field names. Attribute casing options on model. Documentation updates. ignoreOwnership query option. Not fully working: updates double up when index field is the same as attribute field, improved support for pre/post-fixing templates and single composites when fields match

* Adding ExpressionState to have "singleOccurrence" flag which will then cause automatically overwrite values that already exist in place. This is useful because updated Keys are added to the UpdateExpression _after_ the attribute is added, which results in an overwrite and no duplication. This also is ideal for updates since DynamoDB doesnt allow for multiple updates to the same field path anyway. Additionally I have added functionality that will allow for prefixes and postfixes to attribute values. This will be useful in cases where someone is already overloading a field but maybe is parsing out their own ids (i.e. they are trying to do single table the _hard_ way).

* Fixes, documentation, and implementation of prefixes/postfixes for index attribute keys.
  • Loading branch information
tywalch authored Aug 23, 2021
1 parent de2fee8 commit ea7e1dc
Show file tree
Hide file tree
Showing 22 changed files with 2,207 additions and 316 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,10 @@ All notable changes to this project will be documented in this file. Breaking ch

### [1.3.2] = 2021-08-11
### Fixed
- Newly added method `parse()` had critical typo. Method now has an improved api, and appropriate tests [[read more]](./README.md#parse)
- Newly added method `parse()` had critical typo. Method now has an improved api, and appropriate tests [[read more]](./README.md#parse)

### [1.4.0] = 2021-08-22
### Added
- Added support for choosing the case ElectroDB will use when modeling a Partition or Sort Key. [[read more]](./README.md#using-electrodb-with-existing-data)
- Added support for indexes to use fields that are shared with attribute fields. This should help users leverage ElectroDB with existing tables. [[read more]](./README.md#using-electrodb-with-existing-data)
- Added Query Option `ignoreOwnership` to bypass ElectroDB checks/interrogations for ownership of an item before returning it. [[read more]](./README.md#query-options)
736 changes: 496 additions & 240 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions examples/versioncontrol/database/issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const issues = new Entity({
},
updatedAt: {
type: "string",
watch: ["*"],
watch: "*",
set: () => moment.utc().format(),
readOnly: true,
},
Expand Down Expand Up @@ -158,7 +158,7 @@ export const issueComments = new Entity({
},
updatedAt: {
type: "string",
watch: ["*"],
watch: "*",
set: () => moment.utc().format(),
readOnly: true,
},
Expand Down
2 changes: 1 addition & 1 deletion examples/versioncontrol/database/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const users = new Entity({
},
updatedAt: {
type: "string",
watch: ["*"],
watch: "*",
set: () => moment.utc().format(),
readOnly: true,
},
Expand Down
18 changes: 13 additions & 5 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,13 @@ type Schema<A extends string, F extends A, C extends string> = {
readonly index?: string;
readonly collection?: C | ReadonlyArray<C>;
readonly pk: {
readonly casing?: "upper" | "lower" | "none" | "default";
readonly field: string;
readonly composite: ReadonlyArray<F>;
readonly template?: string;
}
readonly sk?: {
readonly casing?: "upper" | "lower" | "none" | "default";
readonly field: string;
readonly composite: ReadonlyArray<F>;
readonly template?: string;
Expand Down Expand Up @@ -924,12 +926,18 @@ type DataUpdateCallback<A extends string, F extends A, C extends string, S exten
type ReturnValues = "default" | "none" | 'all_old' | 'updated_old' | 'all_new' | 'updated_new';

interface QueryOptions {
params?: object;
raw?: boolean;
includeKeys?: boolean;
originalErr?: boolean;
table?: string;
limit?: number;
params?: object;
includeKeys?: boolean;
originalErr?: boolean;
ignoreOwnership?: boolean;
}

// subset of QueryOptions
interface ParseOptions {
ignoreOwnership?: boolean;
}

interface UpdateQueryOptions extends QueryOptions {
Expand Down Expand Up @@ -1123,8 +1131,8 @@ export class Entity<A extends string, F extends A, C extends string, S extends S
match(record: Partial<Item<A,F,C,S,S["attributes"]>>): RecordsActionOptions<A,F,C,S, ResponseItem<A,F,C,S>[], AllTableIndexCompositeAttributes<A,F,C,S>>;
scan: RecordsActionOptions<A,F,C,S, ResponseItem<A,F,C,S>[], TableIndexCompositeAttributes<A,F,C,S>>
query: Queries<A,F,C,S>;
parse(item: ParseSingleInput): ResponseItem<A,F,C,S> | null;
parse(item: ParseMultiInput): ResponseItem<A,F,C,S>[];
parse(item: ParseSingleInput, options?: ParseOptions): ResponseItem<A,F,C,S> | null;
parse(item: ParseMultiInput, options?: ParseOptions): ResponseItem<A,F,C,S>[];
setIdentifier(type: "entity" | "version", value: string): void;
client: any;
}
Expand Down
74 changes: 72 additions & 2 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Entity, Service, WhereAttributeSymbol, UpdateEntityItem} from ".";
import {Entity, Service, WhereAttributeSymbol, UpdateEntityItem, Schema} from ".";
import {expectType, expectError, expectAssignable, expectNotAssignable, expectNotType} from 'tsd';
let entityWithSK = new Entity({
model: {
Expand Down Expand Up @@ -3756,4 +3756,74 @@ complex.update({username: "abc"})
expectError(() => op.eq(attr.mapValue.stringVal, numberValue));
return "";
})
.go()
.go()

// casing property on schema
const casingEntity = new Entity({
model: {
service: "MallStoreDirectory",
entity: "MallStores",
version: "1",
},
attributes: {
id: {
type: "string",
field: "id",
},
mall: {
type: "string",
required: true,
field: "mall",
},
stores: {
type: "number",
},
value: {
type: "string"
}
},
indexes: {
store: {
collection: ["myCollection"],
pk: {
field: "parition_key",
composite: ["id"],
casing: "lower",
},
sk: {
field: "sort_key",
composite: ["mall", "stores"],
casing: "upper",
}
},
other: {
index: "idx1",
collection: "otherCollection",
pk: {
field: "parition_key_idx1",
composite: ["mall"],
casing: "upper",
},
sk: {
field: "sort_key_idx1",
composite: ["id", "stores"],
casing: "default",
}
}
}
}, {table: "StoreDirectory"});

type RequiredIndexOptions = Required<Schema<any, any, any>["indexes"][string]>;
type PKCasingOptions = RequiredIndexOptions["pk"]["casing"];
type SKCasingOptions = RequiredIndexOptions["sk"]["casing"];
const allCasingOptions = "" as "default" | "upper" | "lower" | "none" | undefined;
expectAssignable<PKCasingOptions>(allCasingOptions);
expectAssignable<SKCasingOptions>(allCasingOptions);
expectError<PKCasingOptions>("not_available");
expectError<SKCasingOptions>("not_available");

type AvailableParsingOptions = Parameters<typeof casingEntity.parse>[1]
expectAssignable<AvailableParsingOptions>(undefined);
expectAssignable<AvailableParsingOptions>({});
expectAssignable<AvailableParsingOptions>({ignoreOwnership: true});
expectAssignable<AvailableParsingOptions>({ignoreOwnership: false});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "electrodb",
"version": "1.3.2",
"version": "1.4.0",
"description": "A library to more easily create and interact with multiple entities and heretical relationships in dynamodb",
"main": "index.js",
"scripts": {
Expand Down
Loading

0 comments on commit ea7e1dc

Please sign in to comment.