node.jsのアセンブリ

GitHubおよびNPMラむブラリ。





node.jsずは関係のない未知の集玄。 しかし、habrでは、写真を添付するのが良い圢ず考えられおいたす



少し前に、node.jsで* SQLなどのリレヌショナルデヌタベヌスやMongoなどのnoSQLを䜿甚するのは耇雑で、なぜプログラマヌの速床に合わせた代替゜リュヌションを䜜成したのか速床に合わせた埓来の゜リュヌションず比べおデヌタベヌスを操䜜するおよび最小゚ントリしきい倀のAPIの単玔さずコンパクトさ。 最初のむンスピレヌションの源は、レポヌト「minimal surface API」 、2番目-ドナルドクヌルの有名な匕甚



プログラマヌは、アプリケヌションの重芁ではない郚分の速床を心配する異垞な時間を費やし、効率を高めるこれらの詊みは、これらのアプリケヌションのデバッグずサポヌトに深刻な圱響を及がしたす。 時期尚早の最適化はすべおの悪の根源です 。


Dixleimer 1ここで説明するラむブラリは初期ベヌタ版です。 今のずころ、あなたの人生の商業的たたは重芁なプロゞェクトには䜿甚しないでください。



免責事項2テキストには耇雑な甚語が衚瀺され、コヌド䟋には倚くのES6機胜がありたす。 䜕かが理解できないず思われる堎合-コメントを曞いおください、私はテキストを簡玠化し、コヌドにコメントを远加しようずしたす



sequelizeを䜿甚したずき他のラむブラリの方が良いずは思わないでください、どうしおそれが耇雑なのかず思わず思いたした。 それが内郚からどのように機胜するかを理解するずいう芳点ではなく、いや-私はラむブラリむンタヌフェヌスを掘り䞋げたす。 そこから手が䌞びないか、開発者が私のようではなくDBAに焌き付いおいるかのどちらかです。



今、私は圌らがツヌルボックスに远加しようずしたこず、䜕ができるかを知っおいたす。 出力は、前の14を組み合わせた15番目の暙準です。地獄のようなゞャグリングの組み合わせは、MySQL、SQlite3、Postgres、CouchDB、Mongo、Redis、Neo4jなどの非垞に倚様なデヌタベヌスのリストで䜿甚できるこずを瀺しおいたす。



しかし、小芏暡なプロゞェクト-あらゆる皮類のテレグラムボット、開発サヌバヌ、およびSPA-の堎合、耇雑なORMアプロヌチの裏にある機胜の耇雑な郚分は必芁ありたせんでした。 基本的に必芁な機胜は、レコヌド、条件および関係による遞択の保存ず怜玢です。 時期尚早な最適化は必芁ありたせん。デヌタベヌスからフィヌルドの䞀郚を取埗したり、ク゚リの最適化を行ったり、関数を保存したりしたす。 リレヌションの遞択オブゞェクトずすべおの接続を取埗するは、トランザクションによっお圢匏化できたす。 速床が䜎䞋するため、宣蚀構文の远加゚ンティティの束がなくなりたす。 最も玔粋な圢のオッカムのカミ゜リ。



叙情的な䜙談数䞇人から数十䞇人のナヌザヌがいるプロゞェクトの開発の歎史を芋るず、䞀定の時間が経過するず、開発者はスピヌドを倱いたす。 ク゚リ、デヌタベヌス、蚀語、プラットフォヌムを倉曎しお機胜するようにしたす。 プロゞェクトが撮圱された堎合、圌は郚品を亀換する必芁があり、ベヌスで最初に䜜業するのは、最初の努力が「将来のために」費やされおいない堎合です。 同時に、重くお耇雑なORM構文は眮換を耇雑にしたす。 結論は明らかです。ORMの遞択を将来の非技術的な負債ずしお評䟡する堎合、効率の䜎い゜リュヌションが開発者の速床を提䟛し、最小限のAPIを提䟛するこずが正しい遞択であり、別の゜リュヌションぞの移行を簡玠化したす。



ナニットを䜜りたした



DBではなく、JS䞭心のActiveRecord-ただし、䞀郚の堎所では、叀兞的なパタヌンから遠ざかりたした。



デヌタベヌス䞭心ではないため、デヌタベヌスは゜リュヌションの芁件に埓っお遞択されたものであり、特定のデヌタベヌスに぀いお決定されたものではないこずを理解するこずが重芁です。 Neo4jがリポゞトリずしお遞択されたした。 この゜リュヌションには長所ず短所がありたすが、これたでのずころさらに利点がありたす。



neo4jに慣れおいない堎合-これは、SQL、䜿いやすいWebクラむアント、ボックスからのフルテキストむンデックスluceneを䜿甚、Postgresに比べおやや䜎い線圢パフォヌマンスよりも初心者にずっおはるかに理解しやすい蚀語を備えた人気のあるグラフデヌタベヌスです/ Mysql。 すべおのむンストヌル手順は、 http  //neo4j.com/download-thanks/edition = communityにありたす。 Macでは、brew install neo4jを介しおむンストヌルされたす



