Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,57 @@
## 1.9.25

- `TableFieldReference`:
- Added nullable field `indexName` to represent the name of the index if one exists.

- Added new class `TableRelationshipReferenceEntityTyped` extending `TableRelationshipReference`:
- Adds `sourceFieldEntityType` and `targetFieldEntityType` fields of type `TypeInfo`.
- Provides `copyWithEntityTypes` method to create typed copies.

- `TableRelationshipReference`:
- Added nullable fields `sourceRelationshipFieldIndex` and `targetRelationshipFieldIndex`.
- Added `copyWithEntityTypes` method returning `TableRelationshipReferenceEntityTyped`.

- `EntityHandler`:
- Added `getFieldsListEntityTypes` method to return a map of fields that are list entities or references with their `TypeInfo`.

- `SQLDialect`:
- Added `foreignKeyCreatesImplicitIndex` boolean flag with default `true`.
- Added field `createIndexIfNotExists` to indicate support for `IF NOT EXISTS` in `CREATE INDEX` (default `true`).

- `CreateIndexSQL`:
- Updated `buildSQL` method to conditionally include `IF NOT EXISTS` only if dialect supports it.

- `DBPostgreSQLAdapter`:
- Added `foreignKeyCreatesImplicitIndex` flag to PostgreSQL dialect set to `false`.
- Updated `_findAllTableFieldsReferences` query to include foreign key index name (`fk_index_name`) by joining with `pg_index` and `pg_class`.
- Populated `indexName` in `TableFieldReference` instances from query result.
- Updated relationship references to include `sourceRelationshipFieldIndex` and `targetRelationshipFieldIndex` from `indexName`.

- `DBMySQLAdapter`:
- Set `createIndexIfNotExists` to `false` in MySQL dialect capabilities.

- `DBSQLAdapter`:
- `parseConfigDBGenerateTablesAndCheckTables`: changed return type from `List<bool>` to a record with named fields `(generateTables, checkTables)`.
- `extractTableSQLs`: updated regex to also match `CREATE INDEX` statements in addition to `CREATE` and `ALTER TABLE`.
- `_populateTablesFromSQLsImpl`: fixed error handling for `CREATE INDEX` statements when the SQL dialect does not support `IF NOT EXISTS`.
- Now logs a warning and ignores the error instead of throwing.
- Added detection of missing foreign key indexes when dialect does not create implicit indexes.
- Added detection of missing relationship reference indexes for collection reference fields.
- Updated error reporting and logging to include missing reference indexes and relationship reference indexes.
- Updated `_checkDBTableSchemeReferenceField` to return `TableRelationshipReferenceEntityTyped` with entity types.
- Added generation of missing reference indexes and missing relationship reference indexes SQL statements.
- Updated `_DBTableCheck` class:
- Added fields `missingReferenceIndexes` and `missingRelationshipReferenceIndexes`.
- Added methods to generate missing reference indexes and relationship reference indexes SQL.
- Added `_DBRelationshipTableColumn` subclass of `_DBTableColumn` to represent relationship table columns with relationship table name.
- Updated SQL generation to create indexes for foreign keys if dialect does not create implicit indexes:
- Added index creation after foreign key constraints in `generateAddColumnAlterTableSQL`.
- Added index creation for relationship table foreign keys in relationship table creation SQL.

- Dependency updates:
- `async_extension`: ^1.2.19 → ^1.2.20
- `meta`: ^1.18.0 → ^1.18.1

## 1.9.24

