# python3 -m pip install Flask pymongo
import json
import os
from bson import ObjectId, json_util
from bson.errors import InvalidId
from flask import Flask, request, jsonify, Response
from pymongo import MongoClient
from pymongo.errors import PyMongoError
app = Flask(__name__)
client = MongoClient(os.environ.get('MONGODB_URI', 'mongodb://127.0.0.1:27017'), serverSelectionTimeoutMS=5000)
def object_value(text, name):
    value = json.loads(text)
    if not isinstance(value, dict): raise ValueError(f"'{name}' is not a well-formated json")
    return value
@app.route('/mongodb7.php', methods=['GET', 'POST'])
def api():
    p = dict(request.args)
    p.update(request.form)
    if not p.get('collection'): return jsonify(error="'collection' is missing")
    action = p.get('action', '').lower()
    try:
        database, separator, name = p['collection'].partition('.')
        collection = client[database if separator else 'db'][name if separator else database]
        if action not in ('query', 'insert', 'delete', 'update'): raise ValueError("'action' is not recoginzed")
        if action == 'insert':
            documents = json.loads(p.get('document', '[]'))
            if not isinstance(documents, list): documents = [documents]
            if not documents or any(not isinstance(d, dict) for d in documents):
                raise ValueError("'document' is not a well-formated jsonArray")
            count = len(collection.insert_many(documents).inserted_ids)
        else:
            query = object_value(p.get('filter', '{}' if action == 'query' else ''), 'filter')
            if '_id' in query: query['_id'] = ObjectId(query['_id'])
            if action == 'query':
                sort = [(k.lstrip('+-'), -1 if k.startswith('-') else 1) for k in p.get('sort', '_id').split(',')]
                projection = {'_id': 0}
                projection.update({k.lstrip('+-'): 0 if k.startswith('-') else 1 for k in p.get('key', '-_id').split(',')})
                limit, skip = int(p.get('limit', 0)), int(p.get('skip', 0))
                if min(limit, skip) < 0: raise ValueError('Invalid limit or skip')
                records = list(collection.find(query, projection).sort(sort).skip(skip).limit(limit))
                return Response(json_util.dumps(dict(records=records, count=len(records), action=action), ensure_ascii=False), mimetype='application/json')
            if action == 'delete': count = collection.delete_many(query).deleted_count
            else:
                update = object_value(p.get('newobj', '{}'), 'newobj')
                if not any(k.startswith('$') for k in update): raise ValueError('newobj 请使用 $set 等更新操作符')
                result = collection.update_many(query, update, upsert=p.get('upsert', '').lower() == 'true')
                count = result.modified_count + int(result.upserted_id is not None)
        return jsonify(count=count, action=action)
    except (ValueError, TypeError, InvalidId, PyMongoError) as error:
        return jsonify(error=str(error))
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 3000)))
