Skip to content
Open
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
4 changes: 4 additions & 0 deletions playground/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include: package:lints/recommended.yaml
plugins:
orm:
path: ../pub/orm
6 changes: 6 additions & 0 deletions playground/orm.config.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import 'package:orm/config.dart';

const config = Config(
provider: .sqlite,
output: '', // TODO: update output path
);
14 changes: 14 additions & 0 deletions playground/orm.schema.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:orm/schema.dart';

@model
typedef User = ({@id String id, String email});

@model
typedef Post = ({
@id String id,
String title,
String content,
String authorId,

@Relation(fields: {'authorId'}) User author,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Still missing the references parameter for complete relation mapping.

The fields parameter is now correctly specified, but the relation annotation is incomplete. According to ORM relation patterns, you need both:

  • fields: The foreign key field in the current model (Post) → {'authorId'}
  • references: The primary key field in the referenced model (User) → {'id'}

Without the references parameter, the ORM cannot definitively establish which field in User the authorId foreign key points to.

🔎 Complete the relation mapping
-  @Relation(fields: {'authorId'}) User author,
+  @Relation(fields: {'authorId'}, references: {'id'}) User author,

This explicitly maps Post.authorIdUser.id.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Relation(fields: {'authorId'}) User author,
import 'package:orm/schema.dart';
typedef User = (
@id String id,
String email,
);
typedef Post = (
@id String id,
String title,
String content,
String authorId,
@Relation(fields: {'authorId'}, references: {'id'}) User author,
);
🤖 Prompt for AI Agents
In playground/orm.schema.dart around line 13, the @Relation annotation declares
fields: {'authorId'} but omits the references parameter; add references: {'id'}
to explicitly map Post.authorId to User.id so the ORM knows which User primary
key the foreign key points to, ensuring the relation is fully specified.

});
204 changes: 204 additions & 0 deletions playground/pubspec.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e"
url: "https://pub.dev"
source: hosted
version: "92.0.0"
analysis_server_plugin:
dependency: transitive
description:
name: analysis_server_plugin
sha256: "44adba4d74a2541173bad4c11531d2a4d22810c29c5ddb458a38e9f4d0e5eac7"
url: "https://pub.dev"
source: hosted
version: "0.3.4"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e"
url: "https://pub.dev"
source: hosted
version: "9.0.0"
analyzer_plugin:
dependency: transitive
description:
name: analyzer_plugin
sha256: "6645a029da947ffd823d98118f385d4bd26b54eb069c006b22e0b94e451814b5"
url: "https://pub.dev"
source: hosted
version: "0.13.11"
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async:
dependency: transitive
description:
name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.13.0"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
crypto:
dependency: transitive
description:
name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.dev"
source: hosted
version: "3.0.7"
dart_style:
dependency: transitive
description:
name: dart_style
sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b
url: "https://pub.dev"
source: hosted
version: "3.1.3"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
lints:
dependency: "direct dev"
description:
name: lints
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
url: "https://pub.dev"
source: hosted
version: "6.0.0"
meta:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
orm:
dependency: "direct main"
description:
path: "../pub/orm"
relative: true
source: path
version: "6.0.0-dev.1"
package_config:
dependency: transitive
description:
name: package_config
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
url: "https://pub.dev"
source: hosted
version: "2.2.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
source_span:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
watcher:
dependency: transitive
description:
name: watcher
sha256: f52385d4f73589977c80797e60fe51014f7f2b957b5e9a62c3f6ada439889249
url: "https://pub.dev"
source: hosted
version: "1.2.0"
yaml:
dependency: transitive
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.3"
yaml_edit:
dependency: transitive
description:
name: yaml_edit
sha256: ec709065bb2c911b336853b67f3732dd13e0336bd065cc2f1061d7610ddf45e3
url: "https://pub.dev"
source: hosted
version: "2.2.3"
sdks:
dart: ">=3.10.1 <4.0.0"
12 changes: 12 additions & 0 deletions playground/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: playground
publish_to: none

environment:
sdk: ^3.10.1

dependencies:
orm:
path: ../pub/orm

dev_dependencies:
lints: ^6.0.0
2 changes: 1 addition & 1 deletion pub/orm/lib/config.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:meta/meta.dart';

