AngularDart:具有多个集合的内存数据服务

AngularDart: in memory data service with multiple collections

我一直在关注 Hero Tutorial,并且有一个 in_memory_data_service.dart 文件,其中有一个 "collection/table" 名为 _initialHeroes。但目前一切都只是为了支持这个 collection/table。我如何最好地重构 in_memory_data_service.dart 以支持多个 collections/tables?

我就是这样解决的。只是根据 url 的路径段(即 "places" 或 "posts",我应该连接到哪个内存列表来决定。在我的例子中是地方或帖子。不是很编码很好,但无论如何它只是暂时的并且有效。


import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:angular/angular.dart';
import 'package:http/http.dart';
import 'package:http/testing.dart';
import 'src/place.dart';
import 'src/post.dart';

@Injectable()
class InMemoryDataService extends MockClient {
  static final _initialPlaces = [
    {'id': 11, 'name': 'Place 1'},
    {'id': 12, 'name': 'Place 2'},
    {'id': 13, 'name': 'Place 3'},
    {'id': 14, 'name': 'Place 4'},
    {'id': 15, 'name': 'Place 5'},
    {'id': 16, 'name': 'Place 6'},
    {'id': 17, 'name': 'Place 7'},
    {'id': 18, 'name': 'Place 8'},
    {'id': 19, 'name': 'Place 9'},
    {'id': 20, 'name': 'Place 10'}
  ];

  static final _initialPosts = [
    {'id': 23, 'place_id': 11, 'text': 'My first post'},
    {'id': 24, 'place_id': 11, 'text': 'My second post'},
    {'id': 25, 'place_id': 11, 'text': 'My third post'},
    {'id': 26, 'place_id': 11, 'text': 'My fourth post'},
    {'id': 27, 'place_id': 11, 'text': 'My fifth post'},
    {'id': 28, 'place_id': 11, 'text': 'My sixth post'},
    {'id': 29, 'place_id': 11, 'text': 'My seventh post'},
    {'id': 30, 'place_id': 11, 'text': 'My eights post'},
    {'id': 31, 'place_id': 11, 'text': 'My ninth post'},
    {'id': 32, 'place_id': 11, 'text': 'My tenth post'},
    {'id': 33, 'place_id': 11, 'text': 'My elevents post'},
  ];

  static List _placesTbl;
  static List _postsTbl;
  static int _nextPlacesId;
  static int _nextPostsId;

  static Future _handler(Request request) async {
    if (_placesTbl == null) resetDb();

    var data;
    switch (request.method) {
      case 'GET':
        final id = int.tryParse(request.url.pathSegments.last);

        switch(request.url.pathSegments[1]) {
          case 'places':
            if (id != null) {
              data = _placesTbl
                .firstWhere((place) => place.id == id); // throws if no match
            } else {
              String prefix = request.url.queryParameters['name'] ?? '';
              final regExp = new RegExp(prefix, caseSensitive: false);
              data = _placesTbl.where((place) => place.name.contains(regExp)).toList();
            }
            break;
          case 'posts':
            if (id != null) {
              data = _postsTbl
                .firstWhere((post) => post.id == id); // throws if no match
            } else {
              String prefix = request.url.queryParameters['text'] ?? '';
              final regExp = new RegExp(prefix, caseSensitive: false);
              data = _postsTbl.where((post) => post.text.contains(regExp)).toList();
            }          
            break;
          default:
            throw 'Unimplemented HTTP method ${request.method}';            
        }
        break;
      case 'POST':
        switch(request.url.pathSegments[1]) {
          case 'places':
            var name = json.decode(request.body)['name'];
            var newPlace = new Place(_nextPlacesId++, name);
            _placesTbl.add(newPlace);
            data = newPlace;
            break;
          case 'posts':
            var text = json.decode(request.body)['text'];
            var place_id = json.decode(request.body)['place_id'];
            var newPost = new Post(_nextPostsId++, place_id, text);
            _postsTbl.add(newPost);
            data = newPost;          
            break;
        }
        break;
      case 'PUT':
        switch(request.url.pathSegments[1]) {
          case 'places':
            var placeChanges = new Place.fromJson(json.decode(request.body));
            var targetPlace = _placesTbl.firstWhere((h) => h.id == placeChanges.id);
            targetPlace.name = placeChanges.name;
            data = targetPlace;          
            break;
          case 'posts':
            var postChanges = new Post.fromJson(json.decode(request.body));
            var targetPost = _postsTbl.firstWhere((h) => h.id == postChanges.id);
            targetPost.place_id = postChanges.place_id;
            targetPost.text = postChanges.text;
            data = targetPost;            
            break;
        }
        break;
      case 'DELETE':
        switch(request.url.pathSegments[1]) {
          case 'places':
            var id = int.parse(request.url.pathSegments.last);
            _placesTbl.removeWhere((place) => place.id == id);
            break;
          case 'posts':
            var id = int.parse(request.url.pathSegments.last);
            _postsTbl.removeWhere((post) => post.id == id);
            break;
        }
        // No data, so leave it as null.
        break;
      default:
        throw 'Unimplemented HTTP method ${request.method}';
    }
    return new Response(json.encode({'data': data}), 200,
        headers: {'content-type': 'application/json'});
  }

  static resetDb() {
    _placesTbl = _initialPlaces.map((json) => new Place.fromJson(json)).toList();
    _postsTbl = _initialPosts.map((json) => new Post.fromJson(json)).toList();
    _nextPlacesId = _placesTbl.map((place) => place.id).fold(0, max) + 1;
    _nextPostsId = _postsTbl.map((post) => post.id).fold(0, max) + 1;
  }

  static String lookUpPlacesName(int id) =>
      _placesTbl.firstWhere((place) => place.id == id, orElse: null)?.name;

  static String lookUpPostsText(int id) =>
      _postsTbl.firstWhere((post) => post.id == id, orElse: null)?.text;

  InMemoryDataService() : super(_handler);
}