Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(datastore): support of custom primary key #1641

Merged
merged 10 commits into from
Jul 20, 2022
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ android {
dependencies {
api amplifyCore

implementation 'com.amplifyframework:core:1.36.1'
implementation 'com.amplifyframework:core:v1.37.0-cpkey-preview.2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'

testImplementation 'junit:junit:4.13.2'
Expand All @@ -81,6 +81,6 @@ dependencies {
testImplementation 'androidx.test:core:1.4.0'
testImplementation 'org.robolectric:robolectric:4.3.1'
testImplementation 'com.google.code.gson:gson:2.8.6'
testImplementation 'com.amplifyframework:aws-auth-cognito:1.36.1'
testImplementation 'com.amplifyframework:aws-auth-cognito:v1.37.0-cpkey-preview.2'
HuiSF marked this conversation as resolved.
Show resolved Hide resolved
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.9'
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://github.com/aws-amplify/amplify-flutter.git' }
s.source_files = 'Classes/**/*'
s.dependency 'Flutter'
s.dependency 'Amplify', '1.25.0'
s.dependency 'AWSPluginsCore', '1.25.0'
s.dependency 'AmplifyPlugins/AWSCognitoAuthPlugin', '1.25.0'
s.dependency 'Amplify', '1.27.1-cpk.1'
s.dependency 'AWSPluginsCore', '1.27.1-cpk.1'
s.dependency 'AmplifyPlugins/AWSCognitoAuthPlugin', '1.27.1-cpk.1'
s.dependency 'amplify_core'
s.dependency 'SwiftLint'
s.dependency 'SwiftFormat/CLI'
Expand Down
2 changes: 1 addition & 1 deletion packages/amplify_core/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ android {
}

dependencies {
implementation 'com.amplifyframework:core:1.36.1'
implementation 'com.amplifyframework:core:v1.37.0-cpkey-preview.2'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'

Expand Down
2 changes: 2 additions & 0 deletions packages/amplify_core/lib/amplify_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export 'src/types/models/model_association.dart';
export 'src/types/models/model_field.dart';
export 'src/types/models/model_field_definition.dart';
export 'src/types/models/model_field_type.dart';
export 'src/types/models/model_index.dart';
export 'src/types/models/model_provider.dart';
export 'src/types/models/model_schema.dart';
export 'src/types/models/model_schema_definition.dart';
Expand All @@ -66,6 +67,7 @@ export 'src/types/plugin/amplify_storage_plugin_interface.dart';

/// Query
export 'src/types/query/query_field.dart';
export 'src/types/query/query_model_identifier.dart';

/// Storage
export 'src/types/storage/storage_types.dart';
Expand Down
36 changes: 33 additions & 3 deletions packages/amplify_core/lib/src/types/models/model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,25 @@ import 'model_schema.dart';
import 'model_schema_definition.dart';

abstract class Model {
ModelType getInstanceType();
ModelType getInstanceType() {
throw UnimplementedError(
'getInstanceType() has not been implemented on Model.');
}

String getId();
@Deprecated(
'[getId] is being deprecated in favor of custom primary key feature. Use getter [modelIdentifier] to get model identifier.')
String getId() {
throw UnimplementedError('getId() has not been implemented on Model.');
}

Map<String, Object?> toJson();
ModelIdentifier get modelIdentifier {
throw UnimplementedError(
'modelIdentifier has not been implemented on Model.');
}

Map<String, Object?> toJson() {
throw UnimplementedError('toJson() has not been implemented on Model.');
}

const Model();

Expand Down Expand Up @@ -73,3 +87,19 @@ abstract class ModelType<T extends Model> {
@override
int get hashCode => T.hashCode;
}

/// Model identifier presentation
abstract class ModelIdentifier<T extends Model> {
const ModelIdentifier();

/// Serialize a model identifier as a map.
Map<String, dynamic> serializeAsMap();

/// Serialize a model identifier as a list of key-value pairs. The order of
/// key-value pairs presents primary key and sort keys.
List<Map<String, dynamic>> serializeAsList();

/// Serialize a model identifier into a single string in format:
/// <primaryKey>[#<sortKey>]
String serializeAsString();
}
52 changes: 23 additions & 29 deletions packages/amplify_core/lib/src/types/models/model_association.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,49 @@
*/
import 'dart:convert';

import 'package:aws_common/aws_common.dart';
import 'package:flutter/foundation.dart';

// ignore: constant_identifier_names
enum ModelAssociationEnum { HasMany, HasOne, BelongsTo }

@immutable
class ModelAssociation {
class ModelAssociation with AWSEquatable<ModelAssociation>, AWSSerializable {
final ModelAssociationEnum associationType;
final String? targetName; // opt (used in belongsTo)
final String? associatedName; // opt (used in hasMany/hasOne)
final String? associatedType; // opt (used in hasMany/hasOne)
final String? targetName; // used in belongsTo
final List<String>? targetNames; // used in belongsTo
final String? associatedName; // used in hasMany/hasOne
final String? associatedType; // used in hasMany/hasOne

const ModelAssociation({
required this.associationType,
this.targetName,
@Deprecated('Please use the latest version of Amplify CLI to regenerate models')
haverchuck marked this conversation as resolved.
Show resolved Hide resolved
this.targetName,
this.targetNames,
this.associatedName,
this.associatedType,
});

@override
List<Object?> get props => [
associationType,
targetName,
targetNames,
associatedName,
associatedType,
];

ModelAssociation copyWith({
ModelAssociationEnum? associationType,
String? targetName,
List<String>? targetNames,
String? associatedName,
String? associatedType,
}) {
return ModelAssociation(
associationType: associationType ?? this.associationType,
targetName: targetName ?? this.targetName,
targetNames: targetNames ?? this.targetNames,
associatedName: associatedName ?? this.associatedName,
associatedType: associatedType ?? this.associatedType,
);
Expand All @@ -51,6 +66,7 @@ class ModelAssociation {
final map = {
'associationType': describeEnum(associationType),
'targetName': targetName,
'targetNames': targetNames,
'associatedName': associatedName,
'associatedType': associatedType,
};
Expand All @@ -62,37 +78,15 @@ class ModelAssociation {
return ModelAssociation(
associationType: map['associationType'],
targetName: map['targetName'],
targetNames: map['targetNames'],
associatedName: map['associatedName'],
associatedType: map['associatedType'],
);
}

@override
String toJson() => json.encode(toMap());

factory ModelAssociation.fromJson(String source) =>
ModelAssociation.fromMap(json.decode(source));

@override
String toString() {
return 'ModelAssociation(associationType: $associationType, targetName: $targetName, associatedName: $associatedName, associatedType: $associatedType)';
}

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;

return other is ModelAssociation &&
other.associationType == associationType &&
other.targetName == targetName &&
other.associatedName == associatedName &&
other.associatedType == associatedType;
}

@override
int get hashCode {
return associationType.hashCode ^
targetName.hashCode ^
associatedName.hashCode ^
associatedType.hashCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ class ModelFieldDefinition {
bool isRequired = true,
required String ofModelName,
QueryField? associatedKey,
String? targetName}) {
@Deprecated('Please use the latest version of Amplify CLI to regenerate models')
haverchuck marked this conversation as resolved.
Show resolved Hide resolved
String? targetName,
List<String>? targetNames}) {
// Extra code needed due to lack of nullability support
String? associatedName;
String? associatedType;
Expand All @@ -166,6 +168,7 @@ class ModelFieldDefinition {
association: ModelAssociation(
associationType: ModelAssociationEnum.BelongsTo,
targetName: targetName,
targetNames: targetNames,
associatedName: associatedName,
associatedType: associatedType));
}
Expand Down
67 changes: 67 additions & 0 deletions packages/amplify_core/lib/src/types/models/model_index.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import 'dart:convert';

import 'package:aws_common/aws_common.dart';

/// {@template amplify_core.models.model_index}
/// Describes an index that is created by `@primaryKey` or `@index` directive,
/// and is listed in [ModelSchemaDefinition.indexes].
/// {@endtemplate}
class ModelIndex with AWSEquatable<ModelIndex>, AWSSerializable {
/// Index name that is defined by the name parameter of `@index` directive in
/// a model schema. This will always be null when the index is representing
/// `@primaryKey` directive.
final String? name;

/// An array of field names. The first field is always the field that is
/// annotated by `@primaryKey` or `@index` directive , and the remaining
/// fields are the fields specified by `sortKeyFields` parameter of
/// `@primaryKey` or `@index` directive.
final List<String> fields;

/// {@macro model_index}
const ModelIndex({
required this.fields,
this.name,
});

@override
List<Object?> get props => [name, fields];

/// Make a copy of an existing [ModelIndex] instance.
ModelIndex copyWith({
List<String>? fields,
String? name,
}) =>
ModelIndex(fields: fields ?? this.fields, name: name ?? this.name);

/// Create an instance of [ModelIndex] from a json object
factory ModelIndex.fromJson(Map<String, Object?> map) => ModelIndex(
fields: (map['fields'] as List<Object?>).cast(),
name: map['name'] as String?,
);

/// Generate a json object that represents [ModelIndex]
@override
Map<String, Object?> toJson() => {
'name': name,
'fields': fields,
};

@override
String toString() => 'ModelIndex(name: $name, fields: $fields)';
}
Loading