enum DatabaseProvider { sqlite, mysql, postgresql, sqlserver }
enum DatabaseProvider { sqlite }

@immutable
final class Config {
Expand Down
32 changes: 14 additions & 18 deletions pub/orm/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
// import 'dart:async';
import 'package:analysis_server_plugin/plugin.dart';
import 'package:analysis_server_plugin/registry.dart';

// import 'package:analysis_server_plugin/registry.dart';
import 'src/analyzer/fixes/config_required_fix.dart';
import 'src/analyzer/rules/config_required_rule.dart';

// // import 'src/analyzer/plugin.dart';
class AnalysisPlugin extends Plugin {
@override
String get name => 'orm';

// // mixin A on Plugin {
// // @override
// // Future<void> register(PluginRegistry registry) async {
// // await super.register(registry);
// // }
// // }
@override
void register(PluginRegistry registry) {
registry.registerWarningRule(ConfigRequiredRule());
registry.registerFixForRule(ConfigRequiredRule.code, ConfigRequiredFix.new);
}
}

// // class AnalysisPlugin extends Plugin with SchemaAnalyzerPlugin, A {
// // @override
// // Future<void> register(PluginRegistry registry) async {
// // await super.register(registry);
// // // TODO: implement register
// // }
// // }

// // final plugin = AnalysisPlugin();
final plugin = AnalysisPlugin();
2 changes: 1 addition & 1 deletion pub/orm/lib/schema.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export 'src/schema/schema.dart';
export 'src/schema/model.dart';
export 'src/schema/relation.dart';
export 'src/schema/map.dart';
export 'src/schema/map_to.dart';
export 'src/schema/id.dart';
26 changes: 26 additions & 0 deletions pub/orm/lib/src/analyzer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Analyzer plugin layout

This directory holds analyzer-plugin logic for the ORM package.

Structure
- `rules/`: analysis rules (diagnostics).
- `fixes/`: quick fixes for rule diagnostics.
- `assists/`: assists not tied to diagnostics.
- `utils/`: shared helpers.

Naming
- Rule file: `*_rule.dart` (class `*Rule`).
- Fix file: `*_fix.dart` (class `*Fix`).
- Assist file: `*_assist.dart` (class `*Assist`).

Identifiers
- Rule name: `orm_<snake_case>`.
- Fix id: `orm.fix.<snake_case>`.
- Assist id: `orm.assist.<snake_case>`.

Registration
- Register rules and fixes in `lib/main.dart` via `PluginRegistry`.

Tests
- Place tests under `test/analyzer/`.
- Use `analyzer_testing` + `test_reflective_loader` for rule tests.
Empty file.
61 changes: 61 additions & 0 deletions pub/orm/lib/src/analyzer/fixes/config_required_fix.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
import 'package:analysis_server_plugin/edit/dart/dart_fix_kind_priority.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';

import '../utils/config_utils.dart';

class ConfigRequiredFix extends ResolvedCorrectionProducer {
static const FixKind _kind = FixKind(
'orm.fix.config_required',
DartFixKindPriority.standard,
'Define ORM config: const config = Config(...)',
);

ConfigRequiredFix({required super.context});

@override
CorrectionApplicability get applicability =>
CorrectionApplicability.singleLocation;

@override
FixKind get fixKind => _kind;

@override
Future<void> compute(ChangeBuilder builder) async {
if (findConfigVariable(unit) != null) {
return;
}

final eol = utils.endOfLine;
final configImport = findConfigImport(unit);
final prefix = configImport?.prefix?.name;
final needsImport = configImport == null;

final importOffset = importInsertOffset(unit);
final configDeclOffset = configInsertOffset(unit);
final configText = buildConfigText(prefix, eol, indent: utils.oneIndent);
final importText = buildImportText(eol);

await builder.addDartFileEdit(file, (builder) {
if (needsImport && importOffset == configDeclOffset) {
builder.addInsertion(importOffset, (builder) {
builder.write(importText);
builder.write(eol);
builder.write(configText);
});
return;
}

if (needsImport) {
builder.addInsertion(importOffset, (builder) {
builder.write(importText);
});
}

builder.addInsertion(configDeclOffset, (builder) {
builder.write(configText);
});
});
}
}
Loading