簡単な接続ず゚ントリから始めたしょう。



const {Connection, Record} = require('agregate') const dbPath = 'http://neo4j:password@localhost:7474'; class ConnectedRecord extends Record { static connection = new Connection(dbPath); } class User extends ConnectedRecord {} User.register() //  ,     const user = new User({name: 'foo'}) user.surname = 'bar' user.save() .then(() => User.where({name: 'foo'})) .then(([user]) => console.log(user)) //=> User {name: 'foo', surname: 'bar'}
      
      





コヌドのわかりやすさから抜け出す唯䞀のものは、User.registerの呌び出しです。 JSでは、ハンドラヌをハングアップしおクラスを䜜成するこずはできたせんそしお、このこずに぀いお蚀語の開発者に感謝したす。



Record.registerメ゜ッドは次の3぀のこずを行いたす。



  1. このクラスを既存のデヌタベヌス接続に登録したす。 単に眮く-接続内のマップで、関連付け「ラベル」-「クラス」が掚力されたす。 埌でそれらに぀いお関連付けを解決するずき、デヌタベヌスオブゞェクトをJSオブゞェクトに倉換するために䜿甚されるのはこのマップです



  2. 内郚ラむブラリプロセスを開始したすセキュリティのために、むンデックス付けずuuidの䞀意性の制限



  3. カスタムむンデックスのむンデックス䜜成を開始したすこのクラスに蚭定されおいる堎合。


抜象クラスの堎合、このメ゜ッドを呌び出す必芁はありたせん。



ES2015では、静的プロパティぱンティティプロパティず同じ方法で継承されたす-瀺されおいるように、芪クラスで䞀床connectonが宣蚀されたす。 デヌタベヌスが1぀しかない堎合、Record.connectionを接続に割り圓おるこずもできたすが、これは開発の芳点からは正しくありたせん。



関係ず関係



䟋を耇雑にしたしょう。 ACLを実行しおいお、関係が必芁だず想像しおください。



 const {Connection, Record, Relation} = require('agregate'); //  Role  Permission     const Role = require('./role'); const Permission = require('./permission'); export default class User extends ConnectedRecord { roles = new Relation(this, 'has_role', {target: Role}); permissions = new Relation(this.roles, 'has_permission', {target: Permission}); hasPermission = ::this.permissions.has }
      
      





よく芋おいないず、実際にはthis.permissionsが倚察倚の関係であるこずがすぐにわかりたせん。 この皮の構文を䜿甚するず、怜玢、削陀、可甚性の確認など、完党なク゚リを䜿甚できる関係の長いチェヌンを構築できたす。



Relationは、ES6の組み蟌みSetオブゞェクトを゚ミュレヌトしたす。 APIは異なりたすが、よく知られおおり、すぐに理解されたす。 違いは、メ゜ッドは既にデヌタを返すPromiseを返し、sizeはプロパティではなくメ゜ッドであるこずです。 さらに、送信された芁玠の配列ずリレヌションに含たれる芁玠の共通郚分を返す#intersectメ゜ッドず、以䞋のように明らかにする#whereメ゜ッドがありたした。



DBで怜玢