- `GZipSink`:
Expand Down
2 changes: 1 addition & 1 deletion lib/src/bones_api_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ typedef APILogger =
/// Bones API Library class.
class BonesAPI {
// ignore: constant_identifier_names
static const String VERSION = '1.9.24';
static const String VERSION = '1.9.25';

static bool _boot = false;

Expand Down
99 changes: 93 additions & 6 deletions lib/src/bones_api_condition_encoder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,18 @@ class TableFieldReference {
/// The target table field type.
final Type targetFieldType;

/// The name of the index, if one exists.
final String? indexName;

TableFieldReference(
this.sourceTable,
this.sourceField,
this.sourceFieldType,
this.targetTable,
this.targetField,
this.targetFieldType,
);
this.targetFieldType, {
String? indexName,
}) : indexName = indexName != null && indexName.isNotEmpty ? indexName : null;

@override
bool operator ==(Object other) =>
Expand All @@ -73,7 +77,48 @@ class TableFieldReference {

@override
String toString() {
return 'TableFieldReference{"$sourceTable"."$sourceField"($sourceFieldType) -> "$targetTable"."$targetField"($targetFieldType)}';
return 'TableFieldReference{'
'"$sourceTable"."$sourceField"($sourceFieldType) -> "$targetTable"."$targetField"($targetFieldType)'
'}${indexName != null ? '@$indexName' : ''}';
}
}

/// A [TableRelationshipReference] that explicitly defines the entity types
/// of its relationship fields.
///
/// - [sourceFieldEntityType] represents the entity type of the [sourceField].
/// - [targetFieldEntityType] represents the entity type of the [targetField].
class TableRelationshipReferenceEntityTyped extends TableRelationshipReference {
/// The entity type of the [sourceField].
TypeInfo sourceFieldEntityType;

/// The entity type of the [targetField].
TypeInfo targetFieldEntityType;

TableRelationshipReferenceEntityTyped(
super.relationshipTable,
super.sourceTable,
super.sourceField,
super.sourceFieldType,
this.sourceFieldEntityType,
super.sourceRelationshipField,
super.targetTable,
super.targetField,
super.targetFieldType,
this.targetFieldEntityType,
super.targetRelationshipField, {
super.relationshipField,
super.sourceRelationshipFieldIndex,
super.targetRelationshipFieldIndex,
});

@override
String toString() {
return 'TableRelationshipReferenceEntityTyped[$relationshipTable]{'
'"$sourceTable"."$sourceField"($sourceFieldType @ $sourceFieldEntityType) -> "$targetTable"."$targetField"($targetFieldType @ $targetFieldEntityType)'
'}'
'${sourceRelationshipFieldIndex != null ? '$sourceField@$sourceRelationshipFieldIndex' : ''}'
'${targetRelationshipFieldIndex != null ? '$targetField@$targetRelationshipFieldIndex' : ''}';
}
}

Expand Down Expand Up @@ -109,6 +154,12 @@ class TableRelationshipReference {
/// The virtual/entity relationship field name.
final String? relationshipField;

/// The index of the [sourceRelationshipField]
final String? sourceRelationshipFieldIndex;

/// The index of the [targetRelationshipField]
final String? targetRelationshipFieldIndex;

TableRelationshipReference(
this.relationshipTable,
this.sourceTable,
Expand All @@ -120,13 +171,45 @@ class TableRelationshipReference {
this.targetFieldType,
this.targetRelationshipField, {
this.relationshipField,
});
String? sourceRelationshipFieldIndex,
String? targetRelationshipFieldIndex,
}) : sourceRelationshipFieldIndex =
sourceRelationshipFieldIndex != null &&
sourceRelationshipFieldIndex.isNotEmpty
? sourceRelationshipFieldIndex
: null,
targetRelationshipFieldIndex =
targetRelationshipFieldIndex != null &&
targetRelationshipFieldIndex.isNotEmpty
? targetRelationshipFieldIndex
: null;

/// Returns a copy as [TableRelationshipReference],
/// with entity types [sourceFieldEntityType] and [targetFieldEntityType].
TableRelationshipReferenceEntityTyped copyWithEntityTypes(
TypeInfo sourceFieldEntityType,
TypeInfo targetFieldEntityType,
) => TableRelationshipReferenceEntityTyped(
relationshipTable,
sourceTable,
sourceField,
sourceFieldType,
sourceFieldEntityType,
sourceRelationshipField,
targetTable,
targetField,
targetFieldType,
targetFieldEntityType,
targetRelationshipField,
relationshipField: relationshipField,
sourceRelationshipFieldIndex: sourceRelationshipFieldIndex,
targetRelationshipFieldIndex: targetRelationshipFieldIndex,
);

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is TableRelationshipReference &&
runtimeType == other.runtimeType &&
relationshipTable == other.relationshipTable &&
sourceTable == other.sourceTable &&
sourceField == other.sourceField &&
Expand All @@ -143,7 +226,11 @@ class TableRelationshipReference {

@override
String toString() {
return 'TableRelationshipReference[$relationshipTable]{"$sourceTable"."$sourceField"($sourceFieldType) -> "$targetTable"."$targetField"($targetFieldType)}';
return 'TableRelationshipReference[$relationshipTable]{'
'"$sourceTable"."$sourceField"($sourceFieldType) -> "$targetTable"."$targetField"($targetFieldType)'
'}'
'${sourceRelationshipFieldIndex != null ? '$sourceField@$sourceRelationshipFieldIndex' : ''}'
'${targetRelationshipFieldIndex != null ? '$targetField@$targetRelationshipFieldIndex' : ''}';
}
}

Expand Down
31 changes: 31 additions & 0 deletions lib/src/bones_api_entity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1625,6 +1625,37 @@ abstract class EntityHandler<O> with FieldsFromMap, EntityRulesResolver {
);
}