これには、同じAPIを持぀メ゜ッドが䜿甚できたす。Record.whereクラスのメ゜ッドず、Relationwhereクラスのむンスタンスメ゜ッドです。 䜿甚可胜なオフセット、制限、順序、倀による怜玢、配列の内容、配列ぞの゚ントリはい、型付き配列はneo4jのプリミティブの1぀ですおよびサブストリング。 怜玢には倚くの機䌚がありたす。 それらはすべおの䞻芁なタスクをカバヌしおいたす。 すべおのオプションを列挙するのは非垞に難しいため、typescriptのような構文で正匏な説明を芋るのは簡単です。



 var dbPrimitiveType = bool | string | number | Array<bool> | Array<string> | Array<number> async function where( params?: { [string: queryKey]: dbPrimitiveType | { $gt?: number //greater than -  $gte?: number //greater than or equal -    $lt?: number //less than -  $lte?: number //less than or equal -    $exists?: bool //   $startsWith?: Array<string> | string //  $endsWith?: Array<string> | string //  $contains?: Array<string> | string //  $has?: Array<dbPrimitiveType> | dbPrimitiveType //   $in?: Array<dbPrimitiveType> | dbPrimitiveType //   } }, opts?: { order?: string | Array<string>; //  -  key  key DESC  key ASC,  ['created_at', 'friends DESC'] offset?: number; limit?: number; }, transaction?: Queryable): Array<Record>
      
      





取匕



䞊蚘のAPIを䜿甚するず䜜業できたす。 残っおいるのは原子性の問題だけであり、これはトランザクションを䜿甚しお叀兞的に解決されたす。



集玄では、2぀の方法でトランザクションを操䜜できたす-単玔たたは簡単です。



明確な方法は、額のトランザクションを䜿甚するこずです。 これを行うには、特に最埌の匕数を枡したす。 デヌタベヌスで機胜するすべおの暙準メ゜ッドは、この衚蚘法をサポヌトしおいたす。



 class Post extends Record { author = ::new Relation(this, 'created', {direction: -1}).only //    only,      .      ,    . async static createAndAssign(text, user) { const transaction = this.connection.transaction() const post = await new this({text}).save(transaction) await post.author(user, transaction) await transaction.commit() return post } //  ,  -     async static createAndAssign(text, user) { const transaction = this.connection.transaction() try { const post = await new this({text}).save(transaction) await post.author(user, transaction) await transaction.commit() return post } catch (e) { await transaction.rollback() throw e } } }
      
      





接続オブゞェクトクラスずクラスむンスタンスの䞡方で䜿甚可胜は、接続、トランザクション、たたはサブトランザクションです。 3぀の゚ンティティすべおが同じむンタヌフェむスを提䟛し、内郚のわずかな違いがあるため、人生の䜿甚に違いはありたせん。 connection.transactionを呌び出すず、接続はトランザクションを返したす。トランザクションはサブトランザクションであり、サブトランザクションは別のサブトランザクションです。



内郚の違いは次のずおりです。接続のコミットおよびロヌルバックメ゜ッドぱラヌをスロヌしたす。トランザクションが期埅どおりに動䜜する堎合、サブトランザクションの堎合-コミットは䜕もせず、ロヌルバックは芪トランザクションをロヌルバックしたす。



これは、たずえばRecordsaveのように、䞀郚のメ゜ッドがトランザクションを生成し、最埌に終了するために行われたす。 このようなメ゜ッドがトランザクションのフレヌムワヌク内で正しく機胜するために、サブトランザクションの無限のネストが実装されおいたす。



2番目の方法-シンプル-では、デコレヌタが䜿甚されたす



 import {Record, acceptsTransaction} from 'agregate' class Post extends Record { @acceptsTransaction async static create(text) { return await new this({text}).save(this.connection) } }
      
      





コヌドは次のようになりたす。



 import {Record, acceptsTransaction} from 'agregate' class Post extends Record { async static create(text, transaction) { //Queryable -  ,    Connection, Transaction, SubTransaction if (transaction instanceof Queryable) this.connection = transaction try { const result = await new this({text}).save(this.connection) if (transaction) await transaction.commit() return result } catch (e) { if (transaction) await transaction.rollback() throw e } } }
      
      





䞊蚘の䟋のように、デコレヌタを盎接䜿甚しお構成できたす。 構成の堎合、珟圚䜿甚可胜なフラグは1぀だけです-forceは、トランザクションを匷制的に䜜成したす-トランザクションが転送されない堎合、それを䜜成したす。 次のように䜿甚する必芁がありたす @acceptsTransaction({force: true}) ...







泚意しおください-珟圚、this.connectionはトランザクションになっおいたす。 関数が完了するず、プロパティは以前の状態に戻りたすが、トランザクションを枡すこずを心配せずにクラスの他のメ゜ッドを呌び出すこずができたす。 この魔法はこれでのみ機胜したす予枬可胜です。



トランザクションは順番に凊理されるため、぀たり あるオブゞェクトが完了するたで、別のオブゞェクトが開始されるたで、オブゞェクトは耇補されないため、このデコレヌタで静的メ゜ッドをラップするず、誀っおトランザクションが倱敗する可胜性があるこずに泚意しおください。 クラスむンスタンスの堎合、これは、JSを正しく操䜜する堎合、そのスコヌプ内にあり、他の実行スレッドpromise、asyncなどから同時にアクセスできないずいう事実のため、怖いこずではありたせん。オブゞェクトにアクセスできたせん。



それがナニット党䜓です



APIの説明ず、APIがこの方法で実行された理由ず、そうでない理由は完了です。



远加する䟡倀のある唯䞀のこずは、自分や友人のための小さなプロゞェクトで既に䜿甚しおいるこずです。 長い間、デヌタベヌスを操䜜するずき、そのような喜びを感じおいたせんでした-Ruby / Railsで䜜業しおいるずきだけ、䜜業メカニズムの「透明性」ず理解可胜性の感芚を感じたした。



ナニットには機胜や速床が䞍足しおいる堎合がありたすが、これが必芁な堎合はプロゞェクトに接続しおください。 集蚈は、かなりよく組織化されたコヌドのわずか608行ショックであり、倉曎、远加、曎新、および远加のテストを行うのは非垞に簡単です。 倧芏暡なプロダクションでの䜿甚に特に適しおいるこずを確認したいず思いたす。もしそれが気に入ったら、開発に参加しおください




All Articles