Map<String, TypeInfo>? _fieldsListEntityTypes;

Map<String, TypeInfo> getFieldsListEntityTypes([O? o]) {
var listEntityFields = _fieldsListEntityTypes;
if (listEntityFields != null) return listEntityFields;

var enumFields = getFieldsEnumTypes(o);

var mapListEntityFields =
getFieldsTypes().entries
.map((e) {
var field = e.key;
var typeInfo = e.value;

if (enumFields.containsKey(field)) return null;

if (!typeInfo.isListEntityOrReference) return null;

var entityType = typeInfo.entityType;
if (entityType == null) return null;

return MapEntry(field, typeInfo);
})
.nonNulls
.toMapFromEntries();

return _fieldsListEntityTypes = Map<String, TypeInfo>.unmodifiable(
mapListEntityFields,
);
}

List<EntityAnnotation>? getFieldEntityAnnotations(O? o, String key);

Map<String, List<EntityAnnotation>>? getAllFieldsEntityAnnotations([O? o]) {
Expand Down
9 changes: 4 additions & 5 deletions lib/src/bones_api_entity_db_memory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,10 @@ class DBSQLMemoryAdapter extends DBSQLAdapter<DBSQLMemoryAdapterContext>
}) {
boot();

var retCheckTablesAndGenerateTables =
DBSQLAdapter.parseConfigDBGenerateTablesAndCheckTables(config);

var generateTables = retCheckTablesAndGenerateTables[0];
var checkTables = retCheckTablesAndGenerateTables[1];
var (
generateTables: generateTables,
checkTables: checkTables,
) = DBSQLAdapter.parseConfigDBGenerateTablesAndCheckTables(config);

var populate = config?['populate'];
Object? populateTables;
Expand Down
10 changes: 5 additions & 5 deletions lib/src/bones_api_entity_db_mysql.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class DBMySQLAdapter extends DBSQLAdapter<DBMySqlConnectionWrapper>
elementQuote: '`',
acceptsTemporaryTableForReturning: true,
acceptsInsertIgnore: true,
createIndexIfNotExists: false,
),
transactions: true,
transactionAbort: true,
Expand Down Expand Up @@ -161,11 +162,10 @@ class DBMySQLAdapter extends DBSQLAdapter<DBMySqlConnectionWrapper>
minConnections ??= 1;
maxConnections ??= 3;

var retCheckTablesAndGenerateTables =
DBSQLAdapter.parseConfigDBGenerateTablesAndCheckTables(config);

var generateTables = retCheckTablesAndGenerateTables[0];
var checkTables = retCheckTablesAndGenerateTables[1];
var (
generateTables: generateTables,
checkTables: checkTables,
) = DBSQLAdapter.parseConfigDBGenerateTablesAndCheckTables(config);

var populate = config?['populate'];
Object? populateTables;
Expand Down
